Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore14
-rw-r--r--org.eclipse.jdt.core/.classpath15
-rw-r--r--org.eclipse.jdt.core/.cvsignore2
-rw-r--r--org.eclipse.jdt.core/.vcm_meta8
-rw-r--r--org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java99
-rw-r--r--org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java100
-rw-r--r--org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/CompilationUnit.java80
-rw-r--r--org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileFinder.java59
-rw-r--r--org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java171
-rw-r--r--org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java841
-rw-r--r--org.eclipse.jdt.core/build.properties24
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java1287
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ICompletionRequestor.java261
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ISearchRequestor.java39
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ISearchableNameEnvironment.java43
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ISelectionRequestor.java124
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/SelectionEngine.java498
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionNodeFound.java34
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnClassLiteralAccess.java54
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnExceptionReference.java13
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnExplicitConstructorCall.java74
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnFieldType.java53
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnImportReference.java51
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnMemberAccess.java52
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnMessageSend.java65
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnPackageReference.java49
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedAllocationExpression.java74
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedExceptionReference.java24
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedNameReference.java89
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedTypeReference.java69
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnSingleNameReference.java44
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnSingleTypeReference.java55
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java1275
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionScanner.java719
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/InvalidCursorLocation.java21
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java1026
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/Engine.java141
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionNodeFound.java23
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnExplicitConstructorCall.java66
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnFieldReference.java49
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnImportReference.java48
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnMessageSend.java58
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnPackageReference.java46
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnQualifiedAllocationExpression.java71
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnQualifiedNameReference.java76
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnQualifiedSuperReference.java60
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnQualifiedTypeReference.java61
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnSingleNameReference.java56
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnSingleTypeReference.java58
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnSuperReference.java55
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionParser.java577
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionScanner.java68
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/AbstractSyntaxTreeVisitorAdapter.java641
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java2866
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/CompilationResult.java225
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java508
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ConfigurableOption.java227
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/DefaultErrorHandlingPolicies.java69
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/DocumentElementParser.java1377
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/HierarchyResolver.java398
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/HierarchyType.java79
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IAbstractSyntaxTreeVisitor.java193
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ICompilerRequestor.java8
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IDocumentElementRequestor.java394
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IErrorHandlingPolicy.java6
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IHierarchyRequestor.java20
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IProblem.java63
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IProblemFactory.java28
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ISourceElementRequestor.java133
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/SourceElementParser.java1011
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java375
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java371
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractVariableDeclaration.java42
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java243
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AnonymousLocalTypeDeclaration.java165
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java71
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java178
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java195
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayQualifiedTypeReference.java58
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java182
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayTypeReference.java55
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java144
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AstNode.java139
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java1743
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java149
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java60
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Break.java97
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Case.java98
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java287
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CharLiteral.java106
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java89
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Clinit.java174
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java263
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java166
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java307
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java342
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Continue.java101
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DefaultCase.java77
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DoStatement.java185
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DoubleLiteral.java87
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java646
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java300
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java485
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExtendedStringLiteral.java67
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FalseLiteral.java77
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java187
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java454
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FloatLiteral.java88
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java323
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java263
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ImportReference.java62
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Initializer.java105
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InnerTypeDeclaration.java12
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java250
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IntLiteral.java178
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IntLiteralMinValue.java27
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java112
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Literal.java34
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java201
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalTypeDeclaration.java60
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LongLiteral.java171
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LongLiteralMinValue.java47
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MagicLiteral.java27
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MemberTypeDeclaration.java58
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java309
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java108
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NameReference.java60
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullLiteral.java56
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NumberLiteral.java30
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/OR_OR_Expression.java379
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/OperatorExpression.java1867
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/OperatorIds.java33
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/PostfixExpression.java71
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/PrefixExpression.java52
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java325
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java746
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedSuperReference.java56
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java163
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java66
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java112
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java281
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java799
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java74
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java123
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/StringLiteral.java112
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SuperReference.java66
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java293
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java160
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThisReference.java80
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java81
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TrueLiteral.java78
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java482
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java1065
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java107
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java299
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java226
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileConstants.java34
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java564
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileStruct.java324
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFormatException.java67
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/FieldInfo.java296
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/InnerClassInfo.java130
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/MethodInfo.java225
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/AttributeNamesConstants.java54
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CaseLabel.java82
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CharArrayCache.java193
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java6052
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ConstantPool.java2865
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/DoubleCache.java147
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ExceptionLabel.java34
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/FieldNameAndTypeCache.java172
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/FloatCache.java147
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/IntegerCache.java161
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/Label.java239
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/LongCache.java161
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/MethodNameAndTypeCache.java174
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ObjectCache.java155
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/Opcodes.java206
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/QualifiedNamesConstants.java102
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryField.java27
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryMethod.java28
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryNestedType.java28
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryType.java65
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java19
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IConstants.java31
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IDependent.java16
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IGenericField.java17
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IGenericMethod.java20
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IGenericType.java22
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/INameEnvironment.java45
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ISourceField.java32
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ISourceMethod.java57
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ISourceType.java98
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/NameEnvironmentAnswer.java71
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java147
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java149
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java85
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java470
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java88
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/InitializationFlowContext.java84
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/InsideSubRoutineFlowContext.java31
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LabelFlowContext.java55
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java142
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/SwitchFlowContext.java55
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java534
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/BooleanConstant.java41
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ByteConstant.java56
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CharConstant.java64
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java523
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ConfigurableProblems.java15
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/Constant.java2553
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/DoubleConstant.java58
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/FloatConstant.java56
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ITypeRequestor.java27
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IntConstant.java56
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/LongConstant.java56
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/NullConstant.java25
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ReferenceContext.java19
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ShortConstant.java56
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/StringConstant.java42
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java152
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypeBinding.java175
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypes.java31
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java512
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java34
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BindingIds.java11
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java1451
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java993
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java503
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilerModifiers.java29
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java232
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImportBinding.java44
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InnerEmulationDependency.java16
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InvocationSite.java8
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalTypeBinding.java134
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java111
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java665
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MemberTypeBinding.java43
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java499
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java388
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java983
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java239
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java225
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemBinding.java59
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemFieldBinding.java31
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemMethodBinding.java44
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemPackageBinding.java25
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReasons.java13
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java25
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java648
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java1064
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java1000
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticAccessMethodBinding.java316
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticArgumentBinding.java52
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticFieldBinding.java22
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java35
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java112
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java187
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java115
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java46
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VariableBinding.java38
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/InvalidInputException.java24
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java7837
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ParserBasicInformation.java22
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredBlock.java292
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredElement.java349
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredField.java182
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredImport.java58
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredInitializer.java243
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredLocalVariable.java97
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredMethod.java368
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredStatement.java58
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredType.java511
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredUnit.java194
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java2948
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/SourceConstructorDeclaration.java13
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/SourceFieldDeclaration.java21
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/SourceMethodDeclaration.java13
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/SourceTypeConverter.java340
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/TerminalSymbols.java109
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser1.rscbin0 -> 35746 bytes
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser2.rscbin0 -> 35252 bytes
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser3.rscbin0 -> 1174 bytes
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser4.rscbin0 -> 2004 bytes
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser5.rscbin0 -> 612 bytes
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/AbortCompilation.java52
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/AbortCompilationUnit.java20
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/AbortMethod.java20
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/AbortType.java20
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/DefaultProblem.java242
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/DefaultProblemFactory.java134
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemHandler.java169
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemIrritants.java277
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java2670
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemSeverities.java15
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ShouldNotImplement.java11
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/UnresolvedCompilationError.java25
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/CharOperation.java641
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfInt.java89
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfObject.java95
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfPackage.java101
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfType.java102
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/ObjectVector.java73
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/SimpleNameVector.java67
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetAllocationExpression.java181
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetClassFile.java245
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetCodeStream.java446
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetCompiler.java38
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetConstantPool.java2071
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetEnvironment.java84
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetEvaluator.java215
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetFieldReference.java399
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java276
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetParser.java745
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetQualifiedNameReference.java659
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetReturnStatement.java146
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetScope.java968
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetSingleNameReference.java697
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetSkeleton.java134
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetThisReference.java103
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetToCuMapper.java435
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetTypeDeclaration.java77
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/EvaluationConstants.java34
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/EvaluationContext.java1396
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/EvaluationResult.java246
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/Evaluator.java175
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/GlobalVariable.java61
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/IRequestor.java22
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/InstallException.java21
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/VariablesEvaluator.java327
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/VariablesInfo.java68
-rw-r--r--org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CodeFormatter.java2415
-rw-r--r--org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/impl/FormatterOptions.java255
-rw-r--r--org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/impl/SplitLine.java210
-rw-r--r--org.eclipse.jdt.core/model/Readme.txt1
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/BufferChangedEvent.java112
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/ElementChangedEvent.java40
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/Flags.java217
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IBuffer.java220
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IBufferChangedListener.java11
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClassFile.java49
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathEntry.java183
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeAssist.java35
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeCompletionRequestor.java263
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICompilationUnit.java220
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IElementChangedListener.java12
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IField.java28
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IImportContainer.java10
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IImportDeclaration.java19
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IInitializer.java15
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaElement.java215
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaElementDelta.java231
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModel.java200
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelMarker.java41
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatus.java76
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java211
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaProject.java371
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IMember.java51
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IMethod.java90
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IOpenable.java149
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageDeclaration.java9
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragment.java140
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java160
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IParent.java22
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IRegion.java29
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceManipulation.java121
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceRange.java15
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceReference.java33
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IType.java319
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeHierarchy.java199
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeHierarchyChangedListener.java10
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IWorkingCopy.java147
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaConventions.java398
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java1198
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaModelException.java124
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/Signature.java908
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/ICodeSnippetRequestor.java180
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/IEvaluationContext.java302
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/IGlobalVariable.java28
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/DOMException.java19
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/DOMFactory.java169
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMCompilationUnit.java45
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMFactory.java137
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMField.java57
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMImport.java26
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMInitializer.java31
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMMember.java39
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMMethod.java164
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMNode.java273
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMPackage.java19
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMType.java105
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Assert.java100
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BasicCompilationUnit.java85
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryField.java57
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMember.java128
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMethod.java188
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java413
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Buffer.java720
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BufferCache.java55
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BufferManager.java221
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java485
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFileInfo.java200
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java233
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CommitWorkingCopyOperation.java156
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnit.java687
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitElementInfo.java61
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitStructureRequestor.java779
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitVisitor.java155
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompletionRequestorWrapper.java222
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyElementsOperation.java290
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyResourceElementsOperation.java581
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateCompilationUnitOperation.java109
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateElementInCUOperation.java315
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateFieldOperation.java99
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateImportOperation.java135
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateInitializerOperation.java110
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateMethodOperation.java111
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreatePackageDeclarationOperation.java128
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreatePackageFragmentOperation.java136
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeHierarchyOperation.java108
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeMemberOperation.java144
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeOperation.java101
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeleteElementsOperation.java169
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeleteResourceElementsOperation.java130
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java901
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ElementCache.java61
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/FailedReconciliationException.java19
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/HandleFactory.java183
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IBufferManager.java54
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ICacheEnumeration.java33
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IJavaElementRequestor.java30
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IJavaReconciler.java42
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/INameLookup.java151
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IPathRequestor.java5
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportContainer.java87
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportDeclaration.java69
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IncrementalDeterministicRequestor.java353
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IncrementalReconciler.java381
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IncrementalReconcilerRequestor.java489
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Initializer.java98
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/InitializerElementInfo.java14
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryFile.java74
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragment.java160
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentInfo.java45
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java661
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRootInfo.java41
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java666
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDelta.java645
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDeltaBuilder.java499
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementInfo.java146
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementRequestor.java234
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModel.java647
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelInfo.java88
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java1211
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelOperation.java605
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelStatus.java358
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java1465
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProjectElementInfo.java195
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LRUCacheEnumerator.java67
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Member.java183
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MemberElementInfo.java99
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MoveElementsOperation.java45
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MoveResourceElementsOperation.java45
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MultiOperation.java367
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NameLookup.java653
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NonVoidMethodRequestor.java36
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Openable.java444
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/OpenableElementInfo.java13
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/OverflowingLRUCache.java444
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageDeclaration.java50
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragment.java371
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentInfo.java106
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java369
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRootInfo.java147
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Problem.java243
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ProblemFactory.java135
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Region.java154
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/RenameElementsOperation.java89
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/RenameResourceElementsOperation.java74
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java360
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironmentRequestor.java92
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SelectionRequestor.java317
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetClasspathOperation.java256
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetOutputLocationOperation.java228
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SingleTypeRequestor.java81
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceField.java74
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceFieldElementInfo.java77
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.java656
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethod.java248
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethodElementInfo.java114
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRange.java48
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRefElement.java230
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRefElementInfo.java53
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceType.java419
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceTypeElementInfo.java321
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeVector.java124
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Util.java847
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ValidateSourceElementOperation.java67
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/WorkingCopy.java341
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/WorkingCopyElementInfo.java11
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BinaryBrokerKey.java61
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BuildEvent.java68
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/DeltaKey.java444
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IBinaryBroker.java66
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IBuildListener.java19
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IBuildMonitor.java20
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IConstructor.java64
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IDelta.java206
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IDeltaKey.java59
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IDependencyGraph.java16
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IDevelopmentContext.java218
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IField.java47
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IHandle.java107
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IImage.java168
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IImageBuilder.java47
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IImageContext.java29
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IMember.java64
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IMethod.java74
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IPackage.java132
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IProblemDetail.java86
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IProblemReporter.java75
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IReportCard.java57
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ISearch.java73
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ISearchFactory.java231
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ISearchListener.java26
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ISourceFragment.java40
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IState.java98
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IType.java562
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/InvalidKeyException.java20
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/MemoryBinaryBroker.java65
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NotPresentException.java21
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/SearchProgressEvent.java22
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/SearchResultEvent.java43
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/StateSpecificException.java21
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/AbstractImageBuilder.java202
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/AbstractMemberHandle.java139
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/AbstractMemberHandleSWH.java80
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/AbstractMethodCollaboratorIndictment.java53
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/AbstractNode.java374
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ArrayTypeHandleImpl.java180
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ArrayTypeHandleImplSWH.java91
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BatchImageBuilder.java121
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BinaryBrokerOutput.java98
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BinaryOutput.java70
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BinaryStructure.java411
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BuildMonitorImpl.java57
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BuildNotifier.java302
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BuilderEnvironment.java199
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BuilderType.java221
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ClassOrInterfaceHandleImpl.java554
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ClassOrInterfaceHandleImplSWH.java651
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/CompilerCompilationUnit.java81
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ConsoleProgressMonitor.java87
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ConstructorImpl.java92
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ConstructorImplSWH.java145
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ConvertedCompilationResult.java52
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/DeltaImpl.java1020
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/DependencyGraph.java614
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/DependencyGraphImpl.java49
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/FieldCollaboratorIndictment.java30
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/FieldImpl.java56
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/FieldImplSWH.java122
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/INode.java80
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ImageBuilderInternalException.java45
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ImageContextImpl.java110
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ImageImpl.java236
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ImageImplSWH.java285
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/IncrementalImageBuilder.java2025
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/Indictment.java155
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/IndictmentSet.java314
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/JCUNode.java101
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/JavaBuilder.java369
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/JavaDevelopmentContextImpl.java476
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/MarkerProblemReporter.java299
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/MethodCollaboratorIndictment.java80
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/MethodImpl.java114
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/MethodImplSWH.java170
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ModifiedBuilderType.java283
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/NamespaceNode.java72
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/NewBuilderType.java53
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/NonStateSpecificHandleImpl.java133
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/OldBuilderType.java67
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/OrderedSet.java241
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PackageElement.java80
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PackageImpl.java237
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PackageImplSWH.java214
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PackageMap.java138
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PackageMapEntry.java94
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PathMap.java142
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PrimitiveTypeHandleImpl.java262
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PrimitiveTypeHandleImplSWH.java52
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ProblemDetailImpl.java237
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ProblemFactory.java137
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ProblemTable.java201
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ProjectBinaryOutput.java254
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ProjectResourceCopier.java264
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ReportCardImpl.java222
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/SourceElementTable.java139
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/SourceEntry.java156
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/SourceFragmentImpl.java79
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateImpl.java2077
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateSnap.java106
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateSnapConstantPool.java673
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateSnapV5.java817
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateSnapV6.java66
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateSpecificHandleImpl.java69
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateTables.java14
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeCollaboratorIndictment.java27
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeHierarchyIndictment.java30
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeImpl.java526
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeImplSWH.java493
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeNode.java75
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeStructureEntry.java113
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/UnmodifiedBuilderType.java65
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/WorkQueue.java133
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ZipNode.java63
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/EvaluationContextWrapper.java341
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/GlobalVariableWrapper.java49
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/RequestorWrapper.java76
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBinaryType.java230
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBuilder.java204
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java557
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/RegionBasedHierarchyBuilder.java213
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/RegionBasedTypeHierarchy.java118
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java1297
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/AbstractDOMBuilder.java228
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/CompilationUnit.java52
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMBuilder.java889
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMCompilationUnit.java198
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMField.java709
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMImport.java170
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMInitializer.java270
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMMember.java376
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMMethod.java828
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMNode.java1008
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMPackage.java146
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMType.java764
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/ILineStartFinder.java11
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/NullProblem.java162
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/NullProblemFactory.java52
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/SiblingEnumeration.java52
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/SimpleDOMBuilder.java347
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/lookup/ReferenceInfo.java63
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/AnonymousFileSource.java134
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CharArrayBuffer.java179
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CharArrayOps.java138
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DiskCache.java793
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DiskCacheEntry.java66
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Dumper.java319
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HackFinder.java16
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ICacheEnumeration.java33
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/IComparator.java9
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/IDumpable.java21
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ILRUCacheable.java11
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/IProgressListener.java26
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LRUCache.java518
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LookupTable.java544
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ReferenceInfoAdapter.java58
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/StringHashtableOfInt.java129
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/StringMatcher.java412
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ToStringSorter.java64
-rw-r--r--org.eclipse.jdt.core/plugin.jars8
-rw-r--r--org.eclipse.jdt.core/plugin.xml79
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchConstants.java125
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchResultCollector.java84
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchScope.java78
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ISearchPattern.java16
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ITypeNameRequestor.java42
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchEngine.java634
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DocumentFactory.java23
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IDocument.java54
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IEntryResult.java6
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IIndex.java67
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IIndexer.java28
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IIndexerOutput.java19
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IQueryResult.java8
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IndexFactory.java30
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Block.java59
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/BlocksIndexInput.java428
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/BlocksIndexOutput.java168
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/CodeByteStream.java397
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/EntryResult.java71
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Field.java445
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/FileDocument.java62
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/FileListBlock.java111
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/GammaCompressedIndexBlock.java121
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/HashtableOfObject.java101
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/ICacheEnumeration.java33
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IFileDocument.java85
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IIndexConstants.java16
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/ILRUCacheable.java11
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/InMemoryIndex.java254
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Index.java374
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexBlock.java91
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexInput.java138
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexOutput.java37
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexSummary.java334
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexedFile.java185
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexerOutput.java56
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Int.java12
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/JarFileDocument.java69
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/JarFileEntryDocument.java76
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/LRUCache.java491
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/MemoryCheckThread.java44
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/MergeFactory.java236
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/ObjectVector.java73
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/PropertyDocument.java44
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/SafeRandomAccessFile.java28
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/SimpleIndexBlock.java121
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/SimpleIndexInput.java197
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Util.java433
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/WordEntry.java164
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/AbstractSearchScope.java45
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/HierarchyScope.java152
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IIndexSearchRequestor.java102
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IInfoConstants.java9
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSearchAdapter.java99
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSelector.java240
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java208
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaWorkspaceScope.java30
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PathCollector.java173
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java146
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/SubTypeSearchJob.java119
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AbstractIndexer.java766
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddClassFileToIndex.java78
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddCompilationUnitToIndex.java79
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java184
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/BinaryIndexer.java662
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IIndexConstants.java48
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java123
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java400
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/ReadWriteMonitor.java60
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/RemoveFromIndex.java61
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexer.java80
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexerRequestor.java335
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/AndPattern.java121
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorDeclarationPattern.java326
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorReferencePattern.java271
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldDeclarationPattern.java317
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldReferencePattern.java423
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java891
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocatorParser.java177
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchSet.java332
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodDeclarationPattern.java331
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodPattern.java149
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodReferencePattern.java239
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MultipleSearchPattern.java48
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrNameCombiner.java94
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrPathCombiner.java156
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrPattern.java119
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageDeclarationPattern.java114
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageReferencePattern.java341
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SearchPattern.java1454
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperInterfaceReferencePattern.java72
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferencePattern.java254
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationPattern.java393
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferencePattern.java538
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/IJob.java14
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/IJobConstants.java11
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java285
760 files changed, 189208 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000..a4f9c0a121
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,14 @@
+bin/
+*~
+*.rej
+*.bak
+*.patch
+javacore.*
+heapdump.*
+core.*
+Snap.*
+target/
+bin-resources/
+binext/
+binprocessors/
+antbin/
diff --git a/org.eclipse.jdt.core/.classpath b/org.eclipse.jdt.core/.classpath
new file mode 100644
index 0000000000..20fe2c61c5
--- /dev/null
+++ b/org.eclipse.jdt.core/.classpath
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="Eclipse Java Evaluation"/>
+ <classpathentry kind="src" path="Eclipse Java Compiler"/>
+ <classpathentry kind="src" path="Eclipse Java Code Assist"/>
+ <classpathentry kind="src" path="Eclipse Java Model"/>
+ <classpathentry kind="src" path="Eclipse Java Formatter"/>
+ <classpathentry kind="src" path="Eclipse Java Core Search"/>
+ <classpathentry kind="src" path="Eclipse Java Batch Compiler"/>
+ <classpathentry kind="lib" path="/org.eclipse.core.resources/resources.jar"/>
+ <classpathentry kind="lib" path="/org.apache.xerces/xerces.jar"/>
+ <classpathentry kind="lib" path="/org.eclipse.core.runtime/runtime.jar"/>
+ <classpathentry kind="var" path="JRE_LIB"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.jdt.core/.cvsignore b/org.eclipse.jdt.core/.cvsignore
new file mode 100644
index 0000000000..f68b3dddc6
--- /dev/null
+++ b/org.eclipse.jdt.core/.cvsignore
@@ -0,0 +1,2 @@
+bin
+
diff --git a/org.eclipse.jdt.core/.vcm_meta b/org.eclipse.jdt.core/.vcm_meta
new file mode 100644
index 0000000000..12ced1198a
--- /dev/null
+++ b/org.eclipse.jdt.core/.vcm_meta
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project-description>
+ <nature id="org.eclipse.jdt.core.javanature"/>
+ <reference project-name="org.apache.xerces"/>
+ <reference project-name="org.eclipse.core.resources"/>
+ <builder name="org.eclipse.jdt.core.javabuilder">
+ </builder>
+</project-description>
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java
new file mode 100644
index 0000000000..1dedf04165
--- /dev/null
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java
@@ -0,0 +1,99 @@
+package org.eclipse.jdt.internal.compiler.batch;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+import java.util.*;
+
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.classfmt.*;
+
+class ClasspathDirectory implements FileSystem.Classpath {
+ String path;
+ Hashtable missingPackages;
+ Hashtable directoryCache;
+ ClasspathDirectory(File directory) {
+ this.path = directory.getAbsolutePath();
+ if (!path.endsWith(File.separator))
+ this.path += File.separator;
+ this.missingPackages = new Hashtable(11);
+ this.directoryCache = new Hashtable(11);
+ }
+
+ private String[] directoryList(char[][] compoundName, char[] packageName) {
+ String partialPath =
+ FileSystem.assembleName(packageName, compoundName, File.separatorChar);
+ String[] dirList = (String[]) directoryCache.get(partialPath);
+ if (dirList != null)
+ return dirList;
+ if (missingPackages.containsKey(partialPath))
+ return null;
+
+ File dir = new File(path + partialPath);
+ if (dir != null && dir.isDirectory()) {
+ boolean matchesName = packageName == null;
+ if (!matchesName) {
+ int index = packageName.length;
+ while (--index >= 0 && !Character.isUpperCase(packageName[index])) {
+ }
+ matchesName = index < 0 || exists(new String(packageName), compoundName);
+ // verify that the case sensitive packageName really does exist
+ }
+ if (matchesName) {
+ if ((dirList = dir.list()) == null)
+ dirList = new String[0];
+ directoryCache.put(partialPath, dirList);
+ return dirList;
+ }
+ }
+ missingPackages.put(partialPath, partialPath); // value is not used
+ return null;
+ }
+
+ public boolean exists(String filename, char[][] packageName) {
+ String[] dirList = directoryList(packageName, null);
+ if (dirList != null)
+ for (int i = dirList.length; --i >= 0;)
+ if (filename.equals(dirList[i]))
+ return true;
+ return false;
+ }
+
+ public boolean isPackage(char[][] compoundName, char[] packageName) {
+ return directoryList(compoundName, packageName) != null;
+ }
+
+ public long lastModified(String filename, char[][] packageName) {
+ File file =
+ new File(
+ path + FileSystem.assembleName(filename, packageName, File.separatorChar));
+ return file.lastModified();
+ }
+
+ public NameEnvironmentAnswer readClassFile(
+ String filename,
+ char[][] packageName) {
+ try {
+ return new NameEnvironmentAnswer(
+ ClassFileReader.read(
+ path + FileSystem.assembleName(filename, packageName, File.separatorChar)));
+ } catch (Exception e) {
+ return null; // treat as if class file is missing
+ }
+ }
+
+ public NameEnvironmentAnswer readJavaFile(
+ String fileName,
+ char[][] packageName) {
+ String fullName =
+ path + FileSystem.assembleName(fileName, packageName, File.separatorChar);
+ return new NameEnvironmentAnswer(new CompilationUnit(null, fullName));
+ }
+
+ public String toString() {
+ return "ClasspathDirectory " + path;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java
new file mode 100644
index 0000000000..f5e72f47f6
--- /dev/null
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java
@@ -0,0 +1,100 @@
+package org.eclipse.jdt.internal.compiler.batch;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+import java.util.*;
+import java.util.zip.*;
+
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.classfmt.*;
+
+class ClasspathJar implements FileSystem.Classpath {
+ ZipFile zipFile;
+ Hashtable directoryCache;
+ ClasspathJar(File file) throws IOException {
+ zipFile = new ZipFile(file);
+ buildDirectoryStructure();
+ }
+
+ void buildDirectoryStructure() {
+ directoryCache = new Hashtable(101);
+ for (Enumeration e = zipFile.entries(); e.hasMoreElements();) {
+ String fileName = ((ZipEntry) e.nextElement()).getName();
+
+ // extract the package name
+ int last = fileName.lastIndexOf('/');
+ if (last > 0 && directoryCache.get(fileName.substring(0, last)) == null) {
+ // add the package name & all of its parent packages
+ for (int i = 0; i <= last; i++) {
+ i = fileName.indexOf('/', i);
+ String packageName = fileName.substring(0, i);
+ if (directoryCache.get(packageName) == null)
+ directoryCache.put(packageName, packageName);
+ }
+ }
+ }
+ }
+
+ public boolean exists(String filename, char[][] packageName) {
+ return zipFile.getEntry(FileSystem.assembleName(filename, packageName, '/'))
+ != null;
+ }
+
+ public boolean isPackage(char[][] compoundName, char[] packageName) {
+ return directoryCache.get(
+ FileSystem.assembleName(packageName, compoundName, '/'))
+ != null;
+ }
+
+ public long lastModified(String filename, char[][] packageName) {
+ ZipEntry entry =
+ zipFile.getEntry(FileSystem.assembleName(filename, packageName, '/'));
+ if (entry == null)
+ return -1L;
+ else
+ return entry.getTime();
+ }
+
+ public NameEnvironmentAnswer readClassFile(
+ String filename,
+ char[][] packageName) {
+ try {
+ return new NameEnvironmentAnswer(
+ ClassFileReader.read(
+ zipFile,
+ FileSystem.assembleName(filename, packageName, '/')));
+ } catch (Exception e) {
+ return null; // treat as if class file is missing
+ }
+ }
+
+ public NameEnvironmentAnswer readJavaFile(
+ String filename,
+ char[][] packageName) {
+ try {
+ String fullName = FileSystem.assembleName(filename, packageName, '/');
+ ZipEntry entry = zipFile.getEntry(fullName);
+ InputStreamReader reader = new InputStreamReader(zipFile.getInputStream(entry));
+ int length;
+ char[] contents = new char[length = (int) entry.getSize()];
+ int len = 0;
+ int readSize = 0;
+ while ((readSize != -1) && (len != length)) {
+ readSize = reader.read(contents, len, length - len);
+ len += readSize;
+ }
+ reader.close();
+ return new NameEnvironmentAnswer(new CompilationUnit(contents, fullName));
+ } catch (Exception e) {
+ return null; // treat as if source file is missing
+ }
+ }
+
+ public String toString() {
+ return "Classpath for jar file " + zipFile;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/CompilationUnit.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/CompilationUnit.java
new file mode 100644
index 0000000000..80c08588f9
--- /dev/null
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/CompilationUnit.java
@@ -0,0 +1,80 @@
+package org.eclipse.jdt.internal.compiler.batch;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+
+import org.eclipse.jdt.internal.compiler.env.*;
+
+public class CompilationUnit implements ICompilationUnit {
+ public char[] contents;
+ public char[] fileName;
+ public char[] mainTypeName;
+ public CompilationUnit(char[] contents, String fileName) {
+ this.contents = contents;
+ this.fileName = fileName.toCharArray();
+
+ int start = fileName.lastIndexOf("/") + 1;
+ if (start == 0 || start < fileName.lastIndexOf("\\"))
+ start = fileName.lastIndexOf("\\") + 1;
+
+ int end = fileName.lastIndexOf(".");
+ if (end == -1)
+ end = fileName.length();
+
+ this.mainTypeName = fileName.substring(start, end).toCharArray();
+ }
+
+ public char[] getContents() {
+ if (contents != null)
+ return contents; // answer the cached source
+
+ // otherwise retrieve it
+ BufferedReader reader = null;
+ try {
+ File file = new File(new String(fileName));
+ reader = new BufferedReader(new FileReader(file));
+ int length;
+ char[] contents = new char[length = (int) file.length()];
+ int len = 0;
+ int readSize = 0;
+ while ((readSize != -1) && (len != length)) {
+ // See PR 1FMS89U
+ // We record first the read size. In this case len is the actual read size.
+ len += readSize;
+ readSize = reader.read(contents, len, length - len);
+ }
+ reader.close();
+ // See PR 1FMS89U
+ // Now we need to resize in case the default encoding used more than one byte for each
+ // character
+ if (len != length)
+ System.arraycopy(contents, 0, (contents = new char[len]), 0, len);
+ return contents;
+ } catch (FileNotFoundException e) {
+ } catch (IOException e) {
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (IOException ioe) {
+ }
+ }
+ };
+ return new char[0];
+ }
+
+ public char[] getFileName() {
+ return fileName;
+ }
+
+ public char[] getMainTypeName() {
+ return mainTypeName;
+ }
+
+ public String toString() {
+ return "CompilationUnit[" + new String(fileName) + "]";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileFinder.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileFinder.java
new file mode 100644
index 0000000000..475e59cb05
--- /dev/null
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileFinder.java
@@ -0,0 +1,59 @@
+package org.eclipse.jdt.internal.compiler.batch;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+
+public class FileFinder {
+ private final int INITIAL_SIZE = 10;
+ public String[] resultFiles = new String[INITIAL_SIZE];
+ public int counter = 0;
+ public void find(File f, String pattern, boolean verbose) {
+ if (verbose) {
+ System.out.println("Scanning of " + f.getAbsolutePath());
+ }
+ find0(f, pattern, verbose);
+ System.arraycopy(
+ resultFiles,
+ 0,
+ (resultFiles = new String[counter]),
+ 0,
+ counter);
+ if (verbose) {
+ System.out.println();
+ System.out.println("Scanning of " + f.getAbsolutePath() + " DONE");
+ }
+ }
+
+ public void find0(File f, String pattern, boolean verbose) {
+ if (f.isDirectory()) {
+ String[] files = f.list();
+ if (files == null)
+ return;
+ for (int i = 0, max = files.length; i < max; i++) {
+ File current = new File(f, files[i]);
+ if (current.isDirectory()) {
+ find0(current, pattern, verbose);
+ } else {
+ if (current.getName().toUpperCase().endsWith(pattern)) {
+ int length;
+ if ((length = resultFiles.length) == counter) {
+ System.arraycopy(
+ resultFiles,
+ 0,
+ (resultFiles = new String[length * 2]),
+ 0,
+ length);
+ }
+ resultFiles[counter++] = current.getAbsolutePath();
+ if (verbose && (counter % 100) == 0)
+ System.out.print('.');
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java
new file mode 100644
index 0000000000..1f761bae69
--- /dev/null
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java
@@ -0,0 +1,171 @@
+package org.eclipse.jdt.internal.compiler.batch;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class FileSystem implements INameEnvironment {
+ Classpath[] classpaths;
+ String[] knownFileNames;
+
+ interface Classpath {
+ boolean exists(String filename, char[][] packageName);
+ long lastModified(String filename, char[][] packageName);
+ NameEnvironmentAnswer readClassFile(String filename, char[][] packageName);
+ NameEnvironmentAnswer readJavaFile(String filename, char[][] packageName);
+ boolean isPackage(char[][] compoundName, char[] packageName);
+ }
+
+ /*
+ classPathNames is a collection is Strings representing the full path of each class path
+ initialFileNames is a collection is Strings, the trailing '.java' will be removed if its not already.
+ */
+
+ public FileSystem(String[] classpathNames, String[] initialFileNames) {
+ int classpathSize = classpathNames.length;
+ classpaths = new Classpath[classpathSize];
+ String[] pathNames = new String[classpathSize];
+ int problemsOccured = 0;
+ for (int i = 0; i < classpathSize; i++) {
+ try {
+ File file = new File(convertPathSeparators(classpathNames[i]));
+ if (file.exists()) {
+ if (file.isDirectory()) {
+ classpaths[i] = new ClasspathDirectory(file);
+ pathNames[i] = ((ClasspathDirectory) classpaths[i]).path;
+ } else
+ if (classpathNames[i].endsWith(".jar")
+ | (classpathNames[i].endsWith(".zip"))) {
+ classpaths[i] = new ClasspathJar(file);
+ pathNames[i] =
+ classpathNames[i].substring(0, classpathNames[i].lastIndexOf('.'));
+ }
+ }
+ } catch (IOException e) {
+ classpaths[i] = null;
+ }
+ if (classpaths[i] == null)
+ problemsOccured++;
+ }
+ if (problemsOccured > 0) {
+ Classpath[] newPaths = new Classpath[classpathSize - problemsOccured];
+ String[] newNames = new String[classpathSize - problemsOccured];
+ for (int i = 0, current = 0; i < classpathSize; i++)
+ if (classpaths[i] != null) {
+ newPaths[current] = classpaths[i];
+ newNames[current++] = pathNames[i];
+ }
+ classpathSize = newPaths.length;
+ classpaths = newPaths;
+ pathNames = newNames;
+ }
+
+ knownFileNames = new String[initialFileNames.length];
+ for (int i = initialFileNames.length; --i >= 0;) {
+ String fileName = initialFileNames[i];
+ String matchingPathName = null;
+ if (fileName.lastIndexOf(".") != -1)
+ fileName = fileName.substring(0, fileName.lastIndexOf('.'));
+ // remove trailing ".java"
+
+ fileName = convertPathSeparators(fileName);
+ for (int j = 0; j < classpathSize; j++)
+ if (fileName.startsWith(pathNames[j]))
+ matchingPathName = pathNames[j];
+ if (matchingPathName == null)
+ knownFileNames[i] = fileName; // leave as is...
+ else
+ knownFileNames[i] = fileName.substring(matchingPathName.length());
+ }
+ }
+
+ static String assembleName(
+ char[] fileName,
+ char[][] packageName,
+ char separator) {
+ return new String(CharOperation.concatWith(packageName, fileName, separator));
+ }
+
+ static String assembleName(
+ String fileName,
+ char[][] packageName,
+ char separator) {
+ return new String(
+ CharOperation.concatWith(
+ packageName,
+ fileName == null ? null : fileName.toCharArray(),
+ separator));
+ }
+
+ private String convertPathSeparators(String path) {
+ if (File.separatorChar == '/')
+ return path.replace('\\', '/');
+ else
+ return path.replace('/', '\\');
+ }
+
+ private NameEnvironmentAnswer findClass(char[] name, char[][] packageName) {
+ String fullName = assembleName(name, packageName, File.separatorChar);
+ for (int i = 0, length = knownFileNames.length; i < length; i++)
+ if (fullName.equals(knownFileNames[i]))
+ return null;
+ // looking for a file which we know was provided at the beginning of the compilation
+
+ String filename = new String(name);
+ String binaryFilename = filename + ".class";
+ String sourceFilename = filename + ".java";
+ for (int i = 0, length = classpaths.length; i < length; i++) {
+ Classpath classpath = classpaths[i];
+ boolean binaryExists = classpath.exists(binaryFilename, packageName);
+ boolean sourceExists = classpath.exists(sourceFilename, packageName);
+ if (binaryExists == sourceExists) {
+ if (binaryExists) { // so both are true
+ long binaryModified = classpath.lastModified(binaryFilename, packageName);
+ long sourceModified = classpath.lastModified(sourceFilename, packageName);
+ if (binaryModified > sourceModified)
+ return classpath.readClassFile(binaryFilename, packageName);
+ if (sourceModified > 0)
+ return classpath.readJavaFile(sourceFilename, packageName);
+ }
+ } else {
+ if (binaryExists)
+ return classpath.readClassFile(binaryFilename, packageName);
+ else
+ return classpath.readJavaFile(sourceFilename, packageName);
+ }
+ }
+ return null;
+ }
+
+ public NameEnvironmentAnswer findType(char[][] compoundName) {
+ if (compoundName == null)
+ return null;
+ else
+ return findClass(
+ compoundName[compoundName.length - 1],
+ CharOperation.subarray(compoundName, 0, compoundName.length - 1));
+ }
+
+ public NameEnvironmentAnswer findType(char[] name, char[][] compoundName) {
+ if (name == null)
+ return null;
+ else
+ return findClass(name, compoundName);
+ }
+
+ public boolean isPackage(char[][] compoundName, char[] packageName) {
+ if (compoundName == null)
+ compoundName = new char[0][];
+
+ for (int i = 0, length = classpaths.length; i < length; i++)
+ if (classpaths[i].isPackage(compoundName, packageName))
+ return true;
+ return false;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
new file mode 100644
index 0000000000..a017019aa1
--- /dev/null
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
@@ -0,0 +1,841 @@
+package org.eclipse.jdt.internal.compiler.batch;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.Compiler;
+
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.*;
+
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.parser.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+import org.eclipse.jdt.internal.compiler.impl.*;
+
+import java.io.*;
+import java.util.*;
+
+public class Main implements ConfigurableProblems, ProblemSeverities {
+ PrintWriter out;
+ boolean systemExitWhenFinished = true;
+ boolean proceedOnError = false;
+ int warningMask =
+ ParsingOptionalError
+ | MethodWithConstructorName
+ | OverriddenPackageDefaultMethod
+ | UsingDeprecatedAPI
+ | MaskedCatchBlock
+ | UnusedLocalVariable
+ | UnusedArgument
+ | TemporaryWarning
+ | OverriddenPackageDefaultMethod
+ | AccessEmulation;
+
+ int debugMask = CompilerOptions.Lines | CompilerOptions.Source;
+ int targetJDK = CompilerOptions.JDK1_1;
+ boolean verbose = false;
+ boolean produceRefInfo = false;
+ boolean importProblemIsError = true;
+ boolean timer = false;
+ boolean showProgress = false;
+ public long time = 0;
+ long lineCount;
+ boolean preserveAllLocalVariables = false;
+ // The unused and final local variables will be optimized
+
+ String[] filenames;
+ String[] classpaths;
+ String destinationPath;
+ String log;
+ int repetitions;
+ int globalProblemsCount;
+ int globalErrorsCount;
+ int globalWarningsCount;
+
+ String versionID = "0.103";
+ private static final char[] CLASS_FILE_EXTENSION = ".class".toCharArray();
+
+ int exportedClassFilesCounter;
+ protected Main(PrintWriter writer, boolean systemExitWhenFinished) {
+ this.out = writer;
+ this.systemExitWhenFinished = systemExitWhenFinished;
+ exportedClassFilesCounter = 0;
+ }
+
+ /*
+ * Low-level API performing the actual compilation
+ */
+ protected void compile(String[] argv) {
+ // decode command line arguments
+ try {
+ configure(argv);
+ if (showProgress)
+ System.out.print("Compiling");
+ for (int i = 0; i < repetitions; i++) {
+ globalProblemsCount = 0;
+ globalErrorsCount = 0;
+ globalWarningsCount = 0;
+ lineCount = 0;
+ if (repetitions > 1) {
+ out.flush();
+ out.println("Repetition " + (i + 1) + "/" + repetitions);
+ }
+ long startTime = System.currentTimeMillis();
+
+ // request compilation
+ performCompilation();
+ if (timer) {
+ time = System.currentTimeMillis() - startTime;
+ if (lineCount != 0) {
+ out.println(
+ "Compiled "
+ + lineCount
+ + " lines in "
+ + time
+ + " ms ("
+ + (((int) ((lineCount * 10000.0) / time)) / 10.0)
+ + " lines/s)");
+ } else {
+ out.println("Total compilation time: " + time);
+ }
+ }
+ if (globalProblemsCount > 0) {
+ if (globalProblemsCount == 1) {
+ out.print("1 problem (");
+ } else {
+ out.print(globalProblemsCount + " problems (");
+ }
+ if (globalErrorsCount > 0) {
+ if (globalErrorsCount == 1) {
+ out.print("1 error");
+ } else {
+ out.print(globalErrorsCount + " errors");
+ }
+ }
+ if (globalWarningsCount > 0) {
+ if (globalErrorsCount > 0) {
+ out.print(", ");
+ }
+ if (globalWarningsCount == 1) {
+ out.print("1 warning");
+ } else {
+ out.print(globalWarningsCount + " warnings");
+ }
+ }
+ out.println(")");
+ }
+ if (exportedClassFilesCounter != 0
+ && (this.showProgress || this.timer || this.verbose)) {
+ if (exportedClassFilesCounter == 1) {
+ out.println("1 .class file generated");
+ } else {
+ out.println(exportedClassFilesCounter + " .class files generated");
+ }
+ }
+ }
+ if (showProgress)
+ System.out.println();
+ if (systemExitWhenFinished) {
+ out.flush();
+ System.exit(globalErrorsCount > 0 ? -1 : 0);
+ }
+ } catch (InvalidInputException e) {
+ out.println(e.getMessage());
+ out.println("------------------------");
+ printUsage();
+ if (systemExitWhenFinished) {
+ System.exit(-1);
+ }
+ } catch (ThreadDeath e) { // do not stop this one
+ throw e;
+ } catch (Throwable e) { // internal compiler error
+ if (systemExitWhenFinished) {
+ out.flush();
+ System.exit(-1);
+ }
+ } finally {
+ out.flush();
+ }
+ }
+
+ /*
+ * Internal IDE API
+ */
+ public static void compile(String commandLine) {
+ compile(commandLine, new PrintWriter(System.out));
+ }
+
+ /*
+ * Internal IDE API for test harness purpose
+ */
+ public static void compile(String commandLine, PrintWriter writer) {
+ int count = 0;
+ String[] argv = new String[10];
+ int startIndex = 0;
+ int lastIndex = commandLine.indexOf('"');
+ boolean insideQuotes = false;
+ boolean insideClasspath = false;
+ StringTokenizer tokenizer;
+ while (lastIndex != -1) {
+ if (insideQuotes) {
+ if (count == argv.length) {
+ System.arraycopy(argv, 0, (argv = new String[count * 2]), 0, count);
+ }
+ if (insideClasspath) {
+ argv[count - 1] += commandLine.substring(startIndex, lastIndex);
+ insideClasspath = false;
+ } else {
+ argv[count++] = commandLine.substring(startIndex, lastIndex);
+ }
+ } else {
+ String subCommandLine = commandLine.substring(startIndex, lastIndex);
+ if (subCommandLine.equals(File.pathSeparator)) {
+ argv[count - 1] += File.pathSeparator;
+ insideClasspath = true;
+ } else {
+ tokenizer = new StringTokenizer(subCommandLine, File.pathSeparator + " ");
+ while (tokenizer.hasMoreTokens()) {
+ if (count == argv.length) {
+ System.arraycopy(argv, 0, (argv = new String[count * 2]), 0, count);
+ }
+ argv[count++] = tokenizer.nextToken();
+ }
+ }
+ }
+ startIndex = lastIndex + 1;
+ lastIndex = commandLine.indexOf('"', startIndex);
+ insideQuotes = !insideQuotes;
+ }
+ if (startIndex == 0) {
+ tokenizer = new StringTokenizer(commandLine);
+ while (tokenizer.hasMoreTokens()) {
+ if (count == argv.length) {
+ System.arraycopy(argv, 0, (argv = new String[count * 2]), 0, count);
+ }
+ argv[count++] = tokenizer.nextToken();
+ }
+ } else {
+ if (startIndex + 1 <= commandLine.length()) {
+ if (insideQuotes) {
+ if (count == argv.length) {
+ System.arraycopy(argv, 0, (argv = new String[count * 2]), 0, count);
+ }
+ argv[count++] = commandLine.substring(startIndex, commandLine.length());
+ } else {
+ tokenizer =
+ new StringTokenizer(
+ commandLine.substring(startIndex, commandLine.length()),
+ File.pathSeparator + " ");
+ while (tokenizer.hasMoreTokens()) {
+ if (count == argv.length) {
+ System.arraycopy(argv, 0, (argv = new String[count * 2]), 0, count);
+ }
+ argv[count++] = tokenizer.nextToken();
+ }
+ }
+ }
+ }
+ System.arraycopy(argv, 0, argv = new String[count], 0, count);
+ new Main(writer, false).compile(argv);
+ }
+
+ /*
+ Decode the command line arguments
+ */
+ private void configure(String[] argv) throws InvalidInputException {
+ if ((argv == null) || (argv.length == 0))
+ throw new InvalidInputException("no source file specified");
+ final int InsideClasspath = 1;
+ final int InsideDestinationPath = 2;
+ final int TargetSetting = 4;
+ final int InsideLog = 8;
+ final int InsideRepetition = 16;
+ final int Default = 0;
+ int DEFAULT_SIZE_CLASSPATH = 4;
+ boolean noWarnOptionInUsed = false;
+ boolean warnOptionInUsed = false;
+ int pathCount = 0;
+ int index = -1, filesCount = 0, argCount = argv.length;
+ int mode = Default;
+ repetitions = 0;
+ boolean versionIDRequired = false;
+ boolean printUsageRequired = false;
+
+ while (++index < argCount) {
+ String currentArg = argv[index].trim();
+ if (currentArg.endsWith(".java")) {
+ if (filenames == null) {
+ filenames = new String[argCount - index];
+ } else
+ if (filesCount == filenames.length) {
+ int length = filenames.length;
+ System.arraycopy(
+ filenames,
+ 0,
+ (filenames = new String[length + argCount - index]),
+ 0,
+ length);
+ }
+ filenames[filesCount++] = currentArg;
+ mode = Default;
+ continue;
+ }
+ if (currentArg.equals("-log")) {
+ if (log != null)
+ throw new InvalidInputException("duplicate log specification: " + currentArg);
+ mode = InsideLog;
+ continue;
+ }
+ if (currentArg.equals("-repeat")) {
+ if (repetitions > 0)
+ throw new InvalidInputException(
+ "duplicate repeat specification: " + currentArg);
+ mode = InsideRepetition;
+ continue;
+ }
+ if (currentArg.equals("-d")) {
+ if (destinationPath != null)
+ throw new InvalidInputException(
+ "duplicate output path specification: " + currentArg);
+ mode = InsideDestinationPath;
+ continue;
+ }
+ if (currentArg.equals("-classpath")) {
+ if (pathCount > 0)
+ throw new InvalidInputException(
+ "duplicate classpath specification: " + currentArg);
+ classpaths = new String[DEFAULT_SIZE_CLASSPATH];
+ mode = InsideClasspath;
+ continue;
+ }
+ if (currentArg.equals("-progress")) {
+ mode = Default;
+ showProgress = true;
+ continue;
+ }
+ if (currentArg.equals("-proceedOnError")) {
+ mode = Default;
+ proceedOnError = true;
+ continue;
+ }
+ if (currentArg.equals("-time")) {
+ mode = Default;
+ timer = true;
+ continue;
+ }
+ if (currentArg.equals("-version") || currentArg.equals("-v")) {
+ versionIDRequired = true;
+ continue;
+ }
+ if (currentArg.equals("-help")) {
+ printUsageRequired = true;
+ continue;
+ }
+ if (currentArg.equals("-noImportError")) {
+ mode = Default;
+ importProblemIsError = false;
+ continue;
+ }
+ if (currentArg.equals("-noExit")) {
+ mode = Default;
+ systemExitWhenFinished = false;
+ continue;
+ }
+ if (currentArg.equals("-verbose")) {
+ mode = Default;
+ verbose = true;
+ continue;
+ }
+ if (currentArg.equals("-referenceInfo")) {
+ mode = Default;
+ produceRefInfo = true;
+ continue;
+ }
+ if (currentArg.startsWith("-g")) {
+ mode = Default;
+ debugMask = 0; // reinitialize the default value
+ String debugOption = currentArg;
+ int length = currentArg.length();
+ if (length == 2) {
+ debugMask =
+ CompilerOptions.Lines | CompilerOptions.Vars | CompilerOptions.Source;
+ continue;
+ }
+ if (length > 3) {
+ if (length == 7 && debugOption.equals("-g:none"))
+ continue;
+ StringTokenizer tokenizer =
+ new StringTokenizer(debugOption.substring(3, debugOption.length()), ",");
+ while (tokenizer.hasMoreTokens()) {
+ String token = tokenizer.nextToken();
+ if (token.equals("vars")) {
+ debugMask |= CompilerOptions.Vars;
+ } else
+ if (token.equals("lines")) {
+ debugMask |= CompilerOptions.Lines;
+ } else
+ if (token.equals("source")) {
+ debugMask |= CompilerOptions.Source;
+ } else {
+ throw new InvalidInputException("invalid debug option: " + debugOption);
+ }
+ }
+ continue;
+ }
+ throw new InvalidInputException("invalid debug option: " + debugOption);
+ }
+ if (currentArg.startsWith("-nowarn")) {
+ noWarnOptionInUsed = true;
+ if (warnOptionInUsed)
+ throw new InvalidInputException("duplicate usage of warning configuration");
+ mode = Default;
+ warningMask = TemporaryWarning;
+ // reinitialize the default value (still see TemporaryWarning)
+ continue;
+ }
+ if (currentArg.startsWith("-warn")) {
+ warnOptionInUsed = true;
+ if (noWarnOptionInUsed)
+ throw new InvalidInputException("duplicate usage of warning configuration");
+ mode = Default;
+ String warningOption = currentArg;
+ int length = currentArg.length();
+ if (length == 10 && warningOption.equals("-warn:none")) {
+ warningMask = TemporaryWarning;
+ // reinitialize the default value (still see TemporaryWarning)
+ continue;
+ }
+ if (length < 6)
+ throw new InvalidInputException(
+ "invalid warning configuration: " + warningOption);
+ StringTokenizer tokenizer =
+ new StringTokenizer(warningOption.substring(6, warningOption.length()), ",");
+ int tokenCounter = 0;
+ warningMask = 0; // reinitialize the default value
+ while (tokenizer.hasMoreTokens()) {
+ String token = tokenizer.nextToken();
+ tokenCounter++;
+ if (token.equals("constructorName")) {
+ warningMask |= CompilerOptions.MethodWithConstructorName;
+ } else
+ if (token.equals("packageDefaultMethod")) {
+ warningMask |= CompilerOptions.OverriddenPackageDefaultMethod;
+ } else
+ if (token.equals("maskedCatchBlocks")) {
+ warningMask |= CompilerOptions.MaskedCatchBlock;
+ } else
+ if (token.equals("deprecation")) {
+ warningMask |= CompilerOptions.UsingDeprecatedAPI;
+ } else
+ if (token.equals("unusedLocals")) {
+ warningMask |= CompilerOptions.UnusedLocalVariable;
+ } else
+ if (token.equals("unusedArguments")) {
+ warningMask |= CompilerOptions.UnusedArgument;
+ } else
+ if (token.equals("syntheticAccess")) {
+ warningMask |= CompilerOptions.AccessEmulation;
+ } else {
+ throw new InvalidInputException("invalid warning: " + token);
+ }
+ }
+ if (tokenCounter == 0)
+ throw new InvalidInputException("invalid warning option: " + currentArg);
+ continue;
+ }
+ if (currentArg.equals("-target")) {
+ mode = TargetSetting;
+ continue;
+ }
+ if (currentArg.equals("-preserveAllLocals")) {
+ preserveAllLocalVariables = true;
+ continue;
+ }
+ if (mode == TargetSetting) {
+ if (currentArg.equals("1.1")) {
+ targetJDK = CompilerOptions.JDK1_1;
+ } else
+ if (currentArg.equals("1.2")) {
+ targetJDK = CompilerOptions.JDK1_2;
+ } else {
+ throw new InvalidInputException(
+ "target JDK is either '1.1' or '1.2': " + currentArg);
+ }
+ mode = Default;
+ continue;
+ }
+ if (mode == InsideLog) {
+ log = currentArg;
+ mode = Default;
+ continue;
+ }
+ if (mode == InsideRepetition) {
+ try {
+ repetitions = Integer.parseInt(currentArg);
+ if (repetitions <= 0) {
+ throw new InvalidInputException(
+ "repetition must be a positive integer: " + currentArg);
+ }
+ } catch (NumberFormatException e) {
+ throw new InvalidInputException(
+ "repetition must be a positive integer: " + currentArg);
+ }
+ mode = Default;
+ continue;
+ }
+ if (mode == InsideDestinationPath) {
+ destinationPath = currentArg;
+ mode = Default;
+ continue;
+ }
+ if (mode == InsideClasspath) {
+ StringTokenizer tokenizer = new StringTokenizer(currentArg, File.pathSeparator);
+ while (tokenizer.hasMoreTokens()) {
+ int length;
+ if ((length = classpaths.length) <= pathCount) {
+ System.arraycopy(
+ classpaths,
+ 0,
+ (classpaths = new String[length * 2]),
+ 0,
+ length);
+ }
+ classpaths[pathCount++] = tokenizer.nextToken();
+ }
+ mode = Default;
+ continue;
+ }
+ //default is input directory
+ currentArg = currentArg.replace('/', File.separatorChar);
+ if (currentArg.endsWith(File.separator))
+ currentArg =
+ currentArg.substring(0, currentArg.length() - File.separator.length());
+ File dir = new File(currentArg);
+ if (!dir.isDirectory())
+ throw new InvalidInputException("directory does not exist: " + currentArg);
+ FileFinder finder = new FileFinder();
+ try {
+ finder.find(dir, ".JAVA", verbose);
+ } catch (Exception e) {
+ throw new InvalidInputException(
+ "i/o error : unable to retrieve .JAVA files in directory: " + currentArg);
+ }
+ if (filenames != null) {
+ // some source files were specified explicitly
+ String results[] = finder.resultFiles;
+ int length = results.length;
+ System.arraycopy(
+ filenames,
+ 0,
+ (filenames = new String[length + filesCount]),
+ 0,
+ filesCount);
+ System.arraycopy(results, 0, filenames, filesCount, length);
+ filesCount += length;
+ } else {
+ filenames = finder.resultFiles;
+ filesCount = filenames.length;
+ }
+ mode = Default;
+ continue;
+ }
+
+ /*
+ * Standalone options
+ */
+ if (versionIDRequired) {
+ out.println(
+ "Eclipse Java Compiler " + this.versionID + ", Copyright IBM Corp 2000\n");
+ return;
+ }
+
+ if (printUsageRequired) {
+ printUsage();
+ return;
+ }
+
+ if (filesCount != 0)
+ System.arraycopy(
+ filenames,
+ 0,
+ (filenames = new String[filesCount]),
+ 0,
+ filesCount);
+ if (pathCount == 0) {
+ String classProp = System.getProperty("LFclasspath");
+ if ((classProp == null) || (classProp.length() == 0)) {
+ out.println(
+ "no classpath defined (LF_CLASSPATH), using default directory instead");
+ classProp = ".";
+ }
+ StringTokenizer tokenizer = new StringTokenizer(classProp, File.pathSeparator);
+ classpaths = new String[tokenizer.countTokens()];
+ while (tokenizer.hasMoreTokens()) {
+ classpaths[pathCount++] = tokenizer.nextToken();
+ }
+ }
+
+ if (classpaths == null)
+ classpaths = new String[0];
+ System.arraycopy(
+ classpaths,
+ 0,
+ (classpaths = new String[pathCount]),
+ 0,
+ pathCount);
+ for (int i = 0, max = classpaths.length; i < max; i++) {
+ File file = new File(classpaths[i]);
+ if (!file.exists())
+ throw new InvalidInputException("incorrect classpath: " + classpaths[i]);
+ }
+ if (destinationPath == null) {
+ destinationPath = System.getProperty("user.dir");
+ } else
+ if ("none".equals(destinationPath)) {
+ destinationPath = null;
+ }
+
+ if (filenames == null)
+ throw new InvalidInputException("no source file specified");
+
+ if (log != null) {
+ try {
+ out = new PrintWriter(new FileOutputStream(log, false));
+ } catch (IOException e) {
+ throw new InvalidInputException("cannot open .log file");
+ }
+ } else {
+ showProgress = false;
+ }
+ if (repetitions == 0) {
+ repetitions = 1;
+ }
+ }
+
+ /*
+ * Answer the component to which will be handed back compilation results from the compiler
+ */
+ protected ICompilerRequestor getBatchRequestor() {
+ return new ICompilerRequestor() {
+ int lineDelta = 0;
+ public void acceptResult(CompilationResult compilationResult) {
+ if (compilationResult.lineSeparatorPositions != null) {
+ int unitLineCount = compilationResult.lineSeparatorPositions.length;
+ lineCount += unitLineCount;
+ lineDelta += unitLineCount;
+ if (showProgress
+ && lineDelta > 2000) { // in -log mode, dump a dot every 2000 lines compiled
+ System.out.print('.');
+ lineDelta = 0;
+ }
+ }
+ if (compilationResult.hasProblems()) {
+ IProblem[] problems = compilationResult.getProblems();
+ int count = problems.length;
+ int localErrorCount = 0;
+ for (int i = 0; i < count; i++) {
+ if (problems[i] != null) {
+ globalProblemsCount++;
+ if (localErrorCount == 0)
+ out.println("----------");
+ out.print(
+ globalProblemsCount + (problems[i].isError() ? ". ERROR" : ". WARNING"));
+ if (problems[i].isError()) {
+ globalErrorsCount++;
+ } else {
+ globalWarningsCount++;
+ }
+ out.print(" in " + new String(problems[i].getOriginatingFileName()));
+ try {
+ out.println(
+ ((DefaultProblem) problems[i]).errorReportSource(
+ compilationResult.compilationUnit));
+ out.println(problems[i].getMessage());
+ } catch (Exception e) {
+ out.println("Cannot retrieve the error message for " + problems[i].toString());
+ }
+ out.println("----------");
+ if (problems[i].isError())
+ localErrorCount++;
+ }
+ };
+ // exit?
+ if (systemExitWhenFinished && !proceedOnError && (localErrorCount > 0)) {
+ out.flush();
+ System.exit(-1);
+ }
+ }
+ outputClassFiles(compilationResult);
+ }
+ };
+ }
+
+ /*
+ * Build the set of compilation source units
+ */
+ protected CompilationUnit[] getCompilationUnits()
+ throws InvalidInputException {
+ int fileCount = filenames.length;
+ CompilationUnit[] units = new CompilationUnit[fileCount];
+
+ HashtableOfObject knownFileNames = new HashtableOfObject(fileCount);
+
+ for (int i = 0; i < fileCount; i++) {
+ char[] charName = filenames[i].toCharArray();
+ if (knownFileNames.get(charName) != null) {
+ throw new InvalidInputException(
+ "File " + filenames[i] + " is specified more than once");
+ } else {
+ knownFileNames.put(charName, charName);
+ }
+ File file = new File(filenames[i]);
+ if (!file.exists())
+ throw new InvalidInputException("File " + filenames[i] + " is missing");
+ units[i] = new CompilationUnit(null, filenames[i]);
+ }
+ return units;
+ }
+
+ /*
+ * Low-level API performing the actual compilation
+ */
+ protected IErrorHandlingPolicy getHandlingPolicy() {
+
+ // passes the initial set of files to the batch oracle (to avoid finding more than once the same units when case insensitive match)
+ return new IErrorHandlingPolicy() {
+ public boolean stopOnFirstError() {
+ return false;
+ }
+ public boolean proceedOnErrors() {
+ return proceedOnError; // stop if there are some errors
+ }
+ };
+ }
+
+ /*
+ * Low-level API performing the actual compilation
+ */
+ protected FileSystem getLibraryAccess() {
+ return new FileSystem(classpaths, filenames);
+ }
+
+ /*
+ * Low-level API performing the actual compilation
+ */
+ protected ConfigurableOption[] getOptions() {
+ CompilerOptions options = new CompilerOptions();
+ options.produceDebugAttributes(debugMask);
+ options.preserveAllLocalVariables(preserveAllLocalVariables);
+ options.handleImportProblemAsError(importProblemIsError);
+ options.setWarningThreshold(warningMask);
+ options.setTargetJDK(targetJDK);
+ return options.getConfigurableOptions(Locale.getDefault());
+ }
+
+ protected IProblemFactory getProblemFactory() {
+ return new DefaultProblemFactory(Locale.getDefault());
+ }
+
+ /*
+ * External API
+ */
+
+ public static void main(String[] argv) {
+ new Main(new PrintWriter(System.out), true).compile(argv);
+ }
+
+ // Dump classfiles onto disk for all compilation units that where successfull.
+
+ protected void outputClassFiles(CompilationResult unitResult) {
+
+ if (!((unitResult == null) || (unitResult.hasErrors() && !proceedOnError))) {
+ Enumeration classFiles = unitResult.compiledTypes.elements();
+ if (destinationPath != null) {
+ while (classFiles.hasMoreElements()) {
+ // retrieve the key and the corresponding classfile
+ ClassFile classFile = (ClassFile) classFiles.nextElement();
+ char[] filename = classFile.fileName();
+ int length = filename.length;
+ char[] relativeName = new char[length + 6];
+ System.arraycopy(filename, 0, relativeName, 0, length);
+ System.arraycopy(CLASS_FILE_EXTENSION, 0, relativeName, length, 6);
+ CharOperation.replace(relativeName, '/', File.separatorChar);
+ try {
+ ClassFile.writeToDisk(
+ destinationPath,
+ new String(relativeName),
+ classFile.getBytes());
+ } catch (IOException e) {
+ String fileName = destinationPath + new String(relativeName);
+ e.printStackTrace();
+ System.out.println(
+ "No .class file created for file named "
+ + fileName
+ + " because of a IOException.");
+ }
+ exportedClassFilesCounter++;
+ }
+ }
+ }
+ }
+
+ /*
+ * Low-level API performing the actual compilation
+ */
+ protected void performCompilation() throws InvalidInputException {
+ Compiler batchCompiler =
+ new Compiler(
+ getLibraryAccess(),
+ getHandlingPolicy(),
+ getOptions(),
+ getBatchRequestor(),
+ getProblemFactory());
+
+ CompilerOptions options = batchCompiler.options;
+ // set the non-externally configurable options.
+ options.setVerboseMode(verbose);
+ options.produceReferenceInfo(produceRefInfo);
+
+ batchCompiler.compile(getCompilationUnits());
+ }
+
+ private void printUsage() {
+ out.println(
+ "Eclipse Java Compiler "
+ + this.versionID
+ + ", Copyright IBM Corp 2000\n\n"
+ + "Usage: <options> <source files | directories>\n\n"
+ + "where options include:\n"
+ + "-version or -v\tdisplays the version number (standalone option)\n"
+ + "-help\tdisplay this help message (standalone option)\n"
+ + "-noExit\tPrevent the compiler to call System.exit at the end of the compilation process\n"
+ + "-classpath <dir 1>;<dir 2>;...;<dir P>\n"
+ + "-d <dir>\tdestination directory\n\t\t, specified '-d none' if you don't want to dump files\n"
+ + "-verbose\tprint accessed/processed compilation units \n"
+ + "-time\t\tdisplay total compilation time"
+ + "\n\t\tand speed if line attributes are enabled\n"
+ + "-log <filename>\tspecify a log file for recording problems\n"
+ + "-progress\t\tshow progress (only in -log mode)\n"
+ + "-g[:<level>]\tspecify the level of details for debug attributes"
+ + "\n\t\t-g\tgenerate all debug info"
+ + "\n\t\t-g:none\tno debug info"
+ + "\n\t\t-g:{lines,vars,source}\tonly some debug info\n"
+ + "-nowarn\t\tdo not report warnings \n"
+ + "-warn:<mask>\tspecify the level of details for warnings\n"
+ + "\t\t-warn:none no warning\n"
+ + "\t\t-warn:{constructorName, packageDefaultMethod, deprecation,\n"
+ + "\t\t\tmaskedCatchBlocks, unusedLocals, unusedArguments, \n"
+ + "\t\t\tsyntheticAccess}\n"
+ + "-noImportError\tdo not report errors on incorrect imports\n"
+ + "-proceedOnError\tkeep compiling when error, \n\t\tdumping class files with problem methods\n"
+ + "-referenceInfo\tcompute reference info\n"
+ + "-preserveAllLocals\trequest code gen preserve all local variables\n"
+ + "-repeat <n>\trepeat compilation process for performance analysis\n");
+ out.flush();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/build.properties b/org.eclipse.jdt.core/build.properties
new file mode 100644
index 0000000000..871149d68b
--- /dev/null
+++ b/org.eclipse.jdt.core/build.properties
@@ -0,0 +1,24 @@
+# VAJ build contribution
+build.includes=plugin.xml,plugin.jars,build.properties
+build.vaj.Eclipse\ Java\ Batch\ Compiler=Eclipse Java Batch Compiler
+build.vaj.Eclipse\ Java\ Code\ Assist=Eclipse Java Code Assist
+build.vaj.Eclipse\ Java\ Compiler=Eclipse Java Compiler
+build.vaj.Eclipse\ Java\ Core\ Search=Eclipse Java Core Search
+build.vaj.Eclipse\ Java\ Evaluation=Eclipse Java Evaluation
+build.vaj.Eclipse\ Java\ Formatter=Eclipse Java Formatter
+build.vaj.Eclipse\ Java\ Model=Eclipse Java Model
+
+
+# Eclipse build contribution
+source.jdtcore.jar=Eclipse Java Batch Compiler,\
+ Eclipse Java Code Assist,\
+ Eclipse Java Formatter,\
+ Eclipse Java Compiler,\
+ Eclipse Java Evaluation,\
+ Eclipse Java Core Search,\
+ Eclipse Java Model
+bin.includes=plugin.xml,*.jar
+javadoc.packages=org.eclipse.jdt.core.*,\
+ org.eclipse.jdt.core.eval.*,\
+ org.eclipse.jdt.core.jdom.*,\
+ org.eclipse.jdt.core.search.* \ No newline at end of file
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
new file mode 100644
index 0000000000..aed17b0a2d
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java
@@ -0,0 +1,1287 @@
+package org.eclipse.jdt.internal.codeassist;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.Locale;
+
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.*;
+
+import org.eclipse.jdt.internal.codeassist.impl.*;
+import org.eclipse.jdt.internal.codeassist.complete.*;
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.parser.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+import org.eclipse.jdt.internal.compiler.impl.*;
+
+/**
+ * This class is the entry point for source completions.
+ * It contains two public APIs used to call CodeAssist on a given source with
+ * a given environment, assisting position and storage (and possibly options).
+ */
+public final class CompletionEngine
+ extends Engine
+ implements ISearchRequestor, TypeConstants {
+ CompletionParser parser;
+ ISearchableNameEnvironment nameEnvironment;
+ ICompletionRequestor requestor;
+
+ CompilationUnitScope unitScope;
+ char[] source;
+ boolean resolvingImports = false;
+ boolean insideQualifiedReference = false;
+ int startPosition, endPosition;
+ HashtableOfObject knownPkgs = new HashtableOfObject(10);
+ /*
+ static final char[][] mainDeclarations =
+ new char[][] {
+ "package".toCharArray(),
+ "import".toCharArray(),
+ "abstract".toCharArray(),
+ "final".toCharArray(),
+ "public".toCharArray(),
+ "class".toCharArray(),
+ "interface".toCharArray()};
+
+ static final char[][] modifiers = // may want field, method, type & member type modifiers
+ new char[][] {
+ "abstract".toCharArray(),
+ "final".toCharArray(),
+ "native".toCharArray(),
+ "public".toCharArray(),
+ "protected".toCharArray(),
+ "private".toCharArray(),
+ "static".toCharArray(),
+ "strictfp".toCharArray(),
+ "synchronized".toCharArray(),
+ "transient".toCharArray(),
+ "volatile".toCharArray()};
+ */
+ static final char[][] baseTypes =
+ new char[][] {
+ "boolean".toCharArray(),
+ "byte".toCharArray(),
+ "char".toCharArray(),
+ "double".toCharArray(),
+ "float".toCharArray(),
+ "int".toCharArray(),
+ "long".toCharArray(),
+ "short".toCharArray(),
+ "void".toCharArray()};
+
+ static final char[] classField = "class".toCharArray();
+ static final char[] lengthField = "length".toCharArray();
+ /**
+ * The CompletionEngine is responsible for computing source completions.
+ *
+ * It requires a searchable name environment, which supports some
+ * specific search APIs, and a requestor to feed back the results to a UI.
+ *
+ * @param environment com.ibm.codeassist.java.api.ISearchableNameEnvironment
+ * used to resolve type/package references and search for types/packages
+ * based on partial names.
+ *
+ * @param requestor com.ibm.codeassist.java.api.ICompletionRequestor
+ * since the engine might produce answers of various forms, the engine
+ * is associated with a requestor able to accept all possible completions.
+ *
+ * @param options com.ibm.compiler.java.api.ConfigurableOptions
+ * set of options used to configure the code assist engine.
+ */
+
+ public CompletionEngine(
+ ISearchableNameEnvironment nameEnvironment,
+ ICompletionRequestor requestor,
+ ConfigurableOption[] settings) {
+
+ this.requestor = requestor;
+ this.nameEnvironment = nameEnvironment;
+
+ CompilerOptions options = new CompilerOptions(settings);
+ ProblemReporter problemReporter =
+ new ProblemReporter(
+ DefaultErrorHandlingPolicies.proceedWithAllProblems(),
+ options,
+ new DefaultProblemFactory(Locale.getDefault())) {
+ public void record(IProblem problem, CompilationResult unitResult) {
+ if (problem.getID() != ProblemIrritants.UnmatchedBracket) {
+ unitResult.record(problem);
+ CompletionEngine.this.requestor.acceptError(problem);
+ }
+ }
+ };
+
+ this.parser = new CompletionParser(problemReporter);
+ this.lookupEnvironment =
+ new LookupEnvironment(this, options, problemReporter, nameEnvironment);
+ }
+
+ /**
+ * One result of the search consists of a new class.
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Nested type names are in the qualified form "A.M".
+ * The default package is represented by an empty array.
+ */
+ public void acceptClass(char[] packageName, char[] className, int modifiers) {
+ char[] completionName = CharOperation.concat(packageName, className, '.');
+ if (resolvingImports) {
+ completionName = CharOperation.concat(completionName, new char[] { ';' });
+ } else
+ if (!insideQualifiedReference) {
+ if (mustQualifyType(CharOperation.splitOn('.', packageName), completionName)) {
+ if (packageName == null || packageName.length == 0)
+ if (unitScope != null && unitScope.fPackage.compoundName != NoCharChar)
+ return; // ignore types from the default package from outside it
+ } else {
+ completionName = className;
+ }
+ }
+
+ requestor.acceptClass(
+ packageName,
+ className,
+ completionName,
+ modifiers,
+ startPosition,
+ endPosition);
+ }
+
+ /**
+ * One result of the search consists of a new interface.
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Nested type names are in the qualified form "A.I".
+ * The default package is represented by an empty array.
+ */
+ public void acceptInterface(
+ char[] packageName,
+ char[] interfaceName,
+ int modifiers) {
+ char[] completionName = CharOperation.concat(packageName, interfaceName, '.');
+ if (resolvingImports) {
+ completionName = CharOperation.concat(completionName, new char[] { ';' });
+ } else
+ if (!insideQualifiedReference) {
+ if (mustQualifyType(CharOperation.splitOn('.', packageName), completionName)) {
+ if (packageName == null || packageName.length == 0)
+ if (unitScope != null && unitScope.fPackage.compoundName != NoCharChar)
+ return; // ignore types from the default package from outside it
+ } else {
+ completionName = interfaceName;
+ }
+ }
+
+ requestor.acceptInterface(
+ packageName,
+ interfaceName,
+ completionName,
+ modifiers,
+ startPosition,
+ endPosition);
+ }
+
+ /**
+ * One result of the search consists of a new package.
+ *
+ * NOTE - All package names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * The default package is represented by an empty array.
+ */
+ public void acceptPackage(char[] packageName) {
+ if (this.knownPkgs.containsKey(packageName))
+ return;
+ this.knownPkgs.put(packageName, this);
+ requestor.acceptPackage(
+ packageName,
+ resolvingImports
+ ? CharOperation.concat(packageName, new char[] { '.', '*', ';' })
+ : packageName,
+ startPosition,
+ endPosition);
+ }
+
+ /**
+ * One result of the search consists of a new type.
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Nested type names are in the qualified form "A.M".
+ * The default package is represented by an empty array.
+ */
+ public void acceptType(char[] packageName, char[] typeName) {
+ char[] completionName = CharOperation.concat(packageName, typeName, '.');
+ if (resolvingImports) {
+ completionName = CharOperation.concat(completionName, new char[] { ';' });
+ } else
+ if (!insideQualifiedReference) {
+ if (mustQualifyType(CharOperation.splitOn('.', packageName), completionName)) {
+ if (packageName == null || packageName.length == 0)
+ if (unitScope != null && unitScope.fPackage.compoundName != NoCharChar)
+ return; // ignore types from the default package from outside it
+ } else {
+ completionName = typeName;
+ }
+ }
+
+ requestor.acceptType(
+ packageName,
+ typeName,
+ completionName,
+ startPosition,
+ endPosition);
+ }
+
+ private void complete(AstNode astNode, Binding qualifiedBinding, Scope scope) {
+ setSourceRange(astNode.sourceStart, astNode.sourceEnd);
+ // defaults... some nodes will change these
+
+ if (astNode instanceof CompletionOnFieldType) {
+ CompletionOnSingleTypeReference type =
+ (CompletionOnSingleTypeReference) ((CompletionOnFieldType) astNode).type;
+ char[] token = type.token;
+ setSourceRange(type.sourceStart, type.sourceEnd);
+ // findKeywords(token, modifiers, scope); // could be the start of a field, method or member type
+ findTypesAndPackages(token, scope);
+ } else
+ if (astNode instanceof CompletionOnSingleNameReference) {
+ char[] token = ((CompletionOnSingleNameReference) astNode).token;
+ findVariablesAndMethods(token, scope);
+ findTypesAndPackages(token, scope);
+ // can be the start of a qualified type name
+ } else
+ if (astNode instanceof CompletionOnSingleTypeReference) {
+ char[] token = ((CompletionOnSingleTypeReference) astNode).token;
+ if (qualifiedBinding == null)
+ findTypesAndPackages(token, scope);
+ // can be the start of a qualified type name
+ else
+ findMemberTypes(token, (ReferenceBinding) qualifiedBinding, scope);
+ } else
+ if (astNode instanceof CompletionOnQualifiedNameReference) {
+ insideQualifiedReference = true;
+ CompletionOnQualifiedNameReference ref =
+ (CompletionOnQualifiedNameReference) astNode;
+ char[] token = ref.completionIdentifier;
+ long completionPosition = ref.sourcePositions[ref.sourcePositions.length - 1];
+ if (qualifiedBinding instanceof VariableBinding) {
+ setSourceRange((int) (completionPosition >>> 32), (int) completionPosition);
+ TypeBinding receiverType = ((VariableBinding) qualifiedBinding).type;
+ if (receiverType != null)
+ findFieldsAndMethods(token, receiverType, scope);
+ } else
+ if (qualifiedBinding instanceof ReferenceBinding) {
+ ReferenceBinding receiverType = (ReferenceBinding) qualifiedBinding;
+ setSourceRange((int) (completionPosition >>> 32), (int) completionPosition);
+ findMemberTypes(token, receiverType, scope);
+ findClassField(token, (TypeBinding) qualifiedBinding);
+ findFields(token, receiverType, scope, new ObjectVector(), true);
+ findMethods(token, null, receiverType, scope, new ObjectVector(), true, false);
+ } else
+ if (qualifiedBinding instanceof PackageBinding) {
+ setSourceRange(astNode.sourceStart, (int) completionPosition);
+ // replace to the end of the completion identifier
+ findTypesAndSubpackages(token, (PackageBinding) qualifiedBinding);
+ }
+ } else
+ if (astNode instanceof CompletionOnQualifiedTypeReference) {
+ insideQualifiedReference = true;
+ CompletionOnQualifiedTypeReference ref =
+ (CompletionOnQualifiedTypeReference) astNode;
+ char[] token = ref.completionIdentifier;
+ long completionPosition = ref.sourcePositions[ref.tokens.length];
+ // get the source positions of the completion identifier
+ if (qualifiedBinding instanceof ReferenceBinding) {
+ setSourceRange((int) (completionPosition >>> 32), (int) completionPosition);
+ findMemberTypes(token, (ReferenceBinding) qualifiedBinding, scope);
+ } else
+ if (qualifiedBinding instanceof PackageBinding) {
+ setSourceRange(astNode.sourceStart, (int) completionPosition);
+ // replace to the end of the completion identifier
+ findTypesAndSubpackages(token, (PackageBinding) qualifiedBinding);
+ }
+ } else
+ if (astNode instanceof CompletionOnMemberAccess) {
+ CompletionOnMemberAccess access = (CompletionOnMemberAccess) astNode;
+ long completionPosition = access.nameSourcePosition;
+ setSourceRange((int) (completionPosition >>> 32), (int) completionPosition);
+ findFieldsAndMethods(access.token, (TypeBinding) qualifiedBinding, scope);
+ } else
+ if (astNode instanceof CompletionOnMessageSend) {
+ CompletionOnMessageSend messageSend = (CompletionOnMessageSend) astNode;
+ TypeBinding[] argTypes =
+ computeTypes(messageSend.arguments, (BlockScope) scope);
+ if (qualifiedBinding == null)
+ findMessageSends(messageSend.selector, argTypes, scope);
+ else
+ findMethods(
+ messageSend.selector,
+ argTypes,
+ (ReferenceBinding) qualifiedBinding,
+ scope,
+ new ObjectVector(),
+ false,
+ true);
+ } else
+ if (astNode instanceof CompletionOnExplicitConstructorCall) {
+ CompletionOnExplicitConstructorCall constructorCall =
+ (CompletionOnExplicitConstructorCall) astNode;
+ TypeBinding[] argTypes =
+ computeTypes(constructorCall.arguments, (BlockScope) scope);
+ findConstructors((ReferenceBinding) qualifiedBinding, argTypes, scope);
+ } else
+ if (astNode instanceof CompletionOnQualifiedAllocationExpression) {
+ CompletionOnQualifiedAllocationExpression allocExpression =
+ (CompletionOnQualifiedAllocationExpression) astNode;
+ TypeBinding[] argTypes =
+ computeTypes(allocExpression.arguments, (BlockScope) scope);
+ findConstructors((ReferenceBinding) qualifiedBinding, argTypes, scope);
+ } else
+ if (astNode instanceof CompletionOnClassLiteralAccess) {
+ char[] token = ((CompletionOnClassLiteralAccess) astNode).completionIdentifier;
+ findClassField(token, (TypeBinding) qualifiedBinding);
+ }
+ }
+
+ /**
+ * Ask the engine to compute a completion at the specified position
+ * of the given compilation unit.
+ *
+ * @return void
+ * completion results are answered through a requestor.
+ *
+ * @param unit com.ibm.compiler.java.api.env.ICompilationUnit
+ * the source of the current compilation unit.
+ *
+ * @param completionPosition int
+ * a position in the source where the completion is taking place.
+ * This position is relative to the source provided.
+ */
+ public void complete(ICompilationUnit sourceUnit, int completionPosition) {
+ try {
+ int actualCompletionPosition = completionPosition - 1;
+ // for now until we can change the UI.
+ CompilationResult result = new CompilationResult(sourceUnit, 1, 1);
+ CompilationUnitDeclaration parsedUnit =
+ parser.dietParse(sourceUnit, result, actualCompletionPosition);
+
+ // boolean completionNodeFound = false;
+ if (parsedUnit != null) {
+ // scan the package & import statements first
+ if (parsedUnit.currentPackage instanceof CompletionOnPackageReference) {
+ findPackages((CompletionOnPackageReference) parsedUnit.currentPackage);
+ return;
+ }
+ ImportReference[] imports = parsedUnit.imports;
+ if (imports != null) {
+ for (int i = 0, length = imports.length; i < length; i++) {
+ ImportReference importReference = imports[i];
+ if (importReference instanceof CompletionOnImportReference) {
+ findImports((CompletionOnImportReference) importReference);
+ return;
+ }
+ }
+ }
+
+ if (parsedUnit.types != null) {
+ try {
+ lookupEnvironment.buildTypeBindings(parsedUnit);
+ if ((unitScope = parsedUnit.scope) != null) {
+ source = sourceUnit.getContents();
+ lookupEnvironment.completeTypeBindings(parsedUnit, true);
+ parsedUnit.scope.faultInTypes();
+ parseMethod(parsedUnit, actualCompletionPosition);
+ parsedUnit.resolve();
+ }
+ } catch (CompletionNodeFound e) {
+ // completionNodeFound = true;
+ if (e.astNode != null)
+ // if null then we found a problem in the completion node
+ complete(e.astNode, e.qualifiedBinding, e.scope);
+ }
+ }
+ }
+
+ /* Ignore package, import, class & interface keywords for now...
+ if (!completionNodeFound) {
+ if (parsedUnit == null || parsedUnit.types == null) {
+ // this is not good enough... can still be trying to define a second type
+ CompletionScanner scanner = (CompletionScanner) parser.scanner;
+ setSourceRange(scanner.completedIdentifierStart, scanner.completedIdentifierEnd);
+ findKeywords(scanner.completionIdentifier, mainDeclarations, null);
+ }
+ // currently have no way to know if extends/implements are possible keywords
+ }
+ */
+ } catch (IndexOutOfBoundsException e) { // work-around internal failure - 1GEMF6D
+ } catch (InvalidCursorLocation e) { // may eventually report a usefull error
+ } catch (AbortCompilation e) { // ignore this exception for now since it typically means we cannot find java.lang.Object
+ } finally {
+ reset();
+ }
+ }
+
+ private TypeBinding[] computeTypes(Expression[] arguments, BlockScope scope) {
+ if (arguments == null)
+ return null;
+
+ int argsLength = arguments.length;
+ TypeBinding[] argTypes = new TypeBinding[argsLength];
+ for (int a = argsLength; --a >= 0;)
+ argTypes[a] = arguments[a].resolveType(scope);
+ return argTypes;
+ }
+
+ private void findClassField(char[] token, TypeBinding receiverType) {
+ if (token == null)
+ return;
+
+ if (token.length <= classField.length
+ && CharOperation.prefixEquals(token, classField, false /* ignore case */
+ ))
+ requestor.acceptField(
+ NoChar,
+ NoChar,
+ classField,
+ NoChar,
+ NoChar,
+ classField,
+ CompilerModifiers.AccStatic | CompilerModifiers.AccPublic,
+ startPosition,
+ endPosition);
+ }
+
+ private void findConstructors(
+ ReferenceBinding currentType,
+ TypeBinding[] argTypes,
+ Scope scope) {
+ // No visibility checks can be performed without the scope & invocationSite
+ MethodBinding[] methods = currentType.methods();
+ int minArgLength = argTypes == null ? 0 : argTypes.length;
+ next : for (int f = methods.length; --f >= 0;) {
+ MethodBinding constructor = methods[f];
+ if (constructor.isConstructor()) {
+ TypeBinding[] parameters = constructor.parameters;
+ int paramLength = parameters.length;
+ if (minArgLength > paramLength)
+ continue next;
+ for (int a = minArgLength; --a >= 0;)
+ if (argTypes[a] != null) // can be null if it could not be resolved properly
+ if (!scope.areTypesCompatible(argTypes[a], constructor.parameters[a]))
+ continue next;
+
+ char[][] parameterPackageNames = new char[paramLength][];
+ char[][] parameterTypeNames = new char[paramLength][];
+ for (int i = 0; i < paramLength; i++) {
+ TypeBinding type = parameters[i];
+ parameterPackageNames[i] = type.qualifiedPackageName();
+ parameterTypeNames[i] = type.qualifiedSourceName();
+ }
+ char[] completion = TypeConstants.NoChar;
+ // nothing to insert - do not want to replace the existing selector & arguments
+ if (source == null
+ || source.length <= endPosition
+ || source[endPosition] != ')')
+ completion = new char[] { ')' };
+ requestor.acceptMethod(
+ currentType.qualifiedPackageName(),
+ currentType.qualifiedSourceName(),
+ currentType.sourceName(),
+ parameterPackageNames,
+ parameterTypeNames,
+ TypeConstants.NoChar,
+ TypeConstants.NoChar,
+ completion,
+ constructor.modifiers,
+ endPosition,
+ endPosition);
+ }
+ }
+ }
+
+ // Helper method for findFields(char[], ReferenceBinding, Scope, ObjectVector, boolean)
+
+ private void findFields(
+ char[] fieldName,
+ FieldBinding[] fields,
+ Scope scope,
+ ObjectVector fieldsFound,
+ boolean onlyStaticFields) {
+
+ // Inherited fields which are hidden by subclasses are filtered out
+ // No visibility checks can be performed without the scope & invocationSite
+
+ int fieldLength = fieldName.length;
+ next : for (int f = fields.length; --f >= 0;) {
+ FieldBinding field = fields[f];
+ if (onlyStaticFields && !field.isStatic())
+ continue next;
+ if (fieldLength > field.name.length)
+ continue next;
+ if (!CharOperation.prefixEquals(fieldName, field.name, false /* ignore case */
+ ))
+ continue next;
+
+ for (int i = fieldsFound.size; --i >= 0;) {
+ FieldBinding otherField = (FieldBinding) fieldsFound.elementAt(i);
+ if (field == otherField)
+ continue next;
+ if (CharOperation.equals(field.name, otherField.name, true)) {
+ if (field.declaringClass.isSuperclassOf(otherField.declaringClass))
+ continue next;
+ if (otherField.declaringClass.isInterface())
+ if (field.declaringClass.implementsInterface(otherField.declaringClass, true))
+ continue next;
+ }
+ }
+
+ fieldsFound.add(field);
+ requestor
+ .acceptField(
+ field.declaringClass.qualifiedPackageName(),
+ field.declaringClass.qualifiedSourceName(),
+ field.name,
+ field.type.qualifiedPackageName(),
+ field.type.qualifiedSourceName(),
+ field.name,
+ // may include some qualification to resolve ambiguities
+ field.modifiers, startPosition, endPosition);
+ }
+ }
+
+ private void findFields(
+ char[] fieldName,
+ ReferenceBinding receiverType,
+ Scope scope,
+ ObjectVector fieldsFound,
+ boolean onlyStaticFields) {
+
+ if (fieldName == null)
+ return;
+
+ ReferenceBinding currentType = receiverType;
+ ReferenceBinding[][] interfacesToVisit = null;
+ int lastPosition = -1;
+ do {
+ ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (interfacesToVisit == null)
+ interfacesToVisit = new ReferenceBinding[5][];
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(
+ interfacesToVisit,
+ 0,
+ interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
+ 0,
+ lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+
+ findFields(
+ fieldName,
+ currentType.fields(),
+ scope,
+ fieldsFound,
+ onlyStaticFields);
+ currentType = currentType.superclass();
+ } while (currentType != null);
+
+ if (interfacesToVisit != null) {
+ for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++) {
+ ReferenceBinding anInterface = interfaces[j];
+ if ((anInterface.tagBits & TagBits.InterfaceVisited) == 0) {
+ // if interface as not already been visited
+ anInterface.tagBits |= TagBits.InterfaceVisited;
+
+ findFields(
+ fieldName,
+ anInterface.fields(),
+ scope,
+ fieldsFound,
+ onlyStaticFields);
+
+ ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(
+ interfacesToVisit,
+ 0,
+ interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
+ 0,
+ lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+ }
+ }
+ }
+
+ // bit reinitialization
+ for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++)
+ interfaces[j].tagBits &= ~TagBits.InterfaceVisited;
+ }
+ }
+ }
+
+ private void findFieldsAndMethods(
+ char[] token,
+ TypeBinding receiverType,
+ Scope scope) {
+ if (token == null)
+ return;
+
+ if (receiverType.isBaseType())
+ return; // nothing else is possible with base types
+ if (receiverType.isArrayType()) {
+ if (token.length <= lengthField.length
+ && CharOperation.prefixEquals(token, lengthField, false /* ignore case */
+ ))
+ requestor.acceptField(
+ NoChar,
+ NoChar,
+ lengthField,
+ NoChar,
+ NoChar,
+ lengthField,
+ CompilerModifiers.AccPublic,
+ startPosition,
+ endPosition);
+
+ receiverType = scope.getJavaLangObject();
+ }
+
+ findFields(
+ token,
+ (ReferenceBinding) receiverType,
+ scope,
+ new ObjectVector(),
+ false);
+ findMethods(
+ token,
+ null,
+ (ReferenceBinding) receiverType,
+ scope,
+ new ObjectVector(),
+ false,
+ false);
+ }
+
+ private void findImports(CompletionOnImportReference importReference) {
+ char[] importName = CharOperation.concatWith(importReference.tokens, '.');
+ if (importName.length == 0)
+ return;
+ resolvingImports = true;
+ setSourceRange(
+ importReference.sourceStart,
+ importReference.declarationSourceEnd);
+ // want to replace the existing .*;
+ nameEnvironment.findPackages(importName, this);
+ nameEnvironment.findTypes(importName, this);
+ }
+
+ // what about onDemand types? Ignore them since it does not happen!
+ // import p1.p2.A.*;
+ private void findKeywords(char[] keyword, char[][] choices, Scope scope) {
+ int length = keyword.length;
+ if (length > 0)
+ for (int i = 0; i < choices.length; i++)
+ if (length <= choices[i].length
+ && CharOperation.prefixEquals(keyword, choices[i], false /* ignore case */
+ ))
+ requestor.acceptKeyword(choices[i], startPosition, endPosition);
+ }
+
+ // Helper method for findMemberTypes(char[], ReferenceBinding, Scope)
+
+ private void findMemberTypes(
+ char[] typeName,
+ ReferenceBinding[] memberTypes,
+ ObjectVector typesFound) {
+
+ // Inherited member types which are hidden by subclasses are filtered out
+ // No visibility checks can be performed without the scope & invocationSite
+
+ int typeLength = typeName.length;
+ next : for (int m = memberTypes.length; --m >= 0;) {
+ ReferenceBinding memberType = memberTypes[m];
+ // if (!wantClasses && memberType.isClass()) continue next;
+ // if (!wantInterfaces && memberType.isInterface()) continue next;
+ if (typeLength > memberType.sourceName.length)
+ continue next;
+ if (!CharOperation.prefixEquals(typeName, memberType.sourceName, false
+ /* ignore case */
+ ))
+ continue next;
+
+ for (int i = typesFound.size; --i >= 0;) {
+ ReferenceBinding otherType = (ReferenceBinding) typesFound.elementAt(i);
+ if (memberType == otherType)
+ continue next;
+ if (CharOperation.equals(memberType.sourceName, otherType.sourceName, true)) {
+ if (memberType.enclosingType().isSuperclassOf(otherType.enclosingType()))
+ continue next;
+ if (otherType.enclosingType().isInterface())
+ if (memberType
+ .enclosingType()
+ .implementsInterface(otherType.enclosingType(), true))
+ continue next;
+ }
+ }
+
+ typesFound.add(memberType);
+ if (memberType.isClass())
+ requestor.acceptClass(
+ memberType.qualifiedPackageName(),
+ memberType.qualifiedSourceName(),
+ memberType.sourceName(),
+ memberType.modifiers,
+ startPosition,
+ endPosition);
+ else
+ requestor.acceptInterface(
+ memberType.qualifiedPackageName(),
+ memberType.qualifiedSourceName(),
+ memberType.sourceName(),
+ memberType.modifiers,
+ startPosition,
+ endPosition);
+ }
+ }
+
+ private void findMemberTypes(
+ char[] typeName,
+ ReferenceBinding currentType,
+ Scope scope) {
+ if (typeName == null)
+ return;
+ if (currentType.superInterfaces() == null)
+ return; // we're trying to find a supertype
+
+ ObjectVector typesFound = new ObjectVector();
+ if (insideQualifiedReference
+ || typeName.length == 0) { // do not search up the hierarchy
+ findMemberTypes(typeName, currentType.memberTypes(), typesFound);
+ return;
+ }
+
+ ReferenceBinding[][] interfacesToVisit = null;
+ int lastPosition = -1;
+ do {
+ ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (interfacesToVisit == null)
+ interfacesToVisit = new ReferenceBinding[5][];
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(
+ interfacesToVisit,
+ 0,
+ interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
+ 0,
+ lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+
+ findMemberTypes(typeName, currentType.memberTypes(), typesFound);
+ currentType = currentType.superclass();
+ } while (currentType != null);
+
+ if (interfacesToVisit != null) {
+ for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++) {
+ ReferenceBinding anInterface = interfaces[j];
+ if ((anInterface.tagBits & TagBits.InterfaceVisited) == 0) {
+ // if interface as not already been visited
+ anInterface.tagBits |= TagBits.InterfaceVisited;
+
+ findMemberTypes(typeName, anInterface.memberTypes(), typesFound);
+
+ ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(
+ interfacesToVisit,
+ 0,
+ interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
+ 0,
+ lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+ }
+ }
+ }
+
+ // bit reinitialization
+ for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++)
+ interfaces[j].tagBits &= ~TagBits.InterfaceVisited;
+ }
+ }
+ }
+
+ private void findMessageSends(
+ char[] token,
+ TypeBinding[] argTypes,
+ Scope scope) {
+ if (token == null)
+ return;
+
+ boolean staticsOnly = false;
+ // need to know if we're in a static context (or inside a constructor)
+ int tokenLength = token.length;
+ ObjectVector methodsFound = new ObjectVector();
+ done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found
+ switch (scope.kind) {
+ case Scope.METHOD_SCOPE :
+ // handle the error case inside an explicit constructor call (see MethodScope>>findField)
+ MethodScope methodScope = (MethodScope) scope;
+ staticsOnly |= methodScope.isStatic | methodScope.isConstructorCall;
+ break;
+ case Scope.CLASS_SCOPE :
+ ClassScope classScope = (ClassScope) scope;
+ SourceTypeBinding enclosingType = classScope.referenceContext.binding;
+ findMethods(
+ token,
+ argTypes,
+ enclosingType,
+ classScope,
+ methodsFound,
+ staticsOnly,
+ true);
+ staticsOnly |= enclosingType.isStatic();
+ break;
+ case Scope.COMPILATION_UNIT_SCOPE :
+ break done;
+ }
+ scope = scope.parent;
+ }
+ }
+
+ // Helper method for findMethods(char[], TypeBinding[], ReferenceBinding, Scope, ObjectVector, boolean, boolean)
+
+ private void findMethods(
+ char[] methodName,
+ TypeBinding[] argTypes,
+ MethodBinding[] methods,
+ Scope scope,
+ ObjectVector methodsFound,
+ // boolean noVoidReturnType, how do you know?
+ boolean onlyStaticMethods, boolean exactMatch) {
+
+ // Inherited methods which are hidden by subclasses are filtered out
+ // No visibility checks can be performed without the scope & invocationSite
+
+ int methodLength = methodName.length;
+ int minArgLength = argTypes == null ? 0 : argTypes.length;
+ next : for (int f = methods.length; --f >= 0;) {
+ MethodBinding method = methods[f];
+ if (method.isConstructor())
+ continue next;
+ // if (noVoidReturnType && method.returnType == BaseTypes.VoidBinding) continue next;
+ if (onlyStaticMethods && !method.isStatic())
+ continue next;
+ if (exactMatch) {
+ if (!CharOperation.equals(methodName, method.selector, false /* ignore case */
+ ))
+ continue next;
+ } else {
+ if (methodLength > method.selector.length)
+ continue next;
+ if (!CharOperation.prefixEquals(methodName, method.selector, false
+ /* ignore case */
+ ))
+ continue next;
+ }
+ if (minArgLength > method.parameters.length)
+ continue next;
+ for (int a = minArgLength; --a >= 0;)
+ if (argTypes[a] != null) // can be null if it could not be resolved properly
+ if (!scope.areTypesCompatible(argTypes[a], method.parameters[a]))
+ continue next;
+
+ for (int i = methodsFound.size; --i >= 0;) {
+ MethodBinding otherMethod = (MethodBinding) methodsFound.elementAt(i);
+ if (method == otherMethod)
+ continue next;
+ if (CharOperation.equals(method.selector, otherMethod.selector, true)
+ && method.areParametersEqual(otherMethod)) {
+ if (method.declaringClass.isSuperclassOf(otherMethod.declaringClass))
+ continue next;
+ if (otherMethod.declaringClass.isInterface())
+ if (method
+ .declaringClass
+ .implementsInterface(otherMethod.declaringClass, true))
+ continue next;
+ }
+ }
+
+ methodsFound.add(method);
+ int length = method.parameters.length;
+ char[][] parameterPackageNames = new char[length][];
+ char[][] parameterTypeNames = new char[length][];
+ for (int i = 0; i < length; i++) {
+ TypeBinding type = method.parameters[i];
+ parameterPackageNames[i] = type.qualifiedPackageName();
+ parameterTypeNames[i] = type.qualifiedSourceName();
+ }
+ char[] completion = TypeConstants.NoChar;
+ // nothing to insert - do not want to replace the existing selector & arguments
+ if (!exactMatch) {
+ if (source != null
+ && source.length > endPosition
+ && source[endPosition] == '(')
+ completion = method.selector;
+ else
+ completion = CharOperation.concat(method.selector, new char[] { '(', ')' });
+ }
+ requestor.acceptMethod(
+ method.declaringClass.qualifiedPackageName(),
+ method.declaringClass.qualifiedSourceName(),
+ method.selector,
+ parameterPackageNames,
+ parameterTypeNames,
+ method.returnType.qualifiedPackageName(),
+ method.returnType.qualifiedSourceName(),
+ completion,
+ method.modifiers,
+ startPosition,
+ endPosition);
+ }
+ }
+
+ private void findMethods(
+ char[] selector,
+ TypeBinding[] argTypes,
+ ReferenceBinding receiverType,
+ Scope scope,
+ ObjectVector methodsFound,
+ boolean onlyStaticMethods,
+ boolean exactMatch) {
+
+ if (selector == null)
+ return;
+
+ ReferenceBinding currentType = receiverType;
+ if (currentType.isInterface()) {
+ findMethods(
+ selector,
+ argTypes,
+ currentType.methods(),
+ scope,
+ methodsFound,
+ onlyStaticMethods,
+ exactMatch);
+
+ ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][];
+ int lastPosition = 0;
+ interfacesToVisit[lastPosition] = itsInterfaces;
+
+ for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++) {
+ currentType = interfaces[j];
+ if ((currentType.tagBits & TagBits.InterfaceVisited) == 0) {
+ // if interface as not already been visited
+ currentType.tagBits |= TagBits.InterfaceVisited;
+
+ findMethods(
+ selector,
+ argTypes,
+ currentType.methods(),
+ scope,
+ methodsFound,
+ onlyStaticMethods,
+ exactMatch);
+
+ itsInterfaces = currentType.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(
+ interfacesToVisit,
+ 0,
+ interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
+ 0,
+ lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+ }
+ }
+ }
+
+ // bit reinitialization
+ for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++)
+ interfaces[j].tagBits &= ~TagBits.InterfaceVisited;
+ }
+ }
+ currentType = scope.getJavaLangObject();
+ }
+
+ while (currentType != null) {
+ findMethods(
+ selector,
+ argTypes,
+ currentType.methods(),
+ scope,
+ methodsFound,
+ onlyStaticMethods,
+ exactMatch);
+ currentType = currentType.superclass();
+ }
+ }
+
+ private void findNestedTypes(
+ char[] typeName,
+ ReferenceBinding currentType,
+ Scope scope) {
+ if (typeName == null)
+ return;
+
+ int typeLength = typeName.length;
+ while (scope != null) { // done when a COMPILATION_UNIT_SCOPE is found
+ switch (scope.kind) {
+ case Scope.METHOD_SCOPE :
+ case Scope.BLOCK_SCOPE :
+ BlockScope blockScope = (BlockScope) scope;
+ next : for (int i = 0, length = blockScope.scopeIndex; i < length; i++) {
+ if (blockScope.subscopes[i] instanceof ClassScope) {
+ SourceTypeBinding localType =
+ ((ClassScope) blockScope.subscopes[i]).referenceContext.binding;
+ if (!localType.isAnonymousType()) {
+ if (typeLength > localType.sourceName.length)
+ continue next;
+ if (!CharOperation.prefixEquals(typeName, localType.sourceName, false
+ /* ignore case */
+ ))
+ continue next;
+
+ requestor.acceptClass(
+ localType.qualifiedPackageName(),
+ localType.sourceName,
+ localType.sourceName,
+ localType.modifiers,
+ startPosition,
+ endPosition);
+ }
+ }
+ }
+ break;
+ case Scope.CLASS_SCOPE :
+ findMemberTypes(typeName, scope.enclosingSourceType(), scope);
+ if (typeLength == 0)
+ return; // do not search outside the class scope if no prefix was provided
+ break;
+ case Scope.COMPILATION_UNIT_SCOPE :
+ return;
+ }
+ scope = scope.parent;
+ }
+ }
+
+ private void findPackages(CompletionOnPackageReference packageStatement) {
+ char[] packageName = CharOperation.concatWith(packageStatement.tokens, '.');
+ if (packageName.length == 0)
+ return;
+
+ setSourceRange(packageStatement.sourceStart, packageStatement.sourceEnd);
+ nameEnvironment.findPackages(CharOperation.toLowerCase(packageName), this);
+ }
+
+ private void findTypesAndPackages(char[] token, Scope scope) {
+ if (token == null)
+ return;
+
+ if (scope.enclosingSourceType() != null)
+ findNestedTypes(token, scope.enclosingSourceType(), scope);
+
+ if (unitScope != null) {
+ int typeLength = token.length;
+ SourceTypeBinding[] types = unitScope.topLevelTypes;
+ for (int i = 0, length = types.length; i < length; i++) {
+ SourceTypeBinding sourceType = types[i];
+ if (typeLength > sourceType.sourceName.length)
+ continue;
+ if (!CharOperation.prefixEquals(token, sourceType.sourceName, false
+ /* ignore case */
+ ))
+ continue;
+
+ requestor.acceptType(
+ sourceType.qualifiedPackageName(),
+ sourceType.sourceName(),
+ sourceType.sourceName(),
+ startPosition,
+ endPosition);
+ }
+ }
+
+ if (token.length == 0)
+ return;
+ findKeywords(token, baseTypes, scope);
+ nameEnvironment.findTypes(token, this);
+ nameEnvironment.findPackages(token, this);
+ }
+
+ private void findTypesAndSubpackages(
+ char[] token,
+ PackageBinding packageBinding) {
+ char[] qualifiedName =
+ CharOperation.concatWith(packageBinding.compoundName, token, '.');
+ if (token == null || token.length == 0) {
+ int length = qualifiedName.length;
+ System.arraycopy(
+ qualifiedName,
+ 0,
+ qualifiedName = new char[length + 1],
+ 0,
+ length);
+ qualifiedName[length] = '.';
+ }
+ nameEnvironment.findTypes(qualifiedName, this);
+ nameEnvironment.findPackages(qualifiedName, this);
+ }
+
+ private void findVariablesAndMethods(char[] token, Scope scope) {
+ if (token == null)
+ return;
+
+ // Should local variables hide fields from the receiver type or any of its enclosing types?
+ // we know its an implicit field/method access... see BlockScope getBinding/getImplicitMethod
+
+ boolean staticsOnly = false;
+ // need to know if we're in a static context (or inside a constructor)
+ char[][] found = null;
+ int lastPosition = -1;
+ int tokenLength = token.length;
+ ObjectVector fieldsFound = new ObjectVector();
+ ObjectVector methodsFound = new ObjectVector();
+ done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found
+ switch (scope.kind) {
+ case Scope.METHOD_SCOPE :
+ // handle the error case inside an explicit constructor call (see MethodScope>>findField)
+ MethodScope methodScope = (MethodScope) scope;
+ staticsOnly |= methodScope.isStatic | methodScope.isConstructorCall;
+ case Scope.BLOCK_SCOPE :
+ BlockScope blockScope = (BlockScope) scope;
+ next : for (int i = 0, length = blockScope.locals.length; i < length; i++) {
+ LocalVariableBinding local = blockScope.locals[i];
+ if (local == null)
+ break next;
+ if (tokenLength > local.name.length)
+ continue next;
+ if (!CharOperation.prefixEquals(token, local.name, false /* ignore case */
+ ))
+ continue next;
+ if (local.isSecret())
+ continue next;
+
+ if (found == null) {
+ found = new char[5][];
+ } else {
+ for (int f = 0; f < found.length; f++) {
+ char[] name = found[f];
+ if (name == null)
+ break;
+ if (CharOperation.equals(name, local.name, false /* ignore case */
+ ))
+ continue next;
+ }
+ }
+ if (++lastPosition == found.length)
+ System.arraycopy(
+ found,
+ 0,
+ found = new char[lastPosition * 2][],
+ 0,
+ lastPosition);
+ found[lastPosition] = local.name;
+
+ requestor.acceptLocalVariable(
+ local.name,
+ NoChar,
+ local.type == null
+ ? local.declaration.type.toString().toCharArray()
+ : local.type.qualifiedSourceName(),
+ local.modifiers,
+ startPosition,
+ endPosition);
+ }
+ break;
+ case Scope.CLASS_SCOPE :
+ ClassScope classScope = (ClassScope) scope;
+ SourceTypeBinding enclosingType = classScope.referenceContext.binding;
+ /* if (tokenLength == 0) { // only search inside the type itself if no prefix was provided
+ findFields(token, enclosingType.fields(), classScope, fieldsFound, staticsOnly);
+ findMethods(token, enclosingType.methods(), classScope, methodsFound, staticsOnly, false);
+ break done;
+ } else { */
+ findFields(token, enclosingType, classScope, fieldsFound, staticsOnly);
+ findMethods(
+ token,
+ null,
+ enclosingType,
+ classScope,
+ methodsFound,
+ staticsOnly,
+ false);
+ staticsOnly |= enclosingType.isStatic();
+ // }
+ break;
+ case Scope.COMPILATION_UNIT_SCOPE :
+ break done;
+ }
+ scope = scope.parent;
+ }
+ }
+
+ public AssistParser getParser() {
+ return parser;
+ }
+
+ private boolean mustQualifyType(
+ char[][] packageName,
+ char[] readableTypeName) {
+ // If there are no types defined into the current CU yet.
+ if (unitScope == null)
+ return true;
+ if (CharOperation.equals(unitScope.fPackage.compoundName, packageName))
+ return false;
+
+ ImportBinding[] imports = unitScope.imports;
+ for (int i = 0, length = imports.length; i < length; i++) {
+ if (imports[i].onDemand) {
+ if (CharOperation.equals(imports[i].compoundName, packageName))
+ return false; // how do you match p1.p2.A.* ?
+ } else
+ if (CharOperation.equals(imports[i].readableName(), readableTypeName)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ protected void reset() {
+ super.reset();
+ this.knownPkgs = new HashtableOfObject(10);
+ }
+
+ private void setSourceRange(int start, int end) {
+ this.startPosition = start;
+ this.endPosition = end + 1; // Add 1 for now
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ICompletionRequestor.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ICompletionRequestor.java
new file mode 100644
index 0000000000..3cd745d516
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ICompletionRequestor.java
@@ -0,0 +1,261 @@
+package org.eclipse.jdt.internal.codeassist;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/**
+ * A completion requestor accepts results as they are computed and is aware
+ * of source positions to complete the various different results.
+ */
+
+import org.eclipse.jdt.internal.compiler.*;
+
+public interface ICompletionRequestor {
+ /**
+ * Code assist notification of a class completion.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param packageName char[] - Declaring package name of the class.
+ * @param className char[] - Name of the class.
+ * @param completionName char[] - The completion for the class.
+ * Can include ';' for imported classes.
+ * @param modifiers int - The modifiers of the class.
+ * @see com.ibm.compiler.java.ast.Modifiers
+ * @param completionStart int - The start position of insertion of the name of the class.
+ * @param completionEnd int - The end position of insertion of the name of the class.
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Nested type names are in the qualified form "A.M".
+ * The default package is represented by an empty array.
+ */
+ void acceptClass(
+ char[] packageName,
+ char[] className,
+ char[] completionName,
+ int modifiers,
+ int completionStart,
+ int completionEnd);
+ /**
+ * Code assist notification of a compilation error detected during completion.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param error com.ibm.compiler.java.api.problem.IProblem
+ * Only problems which are categorized as errors are notified to the requestor,
+ * warnings are silently ignored.
+ * In case an error got signaled, no other completions might be available,
+ * therefore the problem message should be presented to the user.
+ * The source positions of the problem are related to the source where it was
+ * detected (might be in another compilation unit, if it was indirectly requested
+ * during the code assist process).
+ * Note: the problem knows its originating file name.
+ */
+ void acceptError(IProblem error);
+ /**
+ * Code assist notification of a field completion.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param declaringTypePackageName char[] - Name of the package in which the type that contains this field is declared.
+ * @param declaringTypeName char[] - Name of the type declaring this new field.
+ * @param name char[] - Name of the field.
+ * @param typePackageName char[] - Name of the package in which the type of this field is declared.
+ * @param typeName char[] - Name of the type of this field.
+ * @param completionName char[] - The completion for the field.
+ * @param modifiers int - The modifiers of this field.
+ * @param completionStart int - The start position of insertion of the name of this field.
+ * @param completionEnd int - The end position of insertion of the name of this field.
+ * @see com.ibm.compiler.java.ast.Modifiers
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Base types are in the form "int" or "boolean".
+ * Array types are in the qualified form "M[]" or "int[]".
+ * Nested type names are in the qualified form "A.M".
+ * The default package is represented by an empty array.
+ */
+ void acceptField(
+ char[] declaringTypePackageName,
+ char[] declaringTypeName,
+ char[] name,
+ char[] typePackageName,
+ char[] typeName,
+ char[] completionName,
+ int modifiers,
+ int completionStart,
+ int completionEnd);
+ /**
+ * Code assist notification of an interface completion.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param packageName char[] - Declaring package name of the interface.
+ * @param className char[] - Name of the interface.
+ * @param completionName char[] - The completion for the interface.
+ * Can include ';' for imported interfaces.
+ * @param modifiers int - The modifiers of the interface.
+ * @see com.ibm.compiler.java.ast.Modifiers
+ * @param completionStart int - The start position of insertion of the name of the interface.
+ * @param completionEnd int - The end position of insertion of the name of the interface.
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Nested type names are in the qualified form "A.M".
+ * The default package is represented by an empty array.
+ */
+ void acceptInterface(
+ char[] packageName,
+ char[] interfaceName,
+ char[] completionName,
+ int modifiers,
+ int completionStart,
+ int completionEnd);
+ /**
+ * Code assist notification of a keyword completion.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param keywordName char[] - The keyword source.
+ * @param completionStart int - The start position of insertion of the name of this keyword.
+ * @param completionEnd int - The end position of insertion of the name of this keyword.
+ */
+ void acceptKeyword(char[] keywordName, int completionStart, int completionEnd);
+ /**
+ * Code assist notification of a label completion.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param labelName char[] - The label source.
+ * @param completionStart int - The start position of insertion of the name of this label.
+ * @param completionEnd int - The end position of insertion of the name of this label.
+ */
+ void acceptLabel(char[] labelName, int completionStart, int completionEnd);
+ /**
+ * Code assist notification of a local variable completion.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param name char[] - Name of the new local variable.
+ * @param typePackageName char[] - Name of the package in which the type of this new local variable is declared.
+ * @param typeName char[] - Name of the type of this new local variable.
+ * @param modifiers int - The modifiers of this new local variable.
+ * @param completionStart int - The start position of insertion of the name of this new local variable.
+ * @param completionEnd int - The end position of insertion of the name of this new local variable.
+ * @see com.ibm.compiler.java.ast.Modifiers
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Base types are in the form "int" or "boolean".
+ * Array types are in the qualified form "M[]" or "int[]".
+ * Nested type names are in the qualified form "A.M".
+ * The default package is represented by an empty array.
+ */
+ void acceptLocalVariable(
+ char[] name,
+ char[] typePackageName,
+ char[] typeName,
+ int modifiers,
+ int completionStart,
+ int completionEnd);
+ /**
+ * Code assist notification of a method completion.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param declaringTypePackageName char[] - Name of the package in which the type that contains this new method is declared.
+ * @param declaringTypeName char[] - Name of the type declaring this new method.
+ * @param selector char[] - Name of the new method.
+ * @param parameterPackageNames char[][] - Names of the packages in which the parameter types are declared.
+ * Should contain as many elements as parameterTypeNames.
+ * @param parameterTypeNames char[][] - Names of the parameters types.
+ * Should contain as many elements as parameterPackageNames.
+ * @param returnTypePackageName char[] - Name of the package in which the return type is declared.
+ * @param returnTypeName char[] - Name of the return type of this new method, should be null for a constructor.
+ * @param completionName char[] - The completion for the method.
+ * Can include zero, one or two brackets. If the closing bracket is included, then the cursor should be placed before it.
+ * @param modifiers int - The modifiers of this new method.
+ * @param completionStart int - The start position of insertion of the name of this new method.
+ * @param completionEnd int - The end position of insertion of the name of this new method.
+ * @see com.ibm.compiler.java.ast.Modifiers
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Base types are in the form "int" or "boolean".
+ * Array types are in the qualified form "M[]" or "int[]".
+ * Nested type names are in the qualified form "A.M".
+ * The default package is represented by an empty array.
+ *
+ * NOTE: parameter names can be retrieved from the source model after the user selects a specific method.
+ */
+ void acceptMethod(
+ char[] declaringTypePackageName,
+ char[] declaringTypeName,
+ char[] selector,
+ char[][] parameterPackageNames,
+ char[][] parameterTypeNames,
+ char[] returnTypePackageName,
+ char[] returnTypeName,
+ char[] completionName,
+ int modifiers,
+ int completionStart,
+ int completionEnd);
+ /**
+ * Code assist notification of a modifier completion.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param modifierName char[] - The new modifier.
+ * @param completionStart int - The start position of insertion of the name of this new modifier.
+ * @param completionEnd int - The end position of insertion of the name of this new modifier.
+ */
+ void acceptModifier(
+ char[] modifierName,
+ int completionStart,
+ int completionEnd);
+ /**
+ * Code assist notification of a package completion.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param packageName char[] - The package name.
+ * @param completionName char[] - The completion for the package.
+ * Can include '.*;' for imports.
+ * @param completionStart int - The start position of insertion of the name of this new package.
+ * @param completionEnd int - The end position of insertion of the name of this new package.
+ *
+ * NOTE - All package names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * The default package is represented by an empty array.
+ */
+ void acceptPackage(
+ char[] packageName,
+ char[] completionName,
+ int completionStart,
+ int completionEnd);
+ /**
+ * Code assist notification of a type completion.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param packageName char[] - Declaring package name of the type.
+ * @param typeName char[] - Name of the type.
+ * @param completionName char[] - The completion for the type.
+ * Can include ';' for imported types.
+ * @param completionStart int - The start position of insertion of the name of the type.
+ * @param completionEnd int - The end position of insertion of the name of the type.
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Nested type names are in the qualified form "A.M".
+ * The default package is represented by an empty array.
+ */
+ void acceptType(
+ char[] packageName,
+ char[] typeName,
+ char[] completionName,
+ int completionStart,
+ int completionEnd);
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ISearchRequestor.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ISearchRequestor.java
new file mode 100644
index 0000000000..d6da77dcc9
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ISearchRequestor.java
@@ -0,0 +1,39 @@
+package org.eclipse.jdt.internal.codeassist;
+
+public interface ISearchRequestor {
+ /**
+ * One result of the search consists of a new class.
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Nested type names are in the qualified form "A.M".
+ * The default package is represented by an empty array.
+ */
+ public void acceptClass(char[] packageName, char[] typeName, int modifiers);
+ /**
+ * One result of the search consists of a new interface.
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Nested type names are in the qualified form "A.I".
+ * The default package is represented by an empty array.
+ */
+ public void acceptInterface(char[] packageName, char[] typeName, int modifiers);
+ /**
+ * One result of the search consists of a new package.
+ *
+ * NOTE - All package names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * The default package is represented by an empty array.
+ */
+ public void acceptPackage(char[] packageName);
+ /**
+ * One result of the search consists of a new type.
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Nested type names are in the qualified form "A.M".
+ * The default package is represented by an empty array.
+ */
+ public void acceptType(char[] packageName, char[] typeName);
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ISearchableNameEnvironment.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ISearchableNameEnvironment.java
new file mode 100644
index 0000000000..5b14ab2635
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ISearchableNameEnvironment.java
@@ -0,0 +1,43 @@
+package org.eclipse.jdt.internal.codeassist;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/**
+ * This interface defines the API that may be used to implement any
+ * search-based tool (such as a CodeAssist, a Finder, ...)
+ * It is mainly used to hide from the search tool the implementation
+ * of the underlying environment and its constructions.
+ */
+
+import org.eclipse.jdt.internal.compiler.env.*;
+
+public interface ISearchableNameEnvironment extends INameEnvironment {
+ /**
+ * Find the packages that start with the given prefix.
+ * A valid prefix is a qualified name separated by periods
+ * (ex. com.ibm.com or java.util).
+ * The packages found are passed to:
+ * ISearchRequestor.acceptPackage(char[][] packageName)
+ */
+
+ void findPackages(char[] prefix, ISearchRequestor requestor);
+ /**
+ * Find the top-level types (classes and interfaces) that are defined
+ * in the current environment and whose name starts with the
+ * given prefix. The prefix is a qualified name separated by periods
+ * or a simple name (ex. java.util.V or V).
+ *
+ * The types found are passed to one of the following methods (if additional
+ * information is known about the types):
+ * ISearchRequestor.acceptType(char[][] packageName, char[] typeName)
+ * ISearchRequestor.acceptClass(char[][] packageName, char[] typeName, int modifiers)
+ * ISearchRequestor.acceptInterface(char[][] packageName, char[] typeName, int modifiers)
+ *
+ * This method can not be used to find member types... member
+ * types are found relative to their enclosing type.
+ */
+
+ void findTypes(char[] prefix, ISearchRequestor requestor);
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ISelectionRequestor.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ISelectionRequestor.java
new file mode 100644
index 0000000000..3d2beecc1c
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ISelectionRequestor.java
@@ -0,0 +1,124 @@
+package org.eclipse.jdt.internal.codeassist;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/**
+ * A selection requestor accepts results from the selection engine.
+ */
+
+import org.eclipse.jdt.internal.compiler.*;
+
+public interface ISelectionRequestor {
+ /**
+ * Code assist notification of a class selection.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param packageName char[] - Declaring package name of the class.
+ * @param className char[] - Name of the class.
+ * @param needQualification boolean - Flag indicating if the type name
+ * must be qualified by its package name (depending on imports).
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Nested type names are in the qualified form "A.M".
+ * The default package is represented by an empty array.
+ */
+ void acceptClass(
+ char[] packageName,
+ char[] className,
+ boolean needQualification);
+ /**
+ * Code assist notification of a compilation error detected during selection.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param error com.ibm.compiler.java.api.problem.IProblem
+ * Only problems which are categorized as errors are notified to the requestor,
+ * warnings are silently ignored.
+ * In case an error got signaled, no other completions might be available,
+ * therefore the problem message should be presented to the user.
+ * The source positions of the problem are related to the source where it was
+ * detected (might be in another compilation unit, if it was indirectly requested
+ * during the code assist process).
+ * Note: the problem knows its originating file name.
+ */
+ void acceptError(IProblem error);
+ /**
+ * Code assist notification of a field selection.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param declaringTypePackageName char[] - Name of the package in which the type that contains this field is declared.
+ * @param declaringTypeName char[] - Name of the type declaring this new field.
+ * @param name char[] - Name of the field.
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Nested type names are in the qualified form "A.M".
+ * The default package is represented by an empty array.
+ */
+ void acceptField(
+ char[] declaringTypePackageName,
+ char[] declaringTypeName,
+ char[] name);
+ /**
+ * Code assist notification of an interface selection.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param packageName char[] - Declaring package name of the interface.
+ * @param interfaceName char[] - Name of the interface.
+ * @param needQualification boolean - Flag indicating if the type name
+ * must be qualified by its package name (depending on imports).
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Nested type names are in the qualified form "A.I".
+ * The default package is represented by an empty array.
+ */
+ void acceptInterface(
+ char[] packageName,
+ char[] interfaceName,
+ boolean needQualification);
+ /**
+ * Code assist notification of a method selection.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param declaringTypePackageName char[] - Name of the package in which the type that contains this new method is declared.
+ * @param declaringTypeName char[] - Name of the type declaring this new method.
+ * @param selector char[] - Name of the new method.
+ * @param parameterPackageNames char[][] - Names of the packages in which the parameter types are declared.
+ * Should contain as many elements as parameterTypeNames.
+ * @param parameterTypeNames char[][] - Names of the parameters types.
+ * Should contain as many elements as parameterPackageNames.
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Base types are in the form "int" or "boolean".
+ * Array types are in the qualified form "M[]" or "int[]".
+ * Nested type names are in the qualified form "A.M".
+ * The default package is represented by an empty array.
+ */
+ void acceptMethod(
+ char[] declaringTypePackageName,
+ char[] declaringTypeName,
+ char[] selector,
+ char[][] parameterPackageNames,
+ char[][] parameterTypeNames);
+ /**
+ * Code assist notification of a package selection.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param packageName char[] - The package name.
+ *
+ * NOTE - All package names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * The default package is represented by an empty array.
+ */
+ void acceptPackage(char[] packageName);
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/SelectionEngine.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/SelectionEngine.java
new file mode 100644
index 0000000000..5397047bbc
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/SelectionEngine.java
@@ -0,0 +1,498 @@
+package org.eclipse.jdt.internal.codeassist;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.Locale;
+
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.*;
+
+import org.eclipse.jdt.internal.codeassist.impl.*;
+import org.eclipse.jdt.internal.codeassist.select.*;
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.parser.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+import org.eclipse.jdt.internal.compiler.impl.*;
+
+/**
+ * The selection engine is intended to infer the nature of a selected name in some
+ * source code. This name can be qualified.
+ *
+ * Selection is resolving context using a name environment (no need to search), assuming
+ * the source where selection occurred is correct and will not perform any completion
+ * attempt. If this was the desired behavior, a call to the CompletionEngine should be
+ * performed instead.
+ */
+public final class SelectionEngine extends Engine implements ISearchRequestor {
+ SelectionParser parser;
+ ISearchableNameEnvironment nameEnvironment;
+ ISelectionRequestor requestor;
+
+ CompilationUnitScope unitScope;
+ boolean acceptedAnswer;
+
+ private int actualSelectionStart;
+ private int actualSelectionEnd;
+ private char[] qualifiedSelection;
+ private char[] selectedIdentifier;
+ /**
+ * The SelectionEngine is responsible for computing the selected object.
+ *
+ * It requires a searchable name environment, which supports some
+ * specific search APIs, and a requestor to feed back the results to a UI.
+ *
+ * @param environment com.ibm.codeassist.java.api.INameEnvironment
+ * used to resolve type/package references and search for types/packages
+ * based on partial names.
+ *
+ * @param requestor com.ibm.codeassist.java.api.ISelectionRequestor
+ * since the engine might produce answers of various forms, the engine
+ * is associated with a requestor able to accept all possible completions.
+ *
+ * @param options com.ibm.compiler.java.api.ConfigurableOptions
+ * set of options used to configure the code assist engine.
+ */
+
+ public SelectionEngine(
+ ISearchableNameEnvironment nameEnvironment,
+ ISelectionRequestor requestor,
+ ConfigurableOption[] settings) {
+ this.requestor = requestor;
+ this.nameEnvironment = nameEnvironment;
+
+ CompilerOptions options = new CompilerOptions(settings);
+ ProblemReporter problemReporter =
+ new ProblemReporter(
+ DefaultErrorHandlingPolicies.proceedWithAllProblems(),
+ options,
+ new DefaultProblemFactory(Locale.getDefault())) {
+ public void record(IProblem problem, CompilationResult unitResult) {
+ unitResult.record(problem);
+ SelectionEngine.this.requestor.acceptError(problem);
+ }
+ };
+
+ this.parser = new SelectionParser(problemReporter);
+ this.lookupEnvironment =
+ new LookupEnvironment(this, options, problemReporter, nameEnvironment);
+ }
+
+ /**
+ * One result of the search consists of a new class.
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Nested type names are in the qualified form "A.M".
+ * The default package is represented by an empty array.
+ */
+ public void acceptClass(char[] packageName, char[] className, int modifiers) {
+ if (CharOperation.equals(className, selectedIdentifier)) {
+
+ if (qualifiedSelection != null
+ && !CharOperation.equals(
+ qualifiedSelection,
+ CharOperation.concat(packageName, className, '.'))) {
+ return;
+ }
+
+ requestor.acceptClass(
+ packageName,
+ className,
+ mustQualifyType(CharOperation.splitOn('.', packageName), className));
+ acceptedAnswer = true;
+ }
+ }
+
+ /**
+ * One result of the search consists of a new interface.
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Nested type names are in the qualified form "A.I".
+ * The default package is represented by an empty array.
+ */
+ public void acceptInterface(
+ char[] packageName,
+ char[] interfaceName,
+ int modifiers) {
+ if (CharOperation.equals(interfaceName, selectedIdentifier)) {
+
+ if (qualifiedSelection != null
+ && !CharOperation.equals(
+ qualifiedSelection,
+ CharOperation.concat(packageName, interfaceName, '.'))) {
+ return;
+ }
+
+ requestor.acceptInterface(
+ packageName,
+ interfaceName,
+ mustQualifyType(CharOperation.splitOn('.', packageName), interfaceName));
+ acceptedAnswer = true;
+ }
+ }
+
+ /**
+ * One result of the search consists of a new package.
+ *
+ * NOTE - All package names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * The default package is represented by an empty array.
+ */
+ public void acceptPackage(char[] packageName) {
+ }
+
+ /**
+ * One result of the search consists of a new type.
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Nested type names are in the qualified form "A.M".
+ * The default package is represented by an empty array.
+ */
+ public void acceptType(char[] packageName, char[] typeName) {
+ acceptClass(packageName, typeName, 0);
+ }
+
+ private boolean checkSelection(
+ char[] source,
+ int selectionStart,
+ int selectionEnd) {
+
+ Scanner scanner = new Scanner();
+ scanner.setSourceBuffer(source);
+ scanner.resetTo(selectionStart, selectionEnd);
+
+ int lastIdentifierStart = -1;
+ int lastIdentifierEnd = -1;
+ int token, identCount = 0;
+ char[] lastIdentifier = null;
+ boolean expectingIdentifier = true;
+ StringBuffer entireSelection =
+ new StringBuffer(selectionEnd - selectionStart + 1);
+ do {
+ try {
+ token = scanner.getNextToken();
+ } catch (InvalidInputException e) {
+ return false;
+ }
+ switch (token) {
+ case TerminalSymbols.TokenNameIdentifier :
+ if (!expectingIdentifier)
+ return false;
+ entireSelection.append(lastIdentifier = scanner.getCurrentIdentifierSource());
+ lastIdentifierStart = scanner.startPosition;
+ lastIdentifierEnd = scanner.currentPosition - 1;
+ identCount++;
+ expectingIdentifier = false;
+ break;
+ case TerminalSymbols.TokenNameDOT :
+ if (expectingIdentifier)
+ return false;
+ entireSelection.append('.');
+ expectingIdentifier = true;
+ break;
+ case TerminalSymbols.TokenNameEOF :
+ if (expectingIdentifier)
+ return false;
+ break;
+ default :
+ return false;
+ }
+ } while (token != TerminalSymbols.TokenNameEOF);
+ if (lastIdentifierStart > 0) {
+ actualSelectionStart = lastIdentifierStart;
+ actualSelectionEnd = lastIdentifierEnd;
+ selectedIdentifier = lastIdentifier;
+ if (identCount > 1)
+ qualifiedSelection = entireSelection.toString().toCharArray();
+ return true;
+ }
+ return false;
+ }
+
+ public AssistParser getParser() {
+ return parser;
+ }
+
+ private boolean mustQualifyType(
+ char[][] packageName,
+ char[] readableTypeName) {
+ // If there are no types defined into the current CU yet.
+ if (unitScope == null)
+ return true;
+ if (CharOperation.equals(unitScope.fPackage.compoundName, packageName))
+ return false;
+
+ ImportBinding[] imports = unitScope.imports;
+ for (int i = 0, length = imports.length; i < length; i++) {
+ if (imports[i].onDemand) {
+ if (CharOperation.equals(imports[i].compoundName, packageName))
+ return false; // how do you match p1.p2.A.* ?
+ } else
+ if (CharOperation.equals(imports[i].readableName(), readableTypeName)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Ask the engine to compute the selection at the specified position
+ * of the given compilation unit.
+ *
+ * @return void
+ * the selection result is answered through a requestor.
+ *
+ * @param unit com.ibm.compiler.java.api.env.ICompilationUnit
+ * the source of the current compilation unit.
+ *
+ * @param selectionSourceStart int
+ * @param selectionSourceEnd int
+ * a range in the source where the selection is.
+ */
+ public void select(
+ ICompilationUnit sourceUnit,
+ int selectionSourceStart,
+ int selectionSourceEnd) {
+
+ char[] source = sourceUnit.getContents();
+ if (!checkSelection(source, selectionSourceStart, selectionSourceEnd - 1))
+ return;
+ try {
+ acceptedAnswer = false;
+ CompilationResult result = new CompilationResult(sourceUnit, 1, 1);
+ CompilationUnitDeclaration parsedUnit =
+ parser.dietParse(sourceUnit, result, actualSelectionStart, actualSelectionEnd);
+
+ if (parsedUnit != null) {
+ // scan the package & import statements first
+ if (parsedUnit.currentPackage instanceof SelectionOnPackageReference) {
+ char[][] tokens =
+ ((SelectionOnPackageReference) parsedUnit.currentPackage).tokens;
+ requestor.acceptPackage(CharOperation.concatWith(tokens, '.'));
+ return;
+ }
+ ImportReference[] imports = parsedUnit.imports;
+ if (imports != null) {
+ for (int i = 0, length = imports.length; i < length; i++) {
+ ImportReference importReference = imports[i];
+ if (importReference instanceof SelectionOnImportReference) {
+ char[][] tokens = ((SelectionOnImportReference) importReference).tokens;
+ requestor.acceptPackage(CharOperation.concatWith(tokens, '.'));
+ nameEnvironment.findTypes(CharOperation.concatWith(tokens, '.'), this);
+ if (!acceptedAnswer)
+ nameEnvironment.findTypes(selectedIdentifier, this);
+ // try with simple type name
+ return;
+ }
+ }
+ }
+
+ if (parsedUnit.types != null) {
+ lookupEnvironment.buildTypeBindings(parsedUnit);
+ if (parsedUnit.scope != null) {
+ try {
+ lookupEnvironment.completeTypeBindings(parsedUnit, true);
+ parsedUnit.scope.faultInTypes();
+ parseMethod(parsedUnit, selectionSourceStart);
+ parsedUnit.resolve();
+ } catch (SelectionNodeFound e) {
+ if (e.binding != null) {
+ // if null then we found a problem in the selection node
+ selectFrom(e.binding);
+ }
+ }
+ }
+ }
+ }
+
+ // only reaches here if no selection could be derived from the parsed tree
+ // thus use the selected source and perform a textual type search
+ if (!acceptedAnswer) {
+ nameEnvironment.findTypes(selectedIdentifier, this);
+ }
+ } catch (IndexOutOfBoundsException e) { // work-around internal failure - 1GEMF6D
+ } catch (AbortCompilation e) { // ignore this exception for now since it typically means we cannot find java.lang.Object
+ } finally {
+ reset();
+ }
+ }
+
+ private void selectFrom(Binding binding) {
+ if (binding instanceof ReferenceBinding) {
+ ReferenceBinding typeBinding = (ReferenceBinding) binding;
+ if (qualifiedSelection != null
+ && !CharOperation.equals(qualifiedSelection, typeBinding.readableName())) {
+ return;
+ }
+ if (typeBinding.isInterface())
+ requestor.acceptInterface(
+ typeBinding.qualifiedPackageName(),
+ typeBinding.qualifiedSourceName(),
+ false);
+ else
+ requestor.acceptClass(
+ typeBinding.qualifiedPackageName(),
+ typeBinding.qualifiedSourceName(),
+ false);
+ acceptedAnswer = true;
+ } else
+ if (binding instanceof MethodBinding) {
+ MethodBinding methodBinding = (MethodBinding) binding;
+ TypeBinding[] parameterTypes = methodBinding.parameters;
+ int length = parameterTypes.length;
+ char[][] parameterPackageNames = new char[length][];
+ char[][] parameterTypeNames = new char[length][];
+ for (int i = 0; i < length; i++) {
+ parameterPackageNames[i] = parameterTypes[i].qualifiedPackageName();
+ parameterTypeNames[i] = parameterTypes[i].qualifiedSourceName();
+ }
+ requestor.acceptMethod(
+ methodBinding.declaringClass.qualifiedPackageName(),
+ methodBinding.declaringClass.qualifiedSourceName(),
+ methodBinding.isConstructor()
+ ? methodBinding.declaringClass.sourceName()
+ : methodBinding.selector,
+ parameterPackageNames,
+ parameterTypeNames);
+ acceptedAnswer = true;
+ } else
+ if (binding instanceof FieldBinding) {
+ FieldBinding fieldBinding = (FieldBinding) binding;
+ if (fieldBinding.declaringClass != null) { // arraylength
+ requestor.acceptField(
+ fieldBinding.declaringClass.qualifiedPackageName(),
+ fieldBinding.declaringClass.qualifiedSourceName(),
+ fieldBinding.name);
+ acceptedAnswer = true;
+ }
+ } else
+ if (binding instanceof LocalVariableBinding) {
+ selectFrom(((LocalVariableBinding) binding).type);
+ // open on the type of the variable
+ } else
+ if (binding instanceof ArrayBinding) {
+ selectFrom(((ArrayBinding) binding).leafComponentType);
+ // open on the type of the array
+ } else
+ if (binding instanceof PackageBinding) {
+ PackageBinding packageBinding = (PackageBinding) binding;
+ requestor.acceptPackage(packageBinding.readableName());
+ acceptedAnswer = true;
+ }
+ }
+
+ /**
+ * Asks the engine to compute the selection of the given type
+ * from the source type.
+ *
+ * @return void
+ * the selection result is answered through a requestor.
+ *
+ * @param sourceType com.ibm.compiler.java.api.env.ISourceType
+ * a source form of the current type in which code assist is invoked.
+ *
+ * @param typeName char[]
+ * a type name which is to be resolved in the context of a compilation unit.
+ * NOTE: the type name is supposed to be correctly reduced (no whitespaces, no unicodes left)
+ */
+
+ public void selectType(ISourceType sourceType, char[] typeName) {
+ try {
+ acceptedAnswer = false;
+
+ // find the outer most type
+ ISourceType outerType = sourceType;
+ ISourceType parent = sourceType.getEnclosingType();
+ while (parent != null) {
+ outerType = parent;
+ parent = parent.getEnclosingType();
+ }
+
+ // compute parse tree for this most outer type
+ CompilationResult result = new CompilationResult(outerType.getFileName(), 1, 1);
+ CompilationUnitDeclaration parsedUnit =
+ SourceTypeConverter.buildCompilationUnit(outerType, false,
+ // don't need field and methods
+ this.parser.problemReporter(), result);
+
+ if (parsedUnit != null && parsedUnit.types != null) {
+ // find the type declaration that corresponds to the original source type
+ char[] packageName = sourceType.getPackageName();
+ char[] sourceTypeName = sourceType.getQualifiedName();
+ // the fully qualified name without the package name
+ if (packageName != null) {
+ // remove the package name if necessary
+ sourceTypeName =
+ CharOperation.subarray(
+ sourceType.getQualifiedName(),
+ packageName.length + 1,
+ sourceTypeName.length);
+ };
+ TypeDeclaration typeDecl =
+ parsedUnit.declarationOfType(CharOperation.splitOn('.', sourceTypeName));
+ if (typeDecl != null) {
+
+ // add fake field with the type we're looking for
+ // note: since we didn't ask for fields above, there is no field defined yet
+ FieldDeclaration field = new FieldDeclaration();
+ int dot;
+ if ((dot = CharOperation.lastIndexOf('.', typeName)) == -1) {
+ this.selectedIdentifier = typeName;
+ field.type = new SelectionOnSingleTypeReference(typeName, -1);
+ // position not used
+ } else {
+ char[][] previousIdentifiers = CharOperation.splitOn('.', typeName, 0, dot - 1);
+ char[] selectionIdentifier =
+ CharOperation.subarray(typeName, dot + 1, typeName.length);
+ this.selectedIdentifier = selectionIdentifier;
+ field.type =
+ new SelectionOnQualifiedTypeReference(
+ previousIdentifiers,
+ selectionIdentifier,
+ new long[previousIdentifiers.length + 1]);
+ }
+ field.name = "<fakeField>".toCharArray();
+ typeDecl.fields = new FieldDeclaration[] { field };
+
+ // build bindings
+ lookupEnvironment.buildTypeBindings(parsedUnit);
+ if ((this.unitScope = parsedUnit.scope) != null) {
+ try {
+ // build fields
+ // note: this builds fields only in the parsed unit (the buildFieldsAndMethods flag is not passed along)
+ this.lookupEnvironment.completeTypeBindings(parsedUnit, true);
+
+ // resolve
+ parsedUnit.scope.faultInTypes();
+ parsedUnit.resolve();
+ } catch (SelectionNodeFound e) {
+ if (e.binding != null) {
+ // if null then we found a problem in the selection node
+ selectFrom(e.binding);
+ }
+ }
+ }
+ }
+ }
+
+ // only reaches here if no selection could be derived from the parsed tree
+ // thus use the selected source and perform a textual type search
+ if (!acceptedAnswer) {
+ if (this.selectedIdentifier != null) {
+ nameEnvironment.findTypes(typeName, this);
+ }
+ }
+ } catch (AbortCompilation e) { // ignore this exception for now since it typically means we cannot find java.lang.Object
+ } finally {
+ reset();
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionNodeFound.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionNodeFound.java
new file mode 100644
index 0000000000..509520cf25
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionNodeFound.java
@@ -0,0 +1,34 @@
+package org.eclipse.jdt.internal.codeassist.complete;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.*;
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class CompletionNodeFound extends RuntimeException {
+ public AstNode astNode;
+ public Binding qualifiedBinding;
+ public Scope scope;
+ public CompletionNodeFound() {
+ this(null, null, null); // we found a problem in the completion node
+ }
+
+ public CompletionNodeFound(
+ AstNode astNode,
+ Binding qualifiedBinding,
+ Scope scope) {
+ this.astNode = astNode;
+ this.qualifiedBinding = qualifiedBinding;
+ this.scope = scope;
+ }
+
+ public CompletionNodeFound(AstNode astNode, Scope scope) {
+ this(astNode, null, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnClassLiteralAccess.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnClassLiteralAccess.java
new file mode 100644
index 0000000000..6a098013cc
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnClassLiteralAccess.java
@@ -0,0 +1,54 @@
+package org.eclipse.jdt.internal.codeassist.complete;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Completion node build by the parser in any case it was intending to
+ * reduce an access to the literal 'class' containing the cursor.
+ * e.g.
+ *
+ * class X {
+ * void foo() {
+ * String[].[cursor]
+ * }
+ * }
+ *
+ * ---> class X {
+ * void foo() {
+ * <CompleteOnClassLiteralAccess:String[].>
+ * }
+ * }
+ *
+ * The source range of the completion node denotes the source range
+ * which should be replaced by the completion.
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class CompletionOnClassLiteralAccess extends ClassLiteralAccess {
+ public char[] completionIdentifier;
+ public CompletionOnClassLiteralAccess(long pos, TypeReference t) {
+ super((int) (pos >>> 32), t);
+ this.sourceEnd = (int) pos;
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ if (super.resolveType(scope) == null)
+ throw new CompletionNodeFound();
+ else
+ throw new CompletionNodeFound(this, targetType, scope);
+ }
+
+ public String toStringExpression() {
+ StringBuffer result = new StringBuffer("<CompleteOnClassLiteralAccess:");
+ result.append(type.toString());
+ result.append(".");
+ result.append(completionIdentifier);
+ result.append(">");
+ return result.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnExceptionReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnExceptionReference.java
new file mode 100644
index 0000000000..12b285d548
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnExceptionReference.java
@@ -0,0 +1,13 @@
+package org.eclipse.jdt.internal.codeassist.complete;
+
+public class CompletionOnExceptionReference
+ extends CompletionOnSingleTypeReference {
+ public CompletionOnExceptionReference(char[] source, long pos) {
+ super(source, pos);
+ }
+
+ public String toStringExpression(int tab) {
+ return "<CompleteOnException:" + new String(token) + ">";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnExplicitConstructorCall.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnExplicitConstructorCall.java
new file mode 100644
index 0000000000..f2e89e55be
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnExplicitConstructorCall.java
@@ -0,0 +1,74 @@
+package org.eclipse.jdt.internal.codeassist.complete;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Completion node build by the parser in any case it was intending to
+ * reduce a explicit constructor call containing the cursor.
+ * e.g.
+ *
+ * class X {
+ * X() {
+ * this(1, 2, [cursor]
+ * }
+ * }
+ *
+ * ---> class X {
+ * X() {
+ * <CompleteOnExplicitConstructorCall:this(1, 2)>
+ * }
+ * }
+ *
+ * The source range is always of length 0.
+ * The arguments of the constructor call are all the arguments defined
+ * before the cursor.
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class CompletionOnExplicitConstructorCall
+ extends ExplicitConstructorCall {
+ public CompletionOnExplicitConstructorCall(int accessMode) {
+ super(accessMode);
+ }
+
+ public void resolve(BlockScope scope) {
+ ReferenceBinding receiverType = scope.enclosingSourceType();
+
+ if (accessMode != This && receiverType != null) {
+ if (receiverType.isHierarchyInconsistent())
+ throw new CompletionNodeFound();
+ receiverType = receiverType.superclass();
+ }
+ if (receiverType == null)
+ throw new CompletionNodeFound();
+ else
+ throw new CompletionNodeFound(this, receiverType, scope);
+ }
+
+ public String toString(int tab) {
+ String s = tabString(tab);
+ s += "<CompleteOnExplicitConstructorCall:";
+ if (qualification != null)
+ s = s + qualification.toStringExpression() + ".";
+ if (accessMode == This) {
+ s = s + "this(";
+ } else {
+ s = s + "super(";
+ }
+ if (arguments != null) {
+ for (int i = 0; i < arguments.length; i++) {
+ s += arguments[i].toStringExpression();
+ if (i != arguments.length - 1) {
+ s += ", ";
+ }
+ };
+ }
+ s += ")>";
+ return s;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnFieldType.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnFieldType.java
new file mode 100644
index 0000000000..69fd4955f5
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnFieldType.java
@@ -0,0 +1,53 @@
+package org.eclipse.jdt.internal.codeassist.complete;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Completion node build by the parser in any case it was intending to
+ * reduce an type reference located as a potential return type for a class
+ * member, containing the cursor location.
+ * This node is only a fake-field wrapper of the actual completion node
+ * which is accessible as the fake-field type.
+ * e.g.
+ *
+ * class X {
+ * Obj[cursor]
+ * }
+ *
+ * ---> class X {
+ * <CompleteOnType:Obj>;
+ * }
+ *
+ * The source range is always of length 0.
+ * The arguments of the allocation expression are all the arguments defined
+ * before the cursor.
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class CompletionOnFieldType extends FieldDeclaration {
+
+ public CompletionOnFieldType(TypeReference type) {
+ super();
+ this.sourceStart = type.sourceStart;
+ this.sourceEnd = type.sourceEnd;
+ this.type = type;
+ this.name = NoChar;
+ }
+
+ public TypeBinding getTypeBinding(Scope scope) {
+ if (type instanceof CompletionOnSingleTypeReference)
+ throw new CompletionNodeFound(this, scope);
+ else // handle the qualified type ref directly
+ return type.getTypeBinding(scope);
+ }
+
+ public String toString(int tab) {
+
+ return type.toString(tab);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnImportReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnImportReference.java
new file mode 100644
index 0000000000..ebfa31b524
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnImportReference.java
@@ -0,0 +1,51 @@
+package org.eclipse.jdt.internal.codeassist.complete;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Completion node build by the parser in any case it was intending to
+ * reduce an import reference containing the cursor location.
+ * e.g.
+ *
+ * import java.io[cursor];
+ * class X {
+ * void foo() {
+ * }
+ * }
+ *
+ * ---> <CompleteOnImport:java.io>
+ * class X {
+ * void foo() {
+ * }
+ * }
+ *
+ * The source range is always of length 0.
+ * The arguments of the allocation expression are all the arguments defined
+ * before the cursor.
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+
+public class CompletionOnImportReference extends ImportReference {
+
+ public CompletionOnImportReference(char[][] tokens, long[] positions) {
+ super(tokens, positions, false);
+ }
+
+ public String toString(int tab, boolean withOnDemand) {
+
+ StringBuffer buffer = new StringBuffer(tabString(tab));
+ buffer.append("<CompleteOnImport:");
+ for (int i = 0; i < tokens.length; i++) {
+ buffer.append(tokens[i]);
+ if (i < (tokens.length - 1)) {
+ buffer.append(".");
+ }
+ }
+ buffer.append(">");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnMemberAccess.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnMemberAccess.java
new file mode 100644
index 0000000000..3c0f715a79
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnMemberAccess.java
@@ -0,0 +1,52 @@
+package org.eclipse.jdt.internal.codeassist.complete;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Completion node build by the parser in any case it was intending to
+ * reduce an access to a member (field reference or message send)
+ * containing the completion identifier.
+ * e.g.
+ *
+ * class X {
+ * void foo() {
+ * bar().fred[cursor]
+ * }
+ * }
+ *
+ * ---> class X {
+ * void foo() {
+ * <CompleteOnMemberAccess:bar().fred>
+ * }
+ * }
+ *
+ * The source range of the completion node denotes the source range
+ * which should be replaced by the completion.
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class CompletionOnMemberAccess extends FieldReference {
+ public CompletionOnMemberAccess(char[] source, long pos) {
+ super(source, pos);
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ TypeBinding receiverType = receiver.resolveType(scope);
+ if (receiverType == null || receiverType.isBaseType())
+ throw new CompletionNodeFound();
+ else
+ throw new CompletionNodeFound(this, receiverType, scope);
+ // array types are passed along to find the length field
+ }
+
+ public String toStringExpression() {
+ /* slow code */
+
+ return "<CompleteOnMemberAccess:" + super.toStringExpression() + ">";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnMessageSend.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnMessageSend.java
new file mode 100644
index 0000000000..0056963b7c
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnMessageSend.java
@@ -0,0 +1,65 @@
+package org.eclipse.jdt.internal.codeassist.complete;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Completion node build by the parser in any case it was intending to
+ * reduce a message send containing the cursor.
+ * e.g.
+ *
+ * class X {
+ * void foo() {
+ * this.bar(1, 2, [cursor]
+ * }
+ * }
+ *
+ * ---> class X {
+ * void foo() {
+ * <CompleteOnMessageSend:this.bar(1, 2)>
+ * }
+ * }
+ *
+ * The source range is always of length 0.
+ * The arguments of the message send are all the arguments defined
+ * before the cursor.
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class CompletionOnMessageSend extends MessageSend {
+ public TypeBinding resolveType(BlockScope scope) {
+ if (receiver == ThisReference.ThisImplicit)
+ throw new CompletionNodeFound(this, null, scope);
+
+ TypeBinding receiverType = receiver.resolveType(scope);
+ if (receiverType == null || receiverType.isBaseType())
+ throw new CompletionNodeFound();
+
+ if (receiverType.isArrayType())
+ receiverType = scope.getJavaLangObject();
+ throw new CompletionNodeFound(this, receiverType, scope);
+ }
+
+ public String toStringExpression() {
+ /*slow code*/
+
+ String s = "<CompleteOnMessageSend:";
+ if (receiver != ThisReference.ThisImplicit)
+ s = s + receiver.toStringExpression() + ".";
+ s = s + new String(selector) + "(";
+ if (arguments != null) {
+ for (int i = 0; i < arguments.length; i++) {
+ s += arguments[i].toStringExpression();
+ if (i != arguments.length - 1) {
+ s += ", ";
+ }
+ };
+ }
+ s = s + ")>";
+ return s;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnPackageReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnPackageReference.java
new file mode 100644
index 0000000000..a65f80b3de
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnPackageReference.java
@@ -0,0 +1,49 @@
+package org.eclipse.jdt.internal.codeassist.complete;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Completion node build by the parser in any case it was intending to
+ * reduce an package statement containing the cursor location.
+ * e.g.
+ *
+ * package java.io[cursor];
+ * class X {
+ * void foo() {
+ * }
+ * }
+ *
+ * ---> <CompleteOnPackage:java.io>
+ * class X {
+ * void foo() {
+ * }
+ * }
+ *
+ * The source range is always of length 0.
+ * The arguments of the allocation expression are all the arguments defined
+ * before the cursor.
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+
+public class CompletionOnPackageReference extends ImportReference {
+ public CompletionOnPackageReference(char[][] tokens, long[] positions) {
+ super(tokens, positions, true);
+ }
+
+ public String toString(int tab, boolean withOnDemand) {
+ StringBuffer buffer = new StringBuffer(tabString(tab));
+ buffer.append("<CompleteOnPackage:");
+ for (int i = 0; i < tokens.length; i++) {
+ buffer.append(tokens[i]);
+ if (i < (tokens.length - 1)) {
+ buffer.append(".");
+ }
+ }
+ buffer.append(">");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedAllocationExpression.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedAllocationExpression.java
new file mode 100644
index 0000000000..b1fb602821
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedAllocationExpression.java
@@ -0,0 +1,74 @@
+package org.eclipse.jdt.internal.codeassist.complete;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Completion node build by the parser in any case it was intending to
+ * reduce an allocation expression containing the cursor.
+ * If the allocation expression is not qualified, the enclosingInstance field
+ * is null.
+ * e.g.
+ *
+ * class X {
+ * void foo() {
+ * new Bar(1, 2, [cursor]
+ * }
+ * }
+ *
+ * ---> class X {
+ * void foo() {
+ * <CompleteOnAllocationExpression:new Bar(1, 2)>
+ * }
+ * }
+ *
+ * The source range is always of length 0.
+ * The arguments of the allocation expression are all the arguments defined
+ * before the cursor.
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class CompletionOnQualifiedAllocationExpression
+ extends QualifiedAllocationExpression {
+ public TypeBinding resolveType(BlockScope scope) {
+ TypeBinding typeBinding = null;
+ if (enclosingInstance != null) {
+ TypeBinding enclosingType = enclosingInstance.resolveType(scope);
+ if (!(enclosingType instanceof ReferenceBinding)) {
+ scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance(
+ enclosingType,
+ enclosingInstance);
+ throw new CompletionNodeFound();
+ }
+ typeBinding =
+ ((SingleTypeReference) type).resolveTypeEnclosing(
+ scope,
+ (ReferenceBinding) enclosingType);
+ if (!(typeBinding instanceof ReferenceBinding))
+ throw new CompletionNodeFound();
+ // no need to continue if its an array or base type
+ if (typeBinding.isInterface()) // handle the anonymous class definition case
+ typeBinding = scope.getJavaLangObject();
+ } else {
+ typeBinding = type.resolveType(scope);
+ if (!(typeBinding instanceof ReferenceBinding))
+ throw new CompletionNodeFound();
+ // no need to continue if its an array or base type
+ }
+
+ throw new CompletionNodeFound(this, typeBinding, scope);
+ }
+
+ public String toStringExpression(int tab) {
+ return (
+ (this.enclosingInstance == null)
+ ? "<CompleteOnAllocationExpression:"
+ : "<CompleteOnQualifiedAllocationExpression:")
+ + super.toStringExpression(tab)
+ + ">";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedExceptionReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedExceptionReference.java
new file mode 100644
index 0000000000..1dabcd034b
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedExceptionReference.java
@@ -0,0 +1,24 @@
+package org.eclipse.jdt.internal.codeassist.complete;
+
+public class CompletionOnQualifiedExceptionReference
+ extends CompletionOnQualifiedTypeReference {
+ public CompletionOnQualifiedExceptionReference(
+ char[][] previousIdentifiers,
+ char[] completionIdentifier,
+ long[] positions) {
+ super(previousIdentifiers, completionIdentifier, positions);
+ }
+
+ public String toStringExpression(int tab) {
+
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("<CompleteOnException:");
+ for (int i = 0; i < tokens.length; i++) {
+ buffer.append(tokens[i]);
+ buffer.append(".");
+ }
+ buffer.append(completionIdentifier).append(">");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedNameReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedNameReference.java
new file mode 100644
index 0000000000..72d94b435d
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedNameReference.java
@@ -0,0 +1,89 @@
+package org.eclipse.jdt.internal.codeassist.complete;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Completion node build by the parser in any case it was intending to
+ * reduce a qualified name reference containing the completion identifier.
+ * e.g.
+ *
+ * class X {
+ * Y y;
+ * void foo() {
+ * y.fred.ba[cursor]
+ * }
+ * }
+ *
+ * ---> class X {
+ * Y y;
+ * void foo() {
+ * <CompleteOnName:y.fred.ba>
+ * }
+ * }
+ *
+ * The source range of the completion node denotes the source range
+ * which should be replaced by the completion.
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class CompletionOnQualifiedNameReference
+ extends QualifiedNameReference {
+ public char[] completionIdentifier;
+ public long[] sourcePositions;
+ // positions of each token, the last one being the positions of the completion identifier
+ public CompletionOnQualifiedNameReference(
+ char[][] previousIdentifiers,
+ char[] completionIdentifier,
+ long[] positions) {
+ super(
+ previousIdentifiers,
+ (int) (positions[0] >>> 32),
+ (int) positions[positions.length - 1]);
+ this.completionIdentifier = completionIdentifier;
+ this.sourcePositions = positions;
+ }
+
+ public CompletionOnQualifiedNameReference(
+ char[][] previousIdentifiers,
+ char[] completionIdentifier,
+ int sourceStart,
+ int sourceEnd) {
+ super(previousIdentifiers, sourceStart, sourceEnd);
+ this.completionIdentifier = completionIdentifier;
+ this.sourcePositions = new long[] {(sourceStart << 32) + sourceEnd };
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ // it can be a package, type, member type, local variable or field
+ binding = scope.getBinding(tokens, this);
+ if (!binding.isValidBinding()) {
+ if (binding instanceof ProblemFieldBinding) {
+ scope.problemReporter().invalidField(this, (FieldBinding) binding);
+ } else
+ if (binding instanceof ProblemReferenceBinding) {
+ scope.problemReporter().invalidType(this, (TypeBinding) binding);
+ } else {
+ scope.problemReporter().unresolvableReference(this, binding);
+ }
+ throw new CompletionNodeFound();
+ }
+
+ throw new CompletionNodeFound(this, binding, scope);
+ }
+
+ public String toStringExpression() {
+
+ StringBuffer buffer = new StringBuffer("<CompleteOnName:");
+ for (int i = 0; i < tokens.length; i++) {
+ buffer.append(tokens[i]);
+ buffer.append(".");
+ }
+ buffer.append(completionIdentifier).append(">");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedTypeReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedTypeReference.java
new file mode 100644
index 0000000000..d6f47e706e
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedTypeReference.java
@@ -0,0 +1,69 @@
+package org.eclipse.jdt.internal.codeassist.complete;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Completion node build by the parser in any case it was intending to
+ * reduce a type reference containing the completion identifier as part
+ * of a qualified name.
+ * e.g.
+ *
+ * class X extends java.lang.Obj[cursor]
+ *
+ * ---> class X extends <CompleteOnType:java.lang.Obj>
+ *
+ * The source range of the completion node denotes the source range
+ * which should be replaced by the completion.
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class CompletionOnQualifiedTypeReference
+ extends QualifiedTypeReference {
+ public char[] completionIdentifier;
+ public CompletionOnQualifiedTypeReference(
+ char[][] previousIdentifiers,
+ char[] completionIdentifier,
+ long[] positions) {
+ super(previousIdentifiers, positions);
+ this.completionIdentifier = completionIdentifier;
+ }
+
+ public void aboutToResolve(Scope scope) {
+ getTypeBinding(scope.parent); // step up from the ClassScope
+ }
+
+ /*
+ * No expansion of the completion reference into an array one
+ */
+ public TypeReference copyDims(int dim) {
+ return this;
+ }
+
+ public TypeBinding getTypeBinding(Scope scope) {
+ // it can be a package, type or member type
+ Binding binding = scope.getTypeOrPackage(tokens);
+ if (!binding.isValidBinding()) {
+ scope.problemReporter().invalidType(this, (TypeBinding) binding);
+ throw new CompletionNodeFound();
+ }
+
+ throw new CompletionNodeFound(this, binding, scope);
+ }
+
+ public String toStringExpression(int tab) {
+
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("<CompleteOnType:");
+ for (int i = 0; i < tokens.length; i++) {
+ buffer.append(tokens[i]);
+ buffer.append(".");
+ }
+ buffer.append(completionIdentifier).append(">");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnSingleNameReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnSingleNameReference.java
new file mode 100644
index 0000000000..19ce6e36c8
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnSingleNameReference.java
@@ -0,0 +1,44 @@
+package org.eclipse.jdt.internal.codeassist.complete;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Completion node build by the parser in any case it was intending to
+ * reduce a single name reference containing the completion identifier.
+ * e.g.
+ *
+ * class X {
+ * void foo() {
+ * ba[cursor]
+ * }
+ * }
+ *
+ * ---> class X {
+ * void foo() {
+ * <CompleteOnName:ba>
+ * }
+ * }
+ *
+ * The source range of the completion node denotes the source range
+ * which should be replaced by the completion.
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class CompletionOnSingleNameReference extends SingleNameReference {
+ public CompletionOnSingleNameReference(char[] source, long pos) {
+ super(source, pos);
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ throw new CompletionNodeFound(this, scope);
+ }
+
+ public String toStringExpression() {
+ return "<CompleteOnName:" + super.toStringExpression() + ">";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnSingleTypeReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnSingleTypeReference.java
new file mode 100644
index 0000000000..08c1b69122
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnSingleTypeReference.java
@@ -0,0 +1,55 @@
+package org.eclipse.jdt.internal.codeassist.complete;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Completion node build by the parser in any case it was intending to
+ * reduce a type reference containing the completion identifier as a single
+ * name reference.
+ * e.g.
+ *
+ * class X extends Obj[cursor]
+ *
+ * ---> class X extends <CompleteOnType:Obj>
+ *
+ * The source range of the completion node denotes the source range
+ * which should be replaced by the completion.
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class CompletionOnSingleTypeReference extends SingleTypeReference {
+ public CompletionOnSingleTypeReference(char[] source, long pos) {
+ super(source, pos);
+ }
+
+ public void aboutToResolve(Scope scope) {
+ getTypeBinding(scope.parent); // step up from the ClassScope
+ }
+
+ /*
+ * No expansion of the completion reference into an array one
+ */
+ public TypeReference copyDims(int dim) {
+ return this;
+ }
+
+ public TypeBinding getTypeBinding(Scope scope) {
+ throw new CompletionNodeFound(this, scope);
+ }
+
+ public TypeBinding resolveTypeEnclosing(
+ BlockScope scope,
+ ReferenceBinding enclosingType) {
+ throw new CompletionNodeFound(this, enclosingType, scope);
+ }
+
+ public String toStringExpression(int tab) {
+
+ return "<CompleteOnType:" + new String(token) + ">";
+ }
+
+}
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
new file mode 100644
index 0000000000..3678cc1533
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java
@@ -0,0 +1,1275 @@
+package org.eclipse.jdt.internal.codeassist.complete;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Parser able to build specific completion parse nodes, given a cursorLocation.
+ *
+ * Cursor location denotes the position of the last character behind which completion
+ * got requested:
+ * -1 means completion at the very beginning of the source
+ * 0 means completion behind the first character
+ * n means completion behind the n-th character
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.*;
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.parser.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.codeassist.impl.*;
+
+public class CompletionParser extends AssistParser {
+
+ /* public fields */
+
+ public int cursorLocation;
+ public char[][] labels; // the visible labels up to the cursor location
+
+ /* the following fields are internal flags */
+
+ boolean betweenNewAndLeftBraket;
+ // whether we are between the keyword 'new' and the following left braket, ie. '[', '(' or '{'
+ boolean betweenCatchAndRightParen;
+ // whether we are between the keyword 'catch' and the following ')'
+ boolean completionBehindDot;
+ // true when completion identifier immediately follows a dot
+
+ // the stacks of types and qualifiers for invocations (ie. method invocations, allocation expressions and
+ // explicit constructor invocations). They use the same stack pointer as the selector stack (ie. invocationPtr)
+ // the invocation type stack contains one of the invocation type constants below
+ // the qualifier stack contains pointers to the expression stack or -1 if there is no qualifier
+ // (a qualifier is the expression that qualifies a 'new', a 'super' constructor or a 'this' constructor
+ // or it is the receiver of a message send)
+ int[] invocationTypeStack = new int[StackIncrement];
+ int[] qualifierStack = new int[StackIncrement];
+
+ // invocation type constants
+ static final int EXPLICIT_RECEIVER = 0;
+ static final int NO_RECEIVER = -1;
+ static final int SUPER_RECEIVER = -2;
+ static final int NAME_RECEIVER = -3;
+ static final int ALLOCATION = -4;
+ static final int QUALIFIED_ALLOCATION = -5;
+
+ // the type of the current invocation (one of the invocation type constants)
+ int invocationType;
+
+ // a pointer in the expression stack to the qualifier of a invocation
+ int qualifier;
+
+ // a stack of label counters
+ // a new counter is pushed on the stack each time when a method (or a constructor) is entered,
+ // it is poped when the method (or constructor) is exited,
+ // it is incremented when a new label is defined
+ int labelCounterPtr;
+ int[] labelCounterStack = new int[StackIncrement];
+
+ // a stack of invocationPtr: contains the first invocationPtr of a block
+ // the current invocationPtr+1 is pushed when a block is entered
+ // it is poped when a block is exited
+ int blockInvocationPtr;
+ int[] blockInvocationStack = new int[StackIncrement];
+ public CompletionParser(ProblemReporter problemReporter) {
+ super(problemReporter);
+ }
+
+ public char[] assistIdentifier() {
+ return ((CompletionScanner) scanner).completionIdentifier;
+ }
+
+ protected void attachOrphanCompletionNode() {
+ if (this.isOrphanCompletionNode) {
+ AstNode orphan = this.assistNode;
+ this.isOrphanCompletionNode = false;
+
+ /* if in context of a type, then persists the identifier into a fake field return type */
+ if (currentElement instanceof RecoveredType) {
+ RecoveredType recoveredType = (RecoveredType) currentElement;
+ /* filter out cases where scanner is still inside type header */
+ if (recoveredType.foundOpeningBrace) {
+ /* generate a pseudo field with a completion on type reference */
+ if (orphan instanceof TypeReference) {
+ currentElement =
+ currentElement.add(new CompletionOnFieldType((TypeReference) orphan), 0);
+ return;
+ }
+ }
+ }
+ /* if in context of a method, persists if inside arguments as a type */
+ if (currentElement instanceof RecoveredMethod) {
+ RecoveredMethod recoveredMethod = (RecoveredMethod) currentElement;
+ /* only consider if inside method header */
+ if (!recoveredMethod.foundOpeningBrace) {
+ //if (rParenPos < lParenPos){ // inside arguments
+ if (orphan instanceof TypeReference) {
+ currentElement =
+ currentElement.parent.add(new CompletionOnFieldType((TypeReference) orphan), 0);
+ return;
+ }
+ }
+ }
+
+ // add the completion node to the method declaration or constructor declaration
+ if (orphan instanceof Statement) {
+ /* check for completion at the beginning of method body
+ behind an invalid signature
+ */
+ RecoveredMethod method = currentElement.enclosingMethod();
+ if (method != null) {
+ AbstractMethodDeclaration methodDecl = method.methodDeclaration;
+ if ((methodDecl.bodyStart == methodDecl.sourceEnd + 1)
+ // was missing opening brace
+ && (scanner.searchLineNumber(orphan.sourceStart)
+ == scanner.searchLineNumber(methodDecl.sourceEnd))) {
+ return;
+ }
+ }
+ // add the completion node as a statement to the list of block statements
+ currentElement = currentElement.add((Statement) orphan, 0);
+ return;
+ }
+ }
+
+ // the following code applies only in methods, constructors or initializers
+ if ((!this.inMethodStack[this.inMethodPtr]
+ && !this.inInitializerStack[this.inInitializerPtr])) {
+ return;
+ }
+
+ // push top expression on ast stack if it contains the completion node
+ Expression expression;
+ if (this.expressionPtr > -1
+ && containsCompletionNode(
+ expression = this.expressionStack[this.expressionPtr])) {
+ /* check for completion at the beginning of method body
+ behind an invalid signature
+ */
+ RecoveredMethod method = currentElement.enclosingMethod();
+ if (method != null) {
+ AbstractMethodDeclaration methodDecl = method.methodDeclaration;
+ if ((methodDecl.bodyStart == methodDecl.sourceEnd + 1)
+ // was missing opening brace
+ && (scanner.searchLineNumber(expression.sourceStart)
+ == scanner.searchLineNumber(methodDecl.sourceEnd))) {
+ return;
+ }
+ }
+ if (expression instanceof AllocationExpression) {
+ // keep the context if it is an allocation expression
+ Statement statement =
+ (Statement) wrapWithExplicitConstructorCallIfNeeded(expression);
+ currentElement = currentElement.add(statement, 0);
+ } else {
+ Statement statement =
+ (Statement) wrapWithExplicitConstructorCallIfNeeded(this.assistNode);
+ currentElement = currentElement.add(statement, 0);
+ }
+ }
+ }
+
+ public int bodyEnd(AbstractMethodDeclaration method) {
+ return cursorLocation;
+ }
+
+ public int bodyEnd(Initializer initializer) {
+ return cursorLocation;
+ }
+
+ /**
+ * Checks if the completion is on the exception type of a catch clause.
+ * Returns whether we found a completion node.
+ */
+ private boolean checkCatchClause() {
+ if (this.betweenCatchAndRightParen && this.identifierPtr > -1) {
+ // NB: if the cursor is on the variable, then it has been reduced (so identifierPtr is -1),
+ // thus this can only be a completion on the type of the catch clause
+ this.assistNode = getTypeReference(0);
+ this.lastCheckPoint = this.assistNode.sourceEnd + 1;
+ this.isOrphanCompletionNode = true;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Checks if the completion is on the type following a 'new'.
+ * Returns whether we found a completion node.
+ */
+ private boolean checkClassInstanceCreation() {
+ if (this.betweenNewAndLeftBraket) {
+ // completion on type inside an allocation expression
+ TypeReference type = getTypeReference(0);
+ this.assistNode = type;
+ this.lastCheckPoint = type.sourceEnd + 1;
+ if (this.invocationType == ALLOCATION) {
+ // non qualified allocation expression: attach it later
+ this.isOrphanCompletionNode = true;
+ } else {
+ // qualified allocation expression
+ QualifiedAllocationExpression allocExpr = new QualifiedAllocationExpression();
+ allocExpr.type = type;
+ allocExpr.enclosingInstance = this.expressionStack[this.qualifier];
+ allocExpr.sourceStart = this.intStack[this.intPtr--];
+ allocExpr.sourceEnd = type.sourceEnd;
+ this.expressionStack[this.qualifier] = allocExpr;
+ // attach it now (it replaces the qualifier expression)
+ this.isOrphanCompletionNode = false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Checks if the completion is on the dot following an array type,
+ * a primitive type or an primitive array type.
+ * Returns whether we found a completion node.
+ */
+ private boolean checkClassLiteralAccess() {
+ if (this.identifierLengthPtr >= 1
+ && this.previousToken == TokenNameDOT) {
+ // (NB: the top id length is 1 and it is for the completion identifier)
+ int length;
+ // if the penultimate id length is negative,
+ // the completion is after a primitive type or a primitive array type
+ if ((length = this.identifierLengthStack[this.identifierLengthPtr - 1]) < 0) {
+ // build the primitive type node
+ int dim = this.isAfterArrayType() ? this.intStack[this.intPtr--] : 0;
+ SingleTypeReference typeRef =
+ (SingleTypeReference) TypeReference.baseTypeReference(-length, dim);
+ typeRef.sourceStart = this.intStack[this.intPtr--];
+ //typeRef.sourceEnd = typeRef.sourceStart + typeRef.token.length; // NB: It's ok to use the length of the token since it doesn't contain any unicode
+
+ // find the completion identifier and its source positions
+ char[] source = identifierStack[identifierPtr];
+ long pos = this.identifierPositionStack[this.identifierPtr--];
+ this.identifierLengthPtr--;
+ // it can only be a simple identifier (so its length is one)
+
+ // build the completion on class literal access node
+ CompletionOnClassLiteralAccess access =
+ new CompletionOnClassLiteralAccess(pos, typeRef);
+ access.completionIdentifier = source;
+ this.identifierLengthPtr--;
+ // pop the length that was used to say it is a primitive type
+ this.assistNode = access;
+ this.isOrphanCompletionNode = true;
+ return true;
+ }
+
+ // if the completion is after a regular array type
+ if (isAfterArrayType()) {
+ // find the completion identifier and its source positions
+ char[] source = identifierStack[identifierPtr];
+ long pos = this.identifierPositionStack[this.identifierPtr--];
+ this.identifierLengthPtr--;
+ // it can only be a simple identifier (so its length is one)
+
+ // get the type reference
+ TypeReference typeRef = getTypeReference(this.intPtr--);
+
+ // build the completion on class literal access node
+ CompletionOnClassLiteralAccess access =
+ new CompletionOnClassLiteralAccess(pos, typeRef);
+ access.completionIdentifier = source;
+ this.assistNode = access;
+ this.isOrphanCompletionNode = true;
+ return true;
+ }
+
+ }
+ return false;
+ }
+
+ /**
+ * Checks if the completion is inside a method invocation or a constructor invocation.
+ * Returns whether we found a completion node.
+ */
+ private boolean checkInvocation() {
+ Expression topExpression =
+ this.expressionPtr >= 0 ? this.expressionStack[this.expressionPtr] : null;
+ boolean isEmptyNameCompletion = false;
+ boolean isEmptyAssistIdentifier = false;
+ int startInvocationPtr =
+ this.blockInvocationPtr >= 0
+ ? this.blockInvocationStack[this.blockInvocationPtr]
+ : 0;
+ if (this.invocationPtr >= startInvocationPtr
+ && ((isEmptyNameCompletion =
+ topExpression == this.assistNode
+ && this.isEmptyNameCompletion())
+ // eg. it is something like "this.fred([cursor]" but it is not something like "this.fred(1 + [cursor]"
+ || (isEmptyAssistIdentifier =
+ this.indexOfAssistIdentifier() >= 0
+ && this.identifierStack[this.identifierPtr].length == 0))) {
+ // eg. it is something like "this.fred(1 [cursor]"
+
+ // pop empty name completion
+ if (isEmptyNameCompletion) {
+ this.expressionPtr--;
+ this.expressionLengthStack[this.expressionLengthPtr]--;
+ } else
+ if (isEmptyAssistIdentifier) {
+ this.identifierPtr--;
+ this.identifierLengthPtr--;
+ }
+
+ // find receiver and qualifier
+ int invocationType = this.invocationTypeStack[this.invocationPtr];
+ int qualifierExprPtr = this.qualifierStack[this.invocationPtr];
+
+ // find arguments
+ int numArgs = this.expressionPtr - qualifierExprPtr;
+ int argStart = qualifierExprPtr + 1;
+ Expression[] arguments = null;
+ if (numArgs > 0) {
+ // remember the arguments
+ arguments = new Expression[numArgs];
+ System.arraycopy(this.expressionStack, argStart, arguments, 0, numArgs);
+
+ // consume the expression arguments
+ this.expressionPtr -= numArgs;
+ int count = numArgs;
+ while (count > 0) {
+ count -= this.expressionLengthStack[this.expressionLengthPtr--];
+ }
+ }
+
+ // build ast node
+ if (invocationType != ALLOCATION && invocationType != QUALIFIED_ALLOCATION) {
+ // creates completion on message send
+ CompletionOnMessageSend messageSend = new CompletionOnMessageSend();
+ messageSend.arguments = arguments;
+ switch (invocationType) {
+ case NO_RECEIVER :
+ // implicit this
+ messageSend.receiver = ThisReference.ThisImplicit;
+ break;
+ case NAME_RECEIVER :
+ // remove selector
+ this.identifierPtr--;
+ this.identifierLengthStack[this.identifierLengthPtr]--;
+ // consume the receiver
+ messageSend.receiver = this.getUnspecifiedReference();
+ break;
+ case SUPER_RECEIVER :
+ messageSend.receiver = SuperReference.Super;
+ break;
+ case EXPLICIT_RECEIVER :
+ messageSend.receiver = this.expressionStack[qualifierExprPtr];
+ }
+
+ // set selector
+ messageSend.selector =
+ this.identifierStack[this.selectorStack[this.invocationPtr]];
+ // remove selector
+ if (this.identifierLengthPtr >= 0
+ && this.identifierLengthStack[this.identifierLengthPtr] == 1) {
+ this.identifierPtr--;
+ this.identifierLengthPtr--;
+ }
+
+ // no source is going to be replaced
+ messageSend.sourceStart = this.cursorLocation + 1;
+ messageSend.sourceEnd = this.cursorLocation;
+
+ // remember the message send as an orphan completion node
+ this.assistNode = messageSend;
+ this.lastCheckPoint = messageSend.sourceEnd + 1;
+ this.isOrphanCompletionNode = true;
+ return true;
+ } else {
+ int selectorPtr = this.selectorStack[this.invocationPtr];
+ if (selectorPtr == THIS_CONSTRUCTOR || selectorPtr == SUPER_CONSTRUCTOR) {
+ // creates an explicit constructor call
+ CompletionOnExplicitConstructorCall call =
+ new CompletionOnExplicitConstructorCall(
+ (selectorPtr == THIS_CONSTRUCTOR)
+ ? ExplicitConstructorCall.This
+ : ExplicitConstructorCall.Super);
+ call.arguments = arguments;
+ if (invocationType == QUALIFIED_ALLOCATION) {
+ call.qualification = this.expressionStack[qualifierExprPtr];
+ }
+
+ // no source is going to be replaced
+ call.sourceStart = this.cursorLocation + 1;
+ call.sourceEnd = this.cursorLocation;
+
+ // remember the explicit constructor call as an orphan completion node
+ this.assistNode = call;
+ this.lastCheckPoint = call.sourceEnd + 1;
+ this.isOrphanCompletionNode = true;
+ return true;
+ } else {
+ // creates an allocation expression
+ CompletionOnQualifiedAllocationExpression allocExpr =
+ new CompletionOnQualifiedAllocationExpression();
+ allocExpr.arguments = arguments;
+ allocExpr.type = super.getTypeReference(0);
+ // we don't want a completion node here, so call super
+ if (invocationType == QUALIFIED_ALLOCATION) {
+ allocExpr.enclosingInstance = this.expressionStack[qualifierExprPtr];
+ }
+ // no source is going to be replaced
+ allocExpr.sourceStart = this.cursorLocation + 1;
+ allocExpr.sourceEnd = this.cursorLocation;
+
+ // remember the allocation expression as an orphan completion node
+ this.assistNode = allocExpr;
+ this.lastCheckPoint = allocExpr.sourceEnd + 1;
+ this.isOrphanCompletionNode = true;
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks if the completion is on a member access (ie. in an identifier following a dot).
+ * Returns whether we found a completion node.
+ */
+ private boolean checkMemberAccess() {
+ if (this.previousToken == TokenNameDOT
+ && this.qualifier > -1
+ && this.expressionPtr == this.qualifier) {
+ // the receiver is an expression
+ pushCompletionOnMemberAccessOnExpressionStack(false);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Checks if the completion is on a name reference.
+ * Returns whether we found a completion node.
+ */
+ private boolean checkNameCompletion() {
+ /*
+ We didn't find any other completion, but the completion identifier is on the identifier stack,
+ so it can only be a completion on name.
+ Note that we allow the completion on a name even if nothing is expected (eg. foo() b[cursor] would
+ be a completion on 'b'). This policy gives more to the user than he/she would expect, but this
+ simplifies the problem. To fix this, the recovery must be changed to work at a 'statement' granularity
+ instead of at the 'expression' granularity as it does right now.
+ */
+
+ // NB: at this point the completion identifier is on the identifier stack
+ this.assistNode = getUnspecifiedReferenceOptimized();
+ this.lastCheckPoint = this.assistNode.sourceEnd + 1;
+ this.isOrphanCompletionNode = true;
+ return true;
+ }
+
+ /**
+ * Checks if the completion is in the context of a method and on the type of one of its arguments
+ * Returns whether we found a completion node.
+ */
+ private boolean checkRecoveredMethod() {
+ if (currentElement instanceof RecoveredMethod) {
+ /* check if current awaiting identifier is the completion identifier */
+ if (this.indexOfAssistIdentifier() < 0)
+ return false;
+
+ /* check if on line with an error already - to avoid completing inside
+ illegal type names e.g. int[<cursor> */
+ if (lastErrorEndPosition <= cursorLocation + 1
+ && scanner.searchLineNumber(lastErrorEndPosition)
+ == scanner.searchLineNumber(
+ ((CompletionScanner) scanner).completedIdentifierStart)) {
+ return false;
+ }
+ RecoveredMethod recoveredMethod = (RecoveredMethod) currentElement;
+ /* only consider if inside method header */
+ if (!recoveredMethod.foundOpeningBrace && lastIgnoredToken == -1) {
+ //if (rParenPos < lParenPos){ // inside arguments
+ this.assistNode = this.getTypeReference(0);
+ this.lastCheckPoint = this.assistNode.sourceEnd + 1;
+ this.isOrphanCompletionNode = true;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks if the completion is in the context of a type and on a type reference in this type.
+ * Persists the identifier into a fake field return type
+ * Returns whether we found a completion node.
+ */
+ private boolean checkRecoveredType() {
+ if (currentElement instanceof RecoveredType) {
+ /* check if current awaiting identifier is the completion identifier */
+ if (this.indexOfAssistIdentifier() < 0)
+ return false;
+
+ /* check if on line with an error already - to avoid completing inside
+ illegal type names e.g. int[<cursor> */
+ if ((lastErrorEndPosition <= cursorLocation + 1)
+ && scanner.searchLineNumber(lastErrorEndPosition)
+ == scanner.searchLineNumber(
+ ((CompletionScanner) scanner).completedIdentifierStart)) {
+ return false;
+ }
+ RecoveredType recoveredType = (RecoveredType) currentElement;
+ /* filter out cases where scanner is still inside type header */
+ if (recoveredType.foundOpeningBrace) {
+ this.assistNode = this.getTypeReference(0);
+ this.lastCheckPoint = this.assistNode.sourceEnd + 1;
+ this.isOrphanCompletionNode = true;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /*
+ * Check whether about to shift beyond the completion token.
+ * If so, depending on the context, a special node might need to be created
+ * and attached to the existing recovered structure so as to be remember in the
+ * resulting parsed structure.
+ */
+ public void completionIdentifierCheck() {
+
+ if (checkRecoveredType())
+ return;
+ if (checkRecoveredMethod())
+ return;
+
+ // if not in a method in non diet mode and if not inside a field initializer, only record references attached to types
+ if (!(this.inMethodStack[this.inMethodPtr] && !this.diet)
+ && !insideFieldInitializer())
+ return;
+
+ /*
+ In some cases, the completion identifier may not have yet been consumed,
+ e.g. int.[cursor]
+ This is because the grammar does not allow any (empty) identifier to follow
+ a base type. We thus have to manually force the identifier to be consumed
+ (i.e. pushed).
+ */
+ if (assistIdentifier() == null
+ && this.currentToken == TokenNameIdentifier) {
+ // Test below copied from CompletionScanner.getCurrentIdentifierSource()
+ if (cursorLocation < this.scanner.startPosition
+ && this.scanner.currentPosition == this.scanner.startPosition) {
+ // fake empty identifier got issued
+ this.pushIdentifier();
+ } else
+ if (cursorLocation + 1 >= this.scanner.startPosition
+ && cursorLocation < this.scanner.currentPosition) {
+ this.pushIdentifier();
+ }
+ }
+
+ // check for different scenarii
+ try {
+ // no need to go further if we found a non empty completion node
+ // (we still need to store labels though)
+ if (this.assistNode != null) {
+ // however inside an invocation, the completion identifier may already have been consumed into an empty name
+ // completion, so this check should be before we check that we are at the cursor location
+ if (!isEmptyNameCompletion() || checkInvocation())
+ return;
+ }
+
+ // no need to check further if we are not at the cursor location
+ if (this.indexOfAssistIdentifier() < 0)
+ return;
+
+ if (checkClassInstanceCreation())
+ return;
+ if (checkCatchClause())
+ return;
+ if (checkMemberAccess())
+ return;
+ if (checkClassLiteralAccess())
+ return;
+
+ // if the completion was not on an empty name, it can still be inside an invocation (eg. this.fred("abc"[cursor])
+ // (NB: Put this check before checkNameCompletion() because the selector of the invocation can be on the identifier stack)
+ if (checkInvocation())
+ return;
+
+ if (checkNameCompletion())
+ return;
+ } finally {
+ storeLabelsIfNeeded();
+ }
+ }
+
+ protected void consumeCaseLabel() {
+ Expression caseExpression = this.expressionStack[this.expressionPtr];
+ if (caseExpression instanceof SingleNameReference
+ || caseExpression instanceof QualifiedNameReference) {
+ // label counter was wrongly incremented in consumeToken
+ if (this.labelCounterPtr >= 0)
+ this.labelCounterStack[this.labelCounterPtr]--;
+ }
+ super.consumeCaseLabel();
+ }
+
+ protected void consumeConditionalExpression(int op) {
+ Expression valueIfTrue = this.expressionStack[this.expressionPtr - 1];
+ if (valueIfTrue instanceof SingleNameReference
+ || valueIfTrue instanceof QualifiedNameReference) {
+ // label counter was wrongly incremented in consumeToken
+ if (this.labelCounterPtr >= 0)
+ this.labelCounterStack[this.labelCounterPtr]--;
+ }
+ super.consumeConditionalExpression(op);
+ }
+
+ protected void consumeConstructorBody() {
+ super.consumeConstructorBody();
+ this.labelCounterPtr--;
+ }
+
+ protected void consumeConstructorHeaderName() {
+
+ int index;
+
+ /* no need to take action if not inside assist identifiers */
+ if ((index = indexOfAssistIdentifier()) < 0) {
+ super.consumeConstructorHeaderName();
+ return;
+ }
+
+ /* force to start recovering in order to get fake field behavior */
+ if (currentElement == null) {
+ this.hasReportedError = true; // do not report any error
+ }
+ this.restartRecovery = true;
+ }
+
+ /*
+ * Copy of code from superclass with the following change:
+ * If the cursor location is on the field access, then create a
+ * CompletionOnMemberAccess instead.
+ */
+ protected void consumeFieldAccess(boolean isSuperAccess) {
+ // FieldAccess ::= Primary '.' 'Identifier'
+ // FieldAccess ::= 'super' '.' 'Identifier'
+
+ // potential receiver is being poped, so reset potential receiver
+ this.invocationType = NO_RECEIVER;
+
+ if (this.indexOfAssistIdentifier() < 0) {
+ super.consumeFieldAccess(isSuperAccess);
+ } else {
+ this.pushCompletionOnMemberAccessOnExpressionStack(isSuperAccess);
+ }
+ }
+
+ protected void consumeMethodBody() {
+ super.consumeMethodBody();
+ this.labelCounterPtr--;
+ }
+
+ protected void consumeNestedMethod() {
+ super.consumeNestedMethod();
+ this.pushNewLabelCounter();
+ }
+
+ protected void consumeStatementLabel() {
+ super.consumeStatementLabel();
+ if (this.labelCounterPtr >= 0)
+ this.labelCounterStack[this.labelCounterPtr]--;
+ }
+
+ protected void consumeToken(int token) {
+ int previous = this.previousToken;
+ int previousIdentifierPtr = this.previousIdentifierPtr;
+ super.consumeToken(token);
+
+ // if in field initializer (directly or not), on the completion identifier and not in recovery mode yet
+ // then position end of file at cursor location (so that we have the same behavior as
+ // in method bodies)
+ if (token == TokenNameIdentifier
+ && this.identifierStack[this.identifierPtr] == assistIdentifier()
+ && this.currentElement == null
+ && this.insideFieldInitializer()) {
+ this.scanner.eofPosition = cursorLocation + 1;
+ }
+
+ // if in a method or if in a field initializer
+ if (this.inMethodStack[this.inMethodPtr]
+ || this.inInitializerStack[this.inInitializerPtr]) {
+ switch (token) {
+ case TokenNameDOT :
+ switch (previous) {
+ case TokenNamethis : // eg. this[.]fred()
+ this.invocationType = EXPLICIT_RECEIVER;
+ break;
+ case TokenNamesuper : // eg. super[.]fred()
+ this.invocationType = SUPER_RECEIVER;
+ break;
+ case TokenNameIdentifier : // eg. bar[.]fred()
+ if (!this.betweenNewAndLeftBraket) { // eg. not new z.y[.]X()
+ if (this.identifierPtr != previousIdentifierPtr) {
+ // if identifier has been consumed, eg. this.x[.]fred()
+ this.invocationType = EXPLICIT_RECEIVER;
+ } else {
+ this.invocationType = NAME_RECEIVER;
+ }
+ }
+ break;
+ }
+ break;
+ case TokenNameIdentifier :
+ if (previous == TokenNameDOT) { // eg. foo().[fred]()
+ // if current identifier is the empty completion one
+ if (identifierStack[identifierPtr]
+ == CompletionScanner.EmptyCompletionIdentifier) {
+ this.completionBehindDot = true;
+ }
+ if (this.invocationType != SUPER_RECEIVER // eg. not super.[fred]()
+ && this.invocationType != NAME_RECEIVER // eg. not bar.[fred]()
+ && this.invocationType != ALLOCATION // eg. not new foo.[Bar]()
+ && this.invocationType != QUALIFIED_ALLOCATION) {
+ // eg. not fred().new foo.[Bar]()
+
+ this.invocationType = EXPLICIT_RECEIVER;
+ this.qualifier = this.expressionPtr;
+ }
+ }
+ break;
+ case TokenNamenew :
+ this.betweenNewAndLeftBraket = true;
+ this.qualifier = this.expressionPtr;
+ // NB: even if there is no qualification, set it to the expression ptr so that the number of arguments are correctly computed
+ if (previous == TokenNameDOT) { // eg. fred().[new] X()
+ this.invocationType = QUALIFIED_ALLOCATION;
+ } else { // eg. [new] X()
+ this.invocationType = ALLOCATION;
+ }
+ break;
+ case TokenNamethis :
+ if (previous == TokenNameDOT) { // eg. fred().[this]()
+ this.invocationType = QUALIFIED_ALLOCATION;
+ this.qualifier = this.expressionPtr;
+ }
+ break;
+ case TokenNamesuper :
+ if (previous == TokenNameDOT) { // eg. fred().[super]()
+ this.invocationType = QUALIFIED_ALLOCATION;
+ this.qualifier = this.expressionPtr;
+ }
+ break;
+ case TokenNamecatch :
+ this.betweenCatchAndRightParen = true;
+ break;
+ case TokenNameLPAREN :
+ this.betweenNewAndLeftBraket = false;
+ if (this.invocationType == NO_RECEIVER
+ || this.invocationType == NAME_RECEIVER) {
+ this.qualifier = this.expressionPtr;
+ // remenber the last expression so that arguments are correctly computed
+ }
+ switch (previous) {
+ case TokenNameIdentifier : // eg. fred[(]) or foo.fred[(])
+ this.pushOnInvocationStacks(this.invocationType, this.qualifier);
+ this.invocationType = NO_RECEIVER;
+ break;
+ case TokenNamethis : // explicit constructor invocation, eg. this[(]1, 2)
+ this.pushOnInvocationStacks(
+ (this.invocationType == QUALIFIED_ALLOCATION)
+ ? QUALIFIED_ALLOCATION
+ : ALLOCATION,
+ this.qualifier);
+ this.invocationType = NO_RECEIVER;
+ break;
+ case TokenNamesuper : // explicit constructor invocation, eg. super[(]1, 2)
+ this.pushOnInvocationStacks(
+ (this.invocationType == QUALIFIED_ALLOCATION)
+ ? QUALIFIED_ALLOCATION
+ : ALLOCATION,
+ this.qualifier);
+ this.invocationType = NO_RECEIVER;
+ break;
+ }
+ break;
+ case TokenNameLBRACE :
+ this.betweenNewAndLeftBraket = false;
+ this.pushBlockInvocationPtr();
+ break;
+ case TokenNameLBRACKET :
+ this.betweenNewAndLeftBraket = false;
+ break;
+ case TokenNameRBRACE :
+ if (this.blockInvocationPtr >= 0)
+ this.blockInvocationPtr--;
+ break;
+ case TokenNameRPAREN :
+ this.betweenCatchAndRightParen = false;
+ break;
+ case TokenNameCOLON :
+ if (previous == TokenNameIdentifier) {
+ if (this.labelCounterPtr >= 0)
+ this.labelCounterStack[this.labelCounterPtr]++;
+ }
+ break;
+ }
+ }
+ }
+
+ /**
+ * Return whether the given ast node contains the completion node.
+ */
+ private boolean containsCompletionNode(AstNode ast) {
+ if (this.assistNode == null || ast instanceof Literal) {
+ return false;
+ }
+ if (this.assistNode == ast) {
+ return true;
+ }
+ if (ast instanceof Reference || ast instanceof TypeReference) {
+ return ast == this.assistNode;
+ }
+ if (ast instanceof Assignment) {
+ Assignment assign = (Assignment) ast;
+ return containsCompletionNode(assign.lhs)
+ || containsCompletionNode(assign.expression);
+ }
+ if (ast instanceof UnaryExpression) {
+ UnaryExpression unary = (UnaryExpression) ast;
+ return containsCompletionNode(unary.expression);
+ }
+ if (ast instanceof BinaryExpression) {
+ BinaryExpression binary = (BinaryExpression) ast;
+ return containsCompletionNode(binary.left)
+ || containsCompletionNode(binary.right);
+ }
+ if (ast instanceof InstanceOfExpression) {
+ InstanceOfExpression instanceOfExpr = (InstanceOfExpression) ast;
+ return containsCompletionNode(instanceOfExpr.expression)
+ || containsCompletionNode(instanceOfExpr.type);
+ }
+ if (ast instanceof ConditionalExpression) {
+ ConditionalExpression conditional = (ConditionalExpression) ast;
+ return containsCompletionNode(conditional.condition)
+ || containsCompletionNode(conditional.valueIfTrue)
+ || containsCompletionNode(conditional.valueIfFalse);
+ }
+ if (ast instanceof AllocationExpression) {
+ AllocationExpression alloc = (AllocationExpression) ast;
+ return containsCompletionNode(alloc.type);
+ }
+ if (ast instanceof CastExpression) {
+ CastExpression cast = (CastExpression) ast;
+ return containsCompletionNode(cast.expression)
+ || containsCompletionNode(cast.type);
+ }
+ if (ast instanceof ExplicitConstructorCall) {
+ ExplicitConstructorCall call = (ExplicitConstructorCall) ast;
+ Expression[] arguments = call.arguments;
+ if (arguments != null) {
+ for (int i = 0; i < arguments.length; i++) {
+ if (containsCompletionNode(arguments[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+ return false;
+ }
+
+ public ImportReference createAssistImportReference(
+ char[][] tokens,
+ long[] positions) {
+ return new CompletionOnImportReference(tokens, positions);
+ }
+
+ public ImportReference createAssistPackageReference(
+ char[][] tokens,
+ long[] positions) {
+ return new CompletionOnPackageReference(tokens, positions);
+ }
+
+ public NameReference createQualifiedAssistNameReference(
+ char[][] previousIdentifiers,
+ char[] name,
+ long[] positions) {
+ return new CompletionOnQualifiedNameReference(
+ previousIdentifiers,
+ name,
+ positions);
+ }
+
+ public TypeReference createQualifiedAssistTypeReference(
+ char[][] previousIdentifiers,
+ char[] name,
+ long[] positions) {
+ return this.betweenCatchAndRightParen // check for exception scenario
+ ? new CompletionOnQualifiedExceptionReference(
+ previousIdentifiers,
+ name,
+ positions)
+ : new CompletionOnQualifiedTypeReference(previousIdentifiers, name, positions);
+ }
+
+ public NameReference createSingleAssistNameReference(
+ char[] name,
+ long position) {
+ return new CompletionOnSingleNameReference(name, position);
+ }
+
+ public TypeReference createSingleAssistTypeReference(
+ char[] name,
+ long position) {
+ return this.betweenCatchAndRightParen // check for exception scenario
+ ? new CompletionOnExceptionReference(name, position)
+ : new CompletionOnSingleTypeReference(name, position);
+ }
+
+ public CompilationUnitDeclaration dietParse(
+ ICompilationUnit sourceUnit,
+ CompilationResult compilationResult,
+ int cursorLocation) {
+
+ this.cursorLocation = cursorLocation;
+ CompletionScanner completionScanner = (CompletionScanner) this.scanner;
+ completionScanner.completionIdentifier = null;
+ completionScanner.cursorLocation = cursorLocation;
+ return this.dietParse(sourceUnit, compilationResult);
+ }
+
+ /*
+ * Flush parser/scanner state regarding to code assist
+ */
+ public void flushAssistState() {
+
+ super.flushAssistState();
+ this.isOrphanCompletionNode = false;
+ this.setAssistIdentifier(null);
+ CompletionScanner completionScanner = (CompletionScanner) this.scanner;
+ completionScanner.completedIdentifierStart = 0;
+ completionScanner.completedIdentifierEnd = -1;
+ }
+
+ protected NameReference getUnspecifiedReferenceOptimized() {
+ if (this.identifierLengthStack[this.identifierLengthPtr] > 1) {
+ // reducing a qualified name
+ // potential receiver is being poped, so reset potential receiver
+ this.invocationType = NO_RECEIVER;
+ }
+ return super.getUnspecifiedReferenceOptimized();
+ }
+
+ /**
+ * Return whether the given ast node has information interresting for code completion.
+ */
+ private boolean hasCompletionInformation(AstNode ast) {
+ return (
+ ast instanceof AbstractMethodDeclaration
+ || ast instanceof AbstractVariableDeclaration
+ || ast instanceof LabeledStatement
+ || ast instanceof TypeDeclaration);
+ }
+
+ public void initialize() {
+ super.initialize();
+ this.initializeForBlockStatements();
+ this.labelCounterPtr = -1;
+ }
+
+ /*
+ * Initializes the state of the parser that is about to go for BlockStatements.
+ */
+ private void initializeForBlockStatements() {
+ this.previousToken = -1;
+ this.previousIdentifierPtr = -1;
+ this.completionBehindDot = false;
+ this.betweenNewAndLeftBraket = false;
+ this.betweenCatchAndRightParen = false;
+ this.invocationType = NO_RECEIVER;
+ this.qualifier = -1;
+ this.blockInvocationPtr = -1;
+ }
+
+ public void initializeScanner() {
+ this.scanner = new CompletionScanner();
+ }
+
+ /**
+ * Returns whether we are directly or indirectly inside a field initializer.
+ */
+ private boolean insideFieldInitializer() {
+ for (int i = this.inInitializerPtr; i >= 0; i--) {
+ if (this.inInitializerStack[i]) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether the completion is just after an array type
+ * eg. String[].[cursor]
+ */
+ private boolean isAfterArrayType() {
+ // TBD: The following relies on the fact that array dimensions are small: it says that if the
+ // top of the intStack is less than 11, then it must be a dimension
+ // (smallest position of array type in a compilation unit is 11 as in "class X{Y[]")
+ int dim = 0;
+ if ((this.intPtr > -1) && (this.intStack[this.intPtr] < 11)) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isEmptyNameCompletion() {
+ return this.assistNode != null
+ && this.assistNode instanceof CompletionOnSingleNameReference
+ && (((CompletionOnSingleNameReference) this.assistNode).token.length == 0);
+ }
+
+ public CompilationUnitDeclaration parse(
+ ICompilationUnit sourceUnit,
+ CompilationResult compilationResult,
+ int cursorLocation) {
+
+ this.cursorLocation = cursorLocation;
+ CompletionScanner completionScanner = (CompletionScanner) this.scanner;
+ completionScanner.completionIdentifier = null;
+ completionScanner.cursorLocation = cursorLocation;
+ return this.parse(sourceUnit, compilationResult);
+ }
+
+ /*
+ * Prepares the state of the parser to go for BlockStatements.
+ */
+ protected void prepareForBlockStatements() {
+ super.prepareForBlockStatements();
+ this.initializeForBlockStatements();
+ }
+
+ protected void pushBlockInvocationPtr() {
+ try {
+ this.blockInvocationStack[++this.blockInvocationPtr] = this.invocationPtr + 1;
+ } catch (IndexOutOfBoundsException e) {
+ int oldStackLength = this.blockInvocationStack.length;
+ int[] oldStack = this.labelCounterStack;
+ this.blockInvocationStack = new int[oldStackLength + StackIncrement];
+ System.arraycopy(oldStack, 0, this.blockInvocationStack, 0, oldStackLength);
+ this.blockInvocationStack[this.blockInvocationPtr] = this.invocationPtr + 1;
+ }
+ }
+
+ /**
+ * Creates a completion on member access node and push it
+ * on the expression stack.
+ */
+ private void pushCompletionOnMemberAccessOnExpressionStack(boolean isSuperAccess) {
+ char[] source = identifierStack[identifierPtr];
+ long pos = identifierPositionStack[identifierPtr--];
+ CompletionOnMemberAccess fr = new CompletionOnMemberAccess(source, pos);
+ this.assistNode = fr;
+ this.lastCheckPoint = fr.sourceEnd + 1;
+ identifierLengthPtr--;
+ if (isSuperAccess) { //considerates the fieldReference beginning at the 'super' ....
+ fr.sourceStart = intStack[intPtr--];
+ fr.receiver = new SuperReference(fr.sourceStart, endPosition);
+ pushOnExpressionStack(fr);
+ } else { //optimize push/pop
+ if ((fr.receiver = expressionStack[expressionPtr]).isThis()) {
+ //fieldreference begins at the this
+ fr.sourceStart = fr.receiver.sourceStart;
+ }
+ expressionStack[expressionPtr] = fr;
+ }
+ }
+
+ protected void pushNewLabelCounter() {
+ try {
+ this.labelCounterStack[++this.labelCounterPtr] = 0;
+ } catch (IndexOutOfBoundsException e) {
+ int oldStackLength = this.labelCounterStack.length;
+ int[] oldStack = this.labelCounterStack;
+ this.labelCounterStack = new int[oldStackLength + StackIncrement];
+ System.arraycopy(oldStack, 0, this.labelCounterStack, 0, oldStackLength);
+ this.labelCounterStack[this.labelCounterPtr] = 0;
+ }
+ }
+
+ /**
+ * Pushes the given invocation type (one of the invocation type constants) on the invocation type stack,
+ * and the given qualifier (an expression pointer to the expression stack) on the qualifier stack.
+ */
+ protected void pushOnInvocationStacks(
+ int invocationType,
+ int qualifierExprPtr) {
+ // NB: invocationPtr has already been incremented by a call to pushOnSelectorStack()
+ try {
+ this.invocationTypeStack[this.invocationPtr] = invocationType;
+ this.qualifierStack[this.invocationPtr] = qualifierExprPtr;
+ } catch (IndexOutOfBoundsException e) {
+ int oldStackLength = this.invocationTypeStack.length;
+ int oldInvocationTypeStack[] = this.invocationTypeStack;
+ int oldQualifierStack[] = this.qualifierStack;
+ this.invocationTypeStack = new int[oldStackLength + StackIncrement];
+ this.qualifierStack = new int[oldStackLength + StackIncrement];
+ System.arraycopy(
+ oldInvocationTypeStack,
+ 0,
+ this.invocationTypeStack,
+ 0,
+ oldStackLength);
+ System.arraycopy(oldQualifierStack, 0, this.qualifierStack, 0, oldStackLength);
+ this.invocationTypeStack[this.invocationPtr] = invocationType;
+ this.qualifierStack[this.invocationPtr] = qualifierExprPtr;
+ }
+ }
+
+ public void recordCompletionOnReference() {
+
+ if (currentElement instanceof RecoveredType) {
+ RecoveredType recoveredType = (RecoveredType) currentElement;
+
+ /* filter out cases where scanner is still inside type header */
+ if (!recoveredType.foundOpeningBrace)
+ return;
+
+ /* generate a pseudo field with a completion on type reference */
+ currentElement.add(new CompletionOnFieldType(this.getTypeReference(0)), 0);
+ return;
+ }
+ if (!diet)
+ return; // only record references attached to types
+
+ }
+
+ protected void reportSyntaxError(int act, int currentKind, int stateStackTop) {
+
+ /* Intercept error state on EOF inside method bodies, due to
+ cursor location being used as an EOF position.
+ */
+ if (!diet && currentToken == TokenNameEOF)
+ return;
+ super.reportSyntaxError(act, currentKind, stateStackTop);
+ }
+
+ /*
+ * Reset internal state after completion is over
+ */
+
+ public void reset() {
+ super.reset();
+ this.cursorLocation = 0;
+ }
+
+ /*
+ * Reset internal state after completion is over
+ */
+
+ public void resetAfterCompletion() {
+ this.cursorLocation = 0;
+ this.flushAssistState();
+ }
+
+ /*
+ * Reset context so as to resume to regular parse loop
+ * If unable to reset for resuming, answers false.
+ *
+ * Move checkpoint location, reset internal stacks and
+ * decide which grammar goal is activated.
+ */
+ protected boolean resumeAfterRecovery() {
+
+ if (this.assistNode != null) {
+ // if an assist node has been found and a recovered element exists,
+ // mark enclosing blocks as to be preserved
+ if (this.currentElement != null) {
+ currentElement.preserveEnclosingBlocks();
+ }
+ /* if reached [eof] inside method body, but still inside nested type,
+ or inside a field initializer, should continue in diet mode until
+ the end of the method body or compilation unit */
+ if ((scanner.eofPosition == cursorLocation + 1)
+ && (!(referenceContext instanceof CompilationUnitDeclaration)
+ || insideFieldInitializer())) {
+
+ /* disabled since does not handle possible field/message refs, i.e. Obj[ASSIST HERE]ect.registerNatives()
+ // consume extra tokens which were part of the qualified reference
+ // so that the replaced source comprises them as well
+ if (this.assistNode instanceof NameReference){
+ int oldEof = scanner.eofPosition;
+ scanner.eofPosition = currentElement.topElement().sourceEnd()+1;
+ scanner.currentPosition = this.cursorLocation+1;
+ int token = -1;
+ try {
+ do {
+ // first token might not have to be a dot
+ if (token >= 0 || !this.completionBehindDot){
+ if ((token = scanner.getNextToken()) != TokenNameDOT) break;
+ }
+ if ((token = scanner.getNextToken()) != TokenNameIdentifier) break;
+ this.assistNode.sourceEnd = scanner.currentPosition - 1;
+ } while (token != TokenNameEOF);
+ } catch (InvalidInputException e){
+ } finally {
+ scanner.eofPosition = oldEof;
+ }
+ }
+ */
+ /* restart in diet mode for finding sibling constructs */
+ if (currentElement.enclosingType() != null) {
+ lastCheckPoint = this.assistNode.sourceEnd + 1;
+ scanner.eofPosition = currentElement.topElement().sourceEnd() + 1;
+ } else {
+ this.resetStacks();
+ return false;
+ }
+ }
+ }
+ return super.resumeAfterRecovery();
+ }
+
+ public void setAssistIdentifier(char[] assistIdent) {
+ ((CompletionScanner) scanner).completionIdentifier = assistIdent;
+ }
+
+ /**
+ * Stores the labels left on the identifier stack if they have not been stored yet.
+ */
+ private void storeLabelsIfNeeded() {
+ int counter =
+ this.labelCounterPtr >= 0 ? this.labelCounterStack[this.labelCounterPtr] : 0;
+ if (this.labels == null && this.identifierPtr >= 0) {
+ this.labels = new char[counter][];
+ System.arraycopy(
+ this.identifierStack,
+ this.identifierPtr - counter + 1,
+ this.labels,
+ 0,
+ counter);
+ }
+ this.identifierPtr -= counter;
+ this.identifierLengthPtr -= counter; // labels have not been concatenated yet
+ }
+
+ /*
+ * Update recovery state based on current parser/scanner state
+ */
+ protected void updateRecoveryState() {
+
+ /* expose parser state to recovery state */
+ currentElement.updateFromParserState();
+
+ /* may be able to retrieve completionNode as an orphan, and then attach it */
+ this.completionIdentifierCheck();
+ this.attachOrphanCompletionNode();
+
+ /* check and update recovered state based on current token,
+ this action is also performed when shifting token after recovery
+ got activated once.
+ */
+ this.recoveryTokenCheck();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionScanner.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionScanner.java
new file mode 100644
index 0000000000..03c66cff23
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionScanner.java
@@ -0,0 +1,719 @@
+package org.eclipse.jdt.internal.codeassist.complete;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Scanner aware of a cursor location so as to discard trailing portions of identifiers
+ * containing the cursor location.
+ *
+ * Cursor location denotes the position of the last character behind which completion
+ * got requested:
+ * -1 means completion at the very beginning of the source
+ * 0 means completion behind the first character
+ * n means completion behind the n-th character
+ */
+import org.eclipse.jdt.internal.compiler.parser.*;
+
+public class CompletionScanner extends Scanner {
+
+ public char[] completionIdentifier;
+ public int cursorLocation;
+
+ /* Source positions of the completedIdentifier
+ * if inside actual identifier, end goes to the actual identifier
+ * end, i.e. beyond cursor location
+ */
+ public int completedIdentifierStart = 0;
+ public int completedIdentifierEnd = -1;
+
+ public static final char[] EmptyCompletionIdentifier = {
+ };
+
+ public CompletionScanner() {
+ super();
+ }
+
+ /*
+ * Truncate the current identifier if it is containing the cursor location. Since completion is performed
+ * on an identifier prefix.
+ *
+ */
+ public char[] getCurrentIdentifierSource() {
+
+ if (completionIdentifier == null) {
+ if (cursorLocation < startPosition
+ && currentPosition == startPosition) { // fake empty identifier got issued
+ // remember actual identifier positions
+ completedIdentifierStart = startPosition;
+ completedIdentifierEnd = completedIdentifierStart - 1;
+ return completionIdentifier = EmptyCompletionIdentifier;
+ }
+ if (cursorLocation + 1 >= startPosition && cursorLocation < currentPosition) {
+ // remember actual identifier positions
+ completedIdentifierStart = startPosition;
+ completedIdentifierEnd = currentPosition - 1;
+ if (withoutUnicodePtr != 0) { // check unicode scenario
+ System.arraycopy(
+ withoutUnicodeBuffer,
+ 1,
+ completionIdentifier = new char[withoutUnicodePtr],
+ 0,
+ withoutUnicodePtr);
+ } else {
+ int length = cursorLocation + 1 - startPosition;
+ // no char[] sharing around completionIdentifier, we want it to be unique so as to use identity checks
+ System.arraycopy(
+ source,
+ startPosition,
+ (completionIdentifier = new char[length]),
+ 0,
+ length);
+ }
+ return completionIdentifier;
+ }
+ }
+ return super.getCurrentIdentifierSource();
+ }
+
+ /*
+ * Identifier splitting for unicodes.
+ * Only store the current unicode if we did not pass the cursorLocation.
+ * Note: this does not handle cases where the cursor is in the middle of a unicode
+ */
+ public boolean getNextCharAsJavaIdentifierPart() {
+
+ int temp = currentPosition;
+ try {
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ //-------------unicode traitement ------------
+ int c1, c2, c3, c4;
+ int unicodeSize = 6;
+ currentPosition++;
+ while (source[currentPosition] == 'u') {
+ currentPosition++;
+ unicodeSize++;
+ }
+
+ if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c1 < 0)
+ || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15 || c2 < 0)
+ || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15 || c3 < 0)
+ || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15 || c4 < 0)) {
+ currentPosition = temp;
+ return false;
+ }
+
+ currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+ if (!Character.isJavaIdentifierPart(currentCharacter)) {
+ currentPosition = temp;
+ return false;
+ }
+
+ //need the unicode buffer
+ if (withoutUnicodePtr == 0) {
+ //buffer all the entries that have been left aside....
+ withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
+ System.arraycopy(
+ source,
+ startPosition,
+ withoutUnicodeBuffer,
+ 1,
+ withoutUnicodePtr);
+ }
+ if (temp < cursorLocation && cursorLocation < currentPosition - 1) {
+ throw new InvalidCursorLocation(
+ InvalidCursorLocation.NO_COMPLETION_INSIDE_UNICODE);
+ }
+ // store the current unicode, only if we did not pass the cursorLocation
+ // Note: this does not handle cases where the cursor is in the middle of a unicode
+ if ((completionIdentifier != null)
+ || (startPosition <= cursorLocation + 1
+ && cursorLocation >= currentPosition - 1)) {
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ }
+ return true;
+ } //-------------end unicode traitement--------------
+ else {
+ if (!Character.isJavaIdentifierPart(currentCharacter)) {
+ currentPosition = temp;
+ return false;
+ }
+
+ if (withoutUnicodePtr != 0) {
+ // store the current unicode, only if we did not pass the cursorLocation
+ // Note: this does not handle cases where the cursor is in the middle of a unicode
+ if ((completionIdentifier != null)
+ || (startPosition <= cursorLocation + 1
+ && cursorLocation >= currentPosition - 1)) {
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ }
+ }
+ return true;
+ }
+ } catch (IndexOutOfBoundsException e) {
+ currentPosition = temp;
+ return false;
+ }
+ }
+
+ public int getNextToken() throws InvalidInputException {
+
+ if (diet) {
+ jumpOverMethodBody();
+ diet = false;
+ return currentPosition > source.length ? TokenNameEOF : TokenNameRBRACE;
+ }
+ try {
+ while (true) { //loop for jumping over comments
+ withoutUnicodePtr = 0;
+ //start with a new token (even comment written with unicode )
+
+ // ---------Consume white space and handles startPosition---------
+ int whiteStart = currentPosition;
+ boolean isWhiteSpace, foundWhiteSpaces;
+ do {
+ startPosition = currentPosition;
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ isWhiteSpace = jumpOverUnicodeWhiteSpace();
+ } else {
+ if (recordLineSeparator
+ && ((currentCharacter == '\r') || (currentCharacter == '\n')))
+ pushLineSeparator();
+ isWhiteSpace =
+ (currentCharacter == ' ') || Character.isWhitespace(currentCharacter);
+ }
+ /* completion requesting strictly inside blanks */
+ if ((whiteStart != currentPosition) //&& (previousToken == TokenNameDOT)
+ && (completionIdentifier == null)
+ && (whiteStart <= cursorLocation + 1)
+ && (cursorLocation < startPosition)
+ && !Character.isJavaIdentifierStart(currentCharacter)) {
+ currentPosition = startPosition; // for next token read
+ return TokenNameIdentifier;
+ }
+ } while (isWhiteSpace);
+ if (tokenizeWhiteSpace && (whiteStart != currentPosition - 1)) {
+ // reposition scanner in case we are interested by spaces as tokens
+ currentPosition--;
+ startPosition = whiteStart;
+ return TokenNameWHITESPACE;
+ }
+ //little trick to get out in the middle of a source comptuation
+ if (currentPosition > eofPosition) {
+ /* might be completing at eof (e.g. behind a dot) */
+ if (completionIdentifier == null && startPosition == cursorLocation + 1) {
+ currentPosition = startPosition;
+ // for being detected as empty free identifier
+ return TokenNameIdentifier;
+ }
+ return TokenNameEOF;
+ }
+
+ // ---------Identify the next token-------------
+
+ switch (currentCharacter) {
+ case '(' :
+ return TokenNameLPAREN;
+ case ')' :
+ return TokenNameRPAREN;
+ case '{' :
+ return TokenNameLBRACE;
+ case '}' :
+ return TokenNameRBRACE;
+ case '[' :
+ return TokenNameLBRACKET;
+ case ']' :
+ return TokenNameRBRACKET;
+ case ';' :
+ return TokenNameSEMICOLON;
+ case ',' :
+ return TokenNameCOMMA;
+ case '.' :
+ if (getNextCharAsDigit())
+ return scanNumber(true);
+ return TokenNameDOT;
+ case '+' :
+ {
+ int test;
+ if ((test = getNextChar('+', '=')) == 0)
+ return TokenNamePLUS_PLUS;
+ if (test > 0)
+ return TokenNamePLUS_EQUAL;
+ return TokenNamePLUS;
+ }
+ case '-' :
+ {
+ int test;
+ if ((test = getNextChar('-', '=')) == 0)
+ return TokenNameMINUS_MINUS;
+ if (test > 0)
+ return TokenNameMINUS_EQUAL;
+ return TokenNameMINUS;
+ }
+ case '~' :
+ return TokenNameTWIDDLE;
+ case '!' :
+ if (getNextChar('='))
+ return TokenNameNOT_EQUAL;
+ return TokenNameNOT;
+ case '*' :
+ if (getNextChar('='))
+ return TokenNameMULTIPLY_EQUAL;
+ return TokenNameMULTIPLY;
+ case '%' :
+ if (getNextChar('='))
+ return TokenNameREMAINDER_EQUAL;
+ return TokenNameREMAINDER;
+ case '<' :
+ {
+ int test;
+ if ((test = getNextChar('=', '<')) == 0)
+ return TokenNameLESS_EQUAL;
+ if (test > 0) {
+ if (getNextChar('='))
+ return TokenNameLEFT_SHIFT_EQUAL;
+ return TokenNameLEFT_SHIFT;
+ }
+ return TokenNameLESS;
+ }
+ case '>' :
+ {
+ int test;
+ if ((test = getNextChar('=', '>')) == 0)
+ return TokenNameGREATER_EQUAL;
+ if (test > 0) {
+ if ((test = getNextChar('=', '>')) == 0)
+ return TokenNameRIGHT_SHIFT_EQUAL;
+ if (test > 0) {
+ if (getNextChar('='))
+ return TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL;
+ return TokenNameUNSIGNED_RIGHT_SHIFT;
+ }
+ return TokenNameRIGHT_SHIFT;
+ }
+ return TokenNameGREATER;
+ }
+ case '=' :
+ if (getNextChar('='))
+ return TokenNameEQUAL_EQUAL;
+ return TokenNameEQUAL;
+ case '&' :
+ {
+ int test;
+ if ((test = getNextChar('&', '=')) == 0)
+ return TokenNameAND_AND;
+ if (test > 0)
+ return TokenNameAND_EQUAL;
+ return TokenNameAND;
+ }
+ case '|' :
+ {
+ int test;
+ if ((test = getNextChar('|', '=')) == 0)
+ return TokenNameOR_OR;
+ if (test > 0)
+ return TokenNameOR_EQUAL;
+ return TokenNameOR;
+ }
+ case '^' :
+ if (getNextChar('='))
+ return TokenNameXOR_EQUAL;
+ return TokenNameXOR;
+ case '?' :
+ return TokenNameQUESTION;
+ case ':' :
+ return TokenNameCOLON;
+ case '\'' :
+ {
+ int test;
+ if ((test = getNextChar('\n', '\r')) == 0) {
+ throw new InvalidInputException(INVALID_CHARACTER_CONSTANT);
+ }
+ if (test > 0) {
+ // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
+ for (int lookAhead = 0; lookAhead < 3; lookAhead++) {
+ if (currentPosition + lookAhead == source.length)
+ break;
+ if (source[currentPosition + lookAhead] == '\n')
+ break;
+ if (source[currentPosition + lookAhead] == '\'') {
+ currentPosition += lookAhead + 1;
+ break;
+ }
+ }
+ throw new InvalidInputException(INVALID_CHARACTER_CONSTANT);
+ }
+ }
+ if (getNextChar('\'')) {
+ // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
+ for (int lookAhead = 0; lookAhead < 3; lookAhead++) {
+ if (currentPosition + lookAhead == source.length)
+ break;
+ if (source[currentPosition + lookAhead] == '\n')
+ break;
+ if (source[currentPosition + lookAhead] == '\'') {
+ currentPosition += lookAhead + 1;
+ break;
+ }
+ }
+ throw new InvalidInputException(INVALID_CHARACTER_CONSTANT);
+ }
+ if (getNextChar('\\'))
+ scanEscapeCharacter();
+ else { // consume next character
+ unicodeAsBackSlash = false;
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ getNextUnicodeChar();
+ } else {
+ if (withoutUnicodePtr != 0) {
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ }
+ }
+ }
+ if (getNextChar('\''))
+ return TokenNameCharacterLiteral;
+ // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
+ for (int lookAhead = 0; lookAhead < 20; lookAhead++) {
+ if (currentPosition + lookAhead == source.length)
+ break;
+ if (source[currentPosition + lookAhead] == '\n')
+ break;
+ if (source[currentPosition + lookAhead] == '\'') {
+ currentPosition += lookAhead + 1;
+ break;
+ }
+ }
+ throw new InvalidInputException(INVALID_CHARACTER_CONSTANT);
+ case '"' :
+ try {
+ // consume next character
+ unicodeAsBackSlash = false;
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ getNextUnicodeChar();
+ } else {
+ if (withoutUnicodePtr != 0) {
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ }
+ }
+
+ while (currentCharacter != '"') {
+ /**** \r and \n are not valid in string literals ****/
+ if ((currentCharacter == '\n') || (currentCharacter == '\r')) {
+ // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
+ for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
+ if (currentPosition + lookAhead == source.length)
+ break;
+ if (source[currentPosition + lookAhead] == '\n')
+ break;
+ if (source[currentPosition + lookAhead] == '\"') {
+ currentPosition += lookAhead + 1;
+ break;
+ }
+ }
+ throw new InvalidInputException(INVALID_CHAR_IN_STRING);
+ }
+ if (currentCharacter == '\\') {
+ int escapeSize = currentPosition;
+ boolean backSlashAsUnicodeInString = unicodeAsBackSlash;
+ //scanEscapeCharacter make a side effect on this value and we need the previous value few lines down this one
+ scanEscapeCharacter();
+ escapeSize = currentPosition - escapeSize;
+ if (withoutUnicodePtr == 0) {
+ //buffer all the entries that have been left aside....
+ withoutUnicodePtr = currentPosition - escapeSize - 1 - startPosition;
+ System.arraycopy(
+ source,
+ startPosition,
+ withoutUnicodeBuffer,
+ 1,
+ withoutUnicodePtr);
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ } else { //overwrite the / in the buffer
+ withoutUnicodeBuffer[withoutUnicodePtr] = currentCharacter;
+ if (backSlashAsUnicodeInString) { //there are TWO \ in the stream where only one is correct
+ withoutUnicodePtr--;
+ }
+ }
+ }
+ // consume next character
+ unicodeAsBackSlash = false;
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ getNextUnicodeChar();
+ } else {
+ if (withoutUnicodePtr != 0) {
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ }
+ }
+
+ }
+ } catch (IndexOutOfBoundsException e) {
+ throw new InvalidInputException(UNTERMINATED_STRING);
+ } catch (InvalidInputException e) {
+ if (e.getMessage().equals(INVALID_ESCAPE)) {
+ // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
+ for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
+ if (currentPosition + lookAhead == source.length)
+ break;
+ if (source[currentPosition + lookAhead] == '\n')
+ break;
+ if (source[currentPosition + lookAhead] == '\"') {
+ currentPosition += lookAhead + 1;
+ break;
+ }
+ }
+
+ }
+ throw e; // rethrow
+ }
+ if (startPosition <= cursorLocation && cursorLocation <= currentPosition - 1) {
+ throw new InvalidCursorLocation(
+ InvalidCursorLocation.NO_COMPLETION_INSIDE_STRING);
+ }
+ return TokenNameStringLiteral;
+ case '/' :
+ {
+ int test;
+ if ((test = getNextChar('/', '*')) == 0) { //line comment
+ try { //get the next char
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ //-------------unicode traitement ------------
+ int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
+ currentPosition++;
+ while (source[currentPosition] == 'u') {
+ currentPosition++;
+ }
+ if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c1 < 0
+ || (c2 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c2 < 0
+ || (c3 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c3 < 0
+ || (c4 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c4 < 0) {
+ throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
+ } else {
+ currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+ }
+ }
+
+ //handle the \\u case manually into comment
+ if (currentCharacter == '\\') {
+ if (source[currentPosition] == '\\')
+ currentPosition++;
+ } //jump over the \\
+ while (currentCharacter != '\r' && currentCharacter != '\n') {
+ //get the next char
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ //-------------unicode traitement ------------
+ int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
+ currentPosition++;
+ while (source[currentPosition] == 'u') {
+ currentPosition++;
+ }
+ if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c1 < 0
+ || (c2 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c2 < 0
+ || (c3 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c3 < 0
+ || (c4 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c4 < 0) {
+ throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
+ } else {
+ currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+ }
+ }
+ //handle the \\u case manually into comment
+ if (currentCharacter == '\\') {
+ if (source[currentPosition] == '\\')
+ currentPosition++;
+ } //jump over the \\
+ }
+ recordComment(false);
+ if (startPosition <= cursorLocation && cursorLocation < currentPosition - 1) {
+ throw new InvalidCursorLocation(
+ InvalidCursorLocation.NO_COMPLETION_INSIDE_COMMENT);
+ }
+ if (recordLineSeparator
+ && ((currentCharacter == '\r') || (currentCharacter == '\n')))
+ pushLineSeparator();
+ if (tokenizeComments) {
+ currentPosition--; // reset one character behind
+ return TokenNameCOMMENT_LINE;
+ }
+ } catch (IndexOutOfBoundsException e) { //an eof will them be generated
+ if (tokenizeComments) {
+ currentPosition--; // reset one character behind
+ return TokenNameCOMMENT_LINE;
+ }
+ }
+ break;
+ }
+ if (test > 0) { //traditional and annotation comment
+ boolean isJavadoc = false, star = false;
+ // consume next character
+ unicodeAsBackSlash = false;
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ getNextUnicodeChar();
+ } else {
+ if (withoutUnicodePtr != 0) {
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ }
+ }
+
+ if (currentCharacter == '*') {
+ isJavadoc = true;
+ star = true;
+ }
+ if (recordLineSeparator
+ && ((currentCharacter == '\r') || (currentCharacter == '\n')))
+ pushLineSeparator();
+ try { //get the next char
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ //-------------unicode traitement ------------
+ int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
+ currentPosition++;
+ while (source[currentPosition] == 'u') {
+ currentPosition++;
+ }
+ if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c1 < 0
+ || (c2 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c2 < 0
+ || (c3 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c3 < 0
+ || (c4 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c4 < 0) {
+ throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
+ } else {
+ currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+ }
+ }
+ //handle the \\u case manually into comment
+ if (currentCharacter == '\\') {
+ if (source[currentPosition] == '\\')
+ currentPosition++;
+ } //jump over the \\
+ // empty comment is not a javadoc /**/
+ if (currentCharacter == '/') {
+ isJavadoc = false;
+ }
+ //loop until end of comment */
+ while ((currentCharacter != '/') || (!star)) {
+ if (recordLineSeparator
+ && ((currentCharacter == '\r') || (currentCharacter == '\n')))
+ pushLineSeparator();
+ star = currentCharacter == '*';
+ //get next char
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ //-------------unicode traitement ------------
+ int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
+ currentPosition++;
+ while (source[currentPosition] == 'u') {
+ currentPosition++;
+ }
+ if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c1 < 0
+ || (c2 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c2 < 0
+ || (c3 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c3 < 0
+ || (c4 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c4 < 0) {
+ throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
+ } else {
+ currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+ }
+ }
+ //handle the \\u case manually into comment
+ if (currentCharacter == '\\') {
+ if (source[currentPosition] == '\\')
+ currentPosition++;
+ } //jump over the \\
+ }
+ recordComment(isJavadoc);
+ if (startPosition <= cursorLocation && cursorLocation < currentPosition - 1) {
+ throw new InvalidCursorLocation(
+ InvalidCursorLocation.NO_COMPLETION_INSIDE_COMMENT);
+ }
+ if (tokenizeComments) {
+ if (isJavadoc)
+ return TokenNameCOMMENT_JAVADOC;
+ return TokenNameCOMMENT_BLOCK;
+ }
+ } catch (IndexOutOfBoundsException e) {
+ throw new InvalidInputException(UNTERMINATED_COMMENT);
+ }
+ break;
+ }
+ if (getNextChar('='))
+ return TokenNameDIVIDE_EQUAL;
+ return TokenNameDIVIDE;
+ }
+ case '\u001a' :
+ if (atEnd())
+ return TokenNameEOF;
+ //the atEnd may not be <currentPosition == source.length> if source is only some part of a real (external) stream
+ throw new InvalidInputException("Ctrl-Z");
+
+ default :
+ if (Character.isJavaIdentifierStart(currentCharacter))
+ return scanIdentifierOrKeyword();
+ if (Character.isDigit(currentCharacter))
+ return scanNumber(false);
+ return TokenNameERROR;
+ }
+ }
+ } //-----------------end switch while try--------------------
+ catch (IndexOutOfBoundsException e) {
+ }
+ /* might be completing at very end of file (e.g. behind a dot) */
+ if (completionIdentifier == null && startPosition == cursorLocation + 1) {
+ currentPosition = startPosition;
+ // for being detected as empty free identifier
+ return TokenNameIdentifier;
+ }
+ return TokenNameEOF;
+ }
+
+ /*
+ * In case we actually read a keyword, but the cursor is located inside,
+ * we pretend we read an identifier.
+ */
+ public int scanIdentifierOrKeyword() throws InvalidInputException {
+
+ int id = super.scanIdentifierOrKeyword();
+
+ // convert completed keyword into an identifier
+ if (id != TokenNameIdentifier
+ && startPosition <= cursorLocation + 1
+ && cursorLocation < currentPosition) {
+ return TokenNameIdentifier;
+ }
+ return id;
+ }
+
+ public int scanNumber(boolean dotPrefix) throws InvalidInputException {
+ int token = super.scanNumber(dotPrefix);
+
+ // consider completion just before a number to be ok, will insert before it
+ if (startPosition <= cursorLocation && cursorLocation < currentPosition) {
+ throw new InvalidCursorLocation(
+ InvalidCursorLocation.NO_COMPLETION_INSIDE_NUMBER);
+ }
+ return token;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/InvalidCursorLocation.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/InvalidCursorLocation.java
new file mode 100644
index 0000000000..321bf85ad3
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/InvalidCursorLocation.java
@@ -0,0 +1,21 @@
+package org.eclipse.jdt.internal.codeassist.complete;
+
+public class InvalidCursorLocation extends RuntimeException {
+
+ public String irritant;
+
+ /* Possible irritants */
+ public static final String NO_COMPLETION_INSIDE_UNICODE =
+ "No Completion Inside Unicode";
+ public static final String NO_COMPLETION_INSIDE_COMMENT =
+ "No Completion Inside Comment";
+ public static final String NO_COMPLETION_INSIDE_STRING =
+ "No Completion Inside String";
+ public static final String NO_COMPLETION_INSIDE_NUMBER =
+ "No Completion Inside Number";
+
+ public InvalidCursorLocation(String irritant) {
+ this.irritant = irritant;
+ }
+
+}
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
new file mode 100644
index 0000000000..cdb036844f
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java
@@ -0,0 +1,1026 @@
+package org.eclipse.jdt.internal.codeassist.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Parser extension for code assist task
+ *
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.parser.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+public abstract class AssistParser extends Parser {
+
+ public AstNode assistNode;
+ public boolean isOrphanCompletionNode;
+
+ /* recovery */
+ int[] blockStarts = new int[30];
+
+ // the previous token read by the scanner
+ protected int previousToken;
+
+ // the index in the identifier stack of the previous identifier
+ protected int previousIdentifierPtr;
+
+ // the stacks of selectors for invocations (ie. method invocations, allocation expressions and
+ // explicit constructor invocations)
+ // the selector stack contains pointers to the identifier stack or one of the selector constants below
+ protected int invocationPtr;
+ protected int[] selectorStack = new int[StackIncrement];
+
+ // selector constants
+ protected static final int THIS_CONSTRUCTOR = -1;
+ protected static final int SUPER_CONSTRUCTOR = -2;
+
+ // whether the parser is in a field initializer
+ // (false is pushed each time a new type is entered,
+ // it is changed to true when the initializer is entered,
+ // it is changed back to false when the initializer is exited,
+ // and it is poped when the type is exited)
+ protected int inInitializerPtr;
+ protected boolean[] inInitializerStack = new boolean[StackIncrement];
+
+ // whether the parser is in a method, constructor or initializer
+ // (false is pushed each time a new type is entered,
+ // it is changed to true when the method is entered,
+ // it is changed back to false when the method is exited,
+ // and it is poped when the type is exited)
+ protected int inMethodPtr;
+ protected boolean[] inMethodStack = new boolean[StackIncrement];
+ public AssistParser(ProblemReporter problemReporter) {
+ super(problemReporter, false);
+ }
+
+ public abstract char[] assistIdentifier();
+ public int bodyEnd(AbstractMethodDeclaration method) {
+ return method.declarationSourceEnd;
+ }
+
+ public int bodyEnd(Initializer initializer) {
+ return initializer.declarationSourceEnd;
+ }
+
+ /*
+ * Build initial recovery state.
+ * Recovery state is inferred from the current state of the parser (reduced node stack).
+ */
+ public RecoveredElement buildInitialRecoveryState() {
+
+ if (!ENABLE_RECOVERY)
+ return null; // do not resume to recovery
+
+ /* recovery in unit structure */
+ if (referenceContext instanceof CompilationUnitDeclaration) {
+ RecoveredElement element = super.buildInitialRecoveryState();
+ flushAssistState();
+ return element;
+ }
+
+ /* recovery in method body */
+ lastCheckPoint = 0;
+
+ RecoveredElement element = null;
+ if (referenceContext instanceof AbstractMethodDeclaration) {
+ element =
+ new RecoveredMethod(
+ (AbstractMethodDeclaration) referenceContext,
+ null,
+ 0,
+ this);
+ lastCheckPoint = ((AbstractMethodDeclaration) referenceContext).bodyStart;
+ } else {
+ /* Initializer bodies are parsed in the context of the type declaration, we must thus search it inside */
+ if (referenceContext instanceof TypeDeclaration) {
+ TypeDeclaration type = (TypeDeclaration) referenceContext;
+ for (int i = 0; i < type.fields.length; i++) {
+ FieldDeclaration field = type.fields[i];
+ if (field.declarationSourceStart <= scanner.initialPosition
+ && scanner.initialPosition <= field.declarationSourceEnd
+ && scanner.eofPosition <= field.declarationSourceEnd + 1) {
+ element = new RecoveredInitializer((Initializer) field, null, 1, this);
+ lastCheckPoint = field.declarationSourceStart;
+ break;
+ }
+ }
+ }
+ }
+
+ if (element == null)
+ return element;
+
+ /* add initial block */
+ Block block = new Block(0);
+ int lastStart = blockStarts[0];
+ block.sourceStart = lastStart;
+ element = element.add(block, 1);
+ int blockIndex = 1; // ignore first block start, since manually rebuilt here
+
+ for (int i = 0; i <= astPtr; i++) {
+ AstNode node = astStack[i];
+
+ /* check for intermediate block creation, so recovery can properly close them afterwards */
+ int nodeStart = node.sourceStart;
+ for (int j = blockIndex; j <= realBlockPtr; j++) {
+ if (blockStarts[j] > nodeStart) {
+ blockIndex = j; // shift the index to the new block
+ break;
+ }
+ if (blockStarts[j] != lastStart) { // avoid multiple block if at same position
+ block = new Block(0);
+ block.sourceStart = lastStart = blockStarts[j];
+ element = element.add(block, 1);
+ }
+ blockIndex = j + 1; // shift the index to the new block
+ }
+ if (node instanceof LocalDeclaration) {
+ LocalDeclaration local = (LocalDeclaration) node;
+ if (local.declarationSourceEnd == 0) {
+ element = element.add(local, 0);
+ if (local.initialization == null) {
+ lastCheckPoint = local.sourceEnd + 1;
+ } else {
+ lastCheckPoint = local.initialization.sourceEnd + 1;
+ }
+ } else {
+ element = element.add(local, 0);
+ lastCheckPoint = local.declarationSourceEnd + 1;
+ }
+ continue;
+ }
+ if (node instanceof AbstractMethodDeclaration) {
+ AbstractMethodDeclaration method = (AbstractMethodDeclaration) node;
+ if (method.declarationSourceEnd == 0) {
+ element = element.add(method, 0);
+ lastCheckPoint = method.bodyStart;
+ } else {
+ element = element.add(method, 0);
+ lastCheckPoint = method.declarationSourceEnd + 1;
+ }
+ continue;
+ }
+ if (node instanceof Initializer) {
+ Initializer initializer = (Initializer) node;
+ if (initializer.declarationSourceEnd == 0) {
+ element = element.add(initializer, 1);
+ lastCheckPoint = initializer.bodyStart;
+ } else {
+ element = element.add(initializer, 0);
+ lastCheckPoint = initializer.declarationSourceEnd + 1;
+ }
+ continue;
+ }
+ if (node instanceof FieldDeclaration) {
+ FieldDeclaration field = (FieldDeclaration) node;
+ if (field.declarationSourceEnd == 0) {
+ element = element.add(field, 0);
+ if (field.initialization == null) {
+ lastCheckPoint = field.sourceEnd + 1;
+ } else {
+ lastCheckPoint = field.initialization.sourceEnd + 1;
+ }
+ } else {
+ element = element.add(field, 0);
+ lastCheckPoint = field.declarationSourceEnd + 1;
+ }
+ continue;
+ }
+ if (node instanceof TypeDeclaration) {
+ TypeDeclaration type = (TypeDeclaration) node;
+ if (type.declarationSourceEnd == 0) {
+ element = element.add(type, 0);
+ lastCheckPoint = type.bodyStart;
+ } else {
+ element = element.add(type, 0);
+ lastCheckPoint = type.declarationSourceEnd + 1;
+ }
+ continue;
+ }
+ if (node instanceof ImportReference) {
+ ImportReference importRef = (ImportReference) node;
+ element = element.add(importRef, 0);
+ lastCheckPoint = importRef.declarationSourceEnd + 1;
+ }
+ }
+ if (this.currentToken == TokenNameRBRACE) {
+ this.currentToken = 0; // closing brace has already been taken care of
+ }
+
+ /* might need some extra block (after the last reduced node) */
+ int pos =
+ this.assistNode == null ? lastCheckPoint : this.assistNode.sourceStart;
+ for (int j = blockIndex; j <= realBlockPtr; j++) {
+ if ((blockStarts[j] < pos)
+ && (blockStarts[j] != lastStart)) { // avoid multiple block if at same position
+ block = new Block(0);
+ block.sourceStart = lastStart = blockStarts[j];
+ element = element.add(block, 1);
+ }
+ }
+
+ return element;
+ }
+
+ protected void consumeClassBodyDeclarationsopt() {
+ super.consumeClassBodyDeclarationsopt();
+ this.inInitializerPtr--;
+ this.inMethodPtr--;
+ }
+
+ protected void consumeClassBodyopt() {
+ super.consumeClassBodyopt();
+ this.invocationPtr--;
+ // NB: This can be decremented below -1 only if in diet mode and not in field initializer
+ }
+
+ protected void consumeClassHeader() {
+ super.consumeClassHeader();
+ this.pushNotInInitializer();
+ this.pushNotInMethod();
+ }
+
+ protected void consumeConstructorBody() {
+ super.consumeConstructorBody();
+ this.inMethodStack[this.inMethodPtr] = false;
+ }
+
+ protected void consumeConstructorHeader() {
+ super.consumeConstructorHeader();
+ this.inMethodStack[this.inMethodPtr] = true;
+ }
+
+ protected void consumeEmptyClassBodyDeclarationsopt() {
+ super.consumeEmptyClassBodyDeclarationsopt();
+ this.inInitializerPtr--;
+ this.inMethodPtr--;
+ }
+
+ protected void consumeEnterAnonymousClassBody() {
+ super.consumeEnterAnonymousClassBody();
+ this.invocationPtr--;
+ // NB: This can be decremented below -1 only if in diet mode and not in field initializer
+ this.pushNotInInitializer();
+ this.pushNotInMethod();
+ }
+
+ protected void consumeExplicitConstructorInvocation(int flag, int recFlag) {
+ super.consumeExplicitConstructorInvocation(flag, recFlag);
+ this.invocationPtr--;
+ // NB: This can be decremented below -1 only if in diet mode and not in field initializer
+ }
+
+ protected void consumeForceNoDiet() {
+ super.consumeForceNoDiet();
+ // if we are not in a method (ie. we are not in a local variable initializer)
+ // then we are entering a field initializer
+ if (!this.inMethodStack[this.inMethodPtr]) {
+ this.inInitializerStack[this.inInitializerPtr] = true;
+ }
+ }
+
+ protected void consumeInterfaceHeader() {
+ super.consumeInterfaceHeader();
+ this.pushNotInInitializer();
+ this.pushNotInMethod();
+ }
+
+ protected void consumeInterfaceMemberDeclarationsopt() {
+ super.consumeInterfaceMemberDeclarationsopt();
+ this.inInitializerPtr--;
+ this.inMethodPtr--;
+ }
+
+ protected void consumeMethodBody() {
+ super.consumeMethodBody();
+ this.inMethodStack[this.inMethodPtr] = false;
+ }
+
+ protected void consumeMethodHeader() {
+ super.consumeMethodHeader();
+ this.inMethodStack[this.inMethodPtr] = true;
+ }
+
+ protected void consumeMethodInvocationName() {
+ super.consumeMethodInvocationName();
+ this.invocationPtr--;
+ // NB: This can be decremented below -1 only if in diet mode and not in field initializer
+ MessageSend messageSend = (MessageSend) expressionStack[expressionPtr];
+ if (messageSend == assistNode) {
+ this.lastCheckPoint = messageSend.sourceEnd + 1;
+ }
+ }
+
+ protected void consumeMethodInvocationPrimary() {
+ super.consumeMethodInvocationPrimary();
+ this.invocationPtr--;
+ // NB: This can be decremented below -1 only if in diet mode and not in field initializer
+ MessageSend messageSend = (MessageSend) expressionStack[expressionPtr];
+ if (messageSend == assistNode) {
+ this.lastCheckPoint = messageSend.sourceEnd + 1;
+ }
+ }
+
+ protected void consumeMethodInvocationSuper() {
+ super.consumeMethodInvocationSuper();
+ this.invocationPtr--;
+ // NB: This can be decremented below -1 only if in diet mode and not in field initializer
+ MessageSend messageSend = (MessageSend) expressionStack[expressionPtr];
+ if (messageSend == assistNode) {
+ this.lastCheckPoint = messageSend.sourceEnd + 1;
+ }
+ }
+
+ protected void consumeNestedMethod() {
+ super.consumeNestedMethod();
+ this.inMethodStack[this.inMethodPtr] = true;
+ }
+
+ protected void consumeOpenBlock() {
+ // OpenBlock ::= $empty
+
+ super.consumeOpenBlock();
+ try {
+ blockStarts[realBlockPtr] = scanner.startPosition;
+ } catch (IndexOutOfBoundsException e) {
+ //realBlockPtr is correct
+ int oldStackLength = blockStarts.length;
+ int oldStack[] = blockStarts;
+ blockStarts = new int[oldStackLength + StackIncrement];
+ System.arraycopy(oldStack, 0, blockStarts, 0, oldStackLength);
+ blockStarts[realBlockPtr] = scanner.startPosition;
+ }
+ }
+
+ protected void consumePackageDeclarationName() {
+ // PackageDeclarationName ::= 'package' Name
+ /* build an ImportRef build from the last name
+ stored in the identifier stack. */
+
+ int index;
+
+ /* no need to take action if not inside assist identifiers */
+ if ((index = indexOfAssistIdentifier()) < 0) {
+ super.consumePackageDeclarationName();
+ return;
+ }
+ /* retrieve identifiers subset and whole positions, the assist node positions
+ should include the entire replaced source. */
+ int length = identifierLengthStack[identifierLengthPtr];
+ char[][] subset = identifierSubSet(index + 1); // include the assistIdentifier
+ identifierLengthPtr--;
+ identifierPtr -= length;
+ long[] positions = new long[length];
+ System.arraycopy(
+ identifierPositionStack,
+ identifierPtr + 1,
+ positions,
+ 0,
+ length);
+
+ /* build specific assist node on package statement */
+ ImportReference reference =
+ this.createAssistPackageReference(subset, positions);
+ assistNode = reference;
+ this.lastCheckPoint = reference.sourceEnd + 1;
+ compilationUnit.currentPackage = reference;
+
+ if (currentToken == TokenNameSEMICOLON) {
+ reference.declarationSourceEnd = scanner.currentPosition - 1;
+ } else {
+ reference.declarationSourceEnd = (int) positions[length - 1];
+ }
+ //endPosition is just before the ;
+ reference.declarationSourceStart = intStack[intPtr--];
+ // flush annotations defined prior to import statements
+ reference.declarationSourceEnd =
+ this.flushAnnotationsDefinedPriorTo(reference.declarationSourceEnd);
+
+ // recovery
+ if (currentElement != null) {
+ lastCheckPoint = reference.declarationSourceEnd + 1;
+ restartRecovery = true;
+ // used to avoid branching back into the regular automaton
+ }
+ }
+
+ protected void consumeRestoreDiet() {
+ super.consumeRestoreDiet();
+ // if we are not in a method (ie. we were not in a local variable initializer)
+ // then we are exiting a field initializer
+ if (!this.inMethodStack[this.inMethodPtr]) {
+ this.inInitializerStack[this.inInitializerPtr] = false;
+ }
+ }
+
+ protected void consumeSingleTypeImportDeclarationName() {
+ // SingleTypeImportDeclarationName ::= 'import' Name
+ /* push an ImportRef build from the last name
+ stored in the identifier stack. */
+
+ int index;
+
+ /* no need to take action if not inside assist identifiers */
+ if ((index = indexOfAssistIdentifier()) < 0) {
+ super.consumeSingleTypeImportDeclarationName();
+ return;
+ }
+ /* retrieve identifiers subset and whole positions, the assist node positions
+ should include the entire replaced source. */
+ int length = identifierLengthStack[identifierLengthPtr];
+ char[][] subset = identifierSubSet(index + 1); // include the assistIdentifier
+ identifierLengthPtr--;
+ identifierPtr -= length;
+ long[] positions = new long[length];
+ System.arraycopy(
+ identifierPositionStack,
+ identifierPtr + 1,
+ positions,
+ 0,
+ length);
+
+ /* build specific assist node on import statement */
+ ImportReference reference = this.createAssistImportReference(subset, positions);
+ assistNode = reference;
+ this.lastCheckPoint = reference.sourceEnd + 1;
+
+ pushOnAstStack(reference);
+
+ if (currentToken == TokenNameSEMICOLON) {
+ reference.declarationSourceEnd = scanner.currentPosition - 1;
+ } else {
+ reference.declarationSourceEnd = (int) positions[length - 1];
+ }
+ //endPosition is just before the ;
+ reference.declarationSourceStart = intStack[intPtr--];
+ // flush annotations defined prior to import statements
+ reference.declarationSourceEnd =
+ this.flushAnnotationsDefinedPriorTo(reference.declarationSourceEnd);
+
+ // recovery
+ if (currentElement != null) {
+ lastCheckPoint = reference.declarationSourceEnd + 1;
+ currentElement = currentElement.add(reference, 0);
+ lastIgnoredToken = -1;
+ restartRecovery = true;
+ // used to avoid branching back into the regular automaton
+ }
+ }
+
+ protected void consumeStaticInitializer() {
+ super.consumeStaticInitializer();
+ this.inMethodStack[this.inMethodPtr] = false;
+ }
+
+ protected void consumeStaticOnly() {
+ super.consumeStaticOnly();
+ this.inMethodStack[this.inMethodPtr] = true;
+ }
+
+ protected void consumeToken(int token) {
+ super.consumeToken(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 ((this.inMethodStack[this.inMethodPtr]
+ || this.inInitializerStack[this.inInitializerPtr])
+ && token == TokenNameLPAREN) {
+ switch (this.previousToken) {
+ case TokenNameIdentifier :
+ this.pushOnSelectorStack(this.identifierPtr);
+ break;
+ case TokenNamethis : // explicit constructor invocation, eg. this(1, 2)
+ this.pushOnSelectorStack(THIS_CONSTRUCTOR);
+ break;
+ case TokenNamesuper : // explicit constructor invocation, eg. super(1, 2)
+ this.pushOnSelectorStack(SUPER_CONSTRUCTOR);
+ break;
+ }
+ }
+ this.previousToken = token;
+ if (token == TokenNameIdentifier) {
+ this.previousIdentifierPtr = this.identifierPtr;
+ }
+ }
+
+ protected void consumeTypeImportOnDemandDeclarationName() {
+ // TypeImportOnDemandDeclarationName ::= 'import' Name '.' '*'
+ /* push an ImportRef build from the last name
+ stored in the identifier stack. */
+
+ int index;
+
+ /* no need to take action if not inside assist identifiers */
+ if ((index = indexOfAssistIdentifier()) < 0) {
+ super.consumeTypeImportOnDemandDeclarationName();
+ return;
+ }
+ /* retrieve identifiers subset and whole positions, the assist node positions
+ should include the entire replaced source. */
+ int length = identifierLengthStack[identifierLengthPtr];
+ char[][] subset = identifierSubSet(index + 1); // include the assistIdentifier
+ identifierLengthPtr--;
+ identifierPtr -= length;
+ long[] positions = new long[length];
+ System.arraycopy(
+ identifierPositionStack,
+ identifierPtr + 1,
+ positions,
+ 0,
+ length);
+
+ /* build specific assist node on import statement */
+ ImportReference reference = this.createAssistImportReference(subset, positions);
+ reference.onDemand = true;
+ assistNode = reference;
+ this.lastCheckPoint = reference.sourceEnd + 1;
+
+ pushOnAstStack(reference);
+
+ if (currentToken == TokenNameSEMICOLON) {
+ reference.declarationSourceEnd = scanner.currentPosition - 1;
+ } else {
+ reference.declarationSourceEnd = (int) positions[length - 1];
+ }
+ //endPosition is just before the ;
+ reference.declarationSourceStart = intStack[intPtr--];
+ // flush annotations defined prior to import statements
+ reference.declarationSourceEnd =
+ this.flushAnnotationsDefinedPriorTo(reference.declarationSourceEnd);
+
+ // recovery
+ if (currentElement != null) {
+ lastCheckPoint = reference.declarationSourceEnd + 1;
+ currentElement = currentElement.add(reference, 0);
+ lastIgnoredToken = -1;
+ restartRecovery = true;
+ // used to avoid branching back into the regular automaton
+ }
+ }
+
+ public abstract ImportReference createAssistImportReference(
+ char[][] tokens,
+ long[] positions);
+ public abstract ImportReference createAssistPackageReference(
+ char[][] tokens,
+ long[] positions);
+ public abstract NameReference createQualifiedAssistNameReference(
+ char[][] previousIdentifiers,
+ char[] name,
+ long[] positions);
+ public abstract TypeReference createQualifiedAssistTypeReference(
+ char[][] previousIdentifiers,
+ char[] name,
+ long[] positions);
+ public abstract NameReference createSingleAssistNameReference(
+ char[] name,
+ long position);
+ public abstract TypeReference createSingleAssistTypeReference(
+ char[] name,
+ long position);
+ /*
+ * Flush parser/scanner state regarding to code assist
+ */
+ public void flushAssistState() {
+ this.assistNode = null;
+ this.isOrphanCompletionNode = false;
+ }
+
+ /*
+ * Build specific type reference nodes in case the cursor is located inside the type reference
+ */
+ protected TypeReference getTypeReference(int dim) {
+
+ int index;
+
+ /* no need to take action if not inside completed identifiers */
+ if ((index = indexOfAssistIdentifier()) < 0) {
+ return super.getTypeReference(dim);
+ }
+
+ /* retrieve identifiers subset and whole positions, the assist node positions
+ should include the entire replaced source. */
+ int length = identifierLengthStack[identifierLengthPtr];
+ char[][] subset = identifierSubSet(index);
+ identifierLengthPtr--;
+ identifierPtr -= length;
+ long[] positions = new long[length];
+ System.arraycopy(
+ identifierPositionStack,
+ identifierPtr + 1,
+ positions,
+ 0,
+ length);
+
+ /* build specific assist on type reference */
+ TypeReference reference;
+ if (index == 0) {
+ /* assist inside first identifier */
+ reference =
+ this.createSingleAssistTypeReference(assistIdentifier(), positions[0]);
+ } else {
+ /* assist inside subsequent identifier */
+ reference =
+ this.createQualifiedAssistTypeReference(subset, assistIdentifier(), positions);
+ }
+ assistNode = reference;
+ this.lastCheckPoint = reference.sourceEnd + 1;
+ return reference;
+ }
+
+ /*
+ * Copy of code from superclass with the following change:
+ * In the case of qualified name reference if the cursor location is on the
+ * qualified name reference, then create a CompletionOnQualifiedNameReference
+ * instead.
+ */
+ protected NameReference getUnspecifiedReferenceOptimized() {
+
+ int completionIndex;
+
+ /* no need to take action if not inside completed identifiers */
+ if ((completionIndex = indexOfAssistIdentifier()) < 0) {
+ return super.getUnspecifiedReferenceOptimized();
+ }
+
+ /* retrieve identifiers subset and whole positions, the completion node positions
+ should include the entire replaced source. */
+ int length = identifierLengthStack[identifierLengthPtr];
+ char[][] subset = identifierSubSet(completionIndex);
+ identifierLengthPtr--;
+ identifierPtr -= length;
+ long[] positions = new long[length];
+ System.arraycopy(
+ identifierPositionStack,
+ identifierPtr + 1,
+ positions,
+ 0,
+ length);
+
+ /* build specific completion on name reference */
+ NameReference reference;
+ if (completionIndex == 0) {
+ /* completion inside first identifier */
+ reference =
+ this.createSingleAssistNameReference(assistIdentifier(), positions[0]);
+ } else {
+ /* completion inside subsequent identifier */
+ reference =
+ this.createQualifiedAssistNameReference(subset, assistIdentifier(), positions);
+ };
+ reference.bits &= ~NameReference.RestrictiveFlagMASK;
+ reference.bits |= LOCAL | FIELD;
+
+ assistNode = reference;
+ lastCheckPoint = reference.sourceEnd + 1;
+ return reference;
+ }
+
+ public void goForBlockStatementsopt() {
+ //tells the scanner to go for block statements opt parsing
+
+ firstToken = TokenNameTWIDDLE;
+ scanner.recordLineSeparator = false;
+ }
+
+ public void goForConstructorBlockStatementsopt() {
+ //tells the scanner to go for constructor block statements opt parsing
+
+ firstToken = TokenNameNOT;
+ scanner.recordLineSeparator = false;
+ }
+
+ /*
+ * Retrieve a partial subset of a qualified name reference up to the completion point.
+ * It does not pop the actual awaiting identifiers, so as to be able to retrieve position
+ * information afterwards.
+ */
+ protected char[][] identifierSubSet(int subsetLength) {
+
+ if (subsetLength == 0)
+ return null;
+
+ char[][] subset;
+ System.arraycopy(
+ identifierStack,
+ identifierPtr - identifierLengthStack[identifierLengthPtr] + 1,
+ (subset = new char[subsetLength][]),
+ 0,
+ subsetLength);
+ return subset;
+ }
+
+ /*
+ * Iterate the most recent group of awaiting identifiers (grouped for qualified name reference (eg. aa.bb.cc)
+ * so as to check whether one of them is the assist identifier.
+ * If so, then answer the index of the assist identifier (0 being the first identifier of the set).
+ * eg. aa(0).bb(1).cc(2)
+ * If no assist identifier was found, answers -1.
+ */
+ protected int indexOfAssistIdentifier() {
+
+ if (identifierLengthPtr < 0) {
+ return -1; // no awaiting identifier
+ }
+
+ char[] assistIdentifier;
+ if ((assistIdentifier = this.assistIdentifier()) == null) {
+ return -1; // no assist identifier found yet
+ }
+
+ // iterate awaiting identifiers backwards
+ int length = identifierLengthStack[identifierLengthPtr];
+ for (int i = 0; i < length; i++) {
+ if (identifierStack[identifierPtr - i] == assistIdentifier) {
+ return length - i - 1;
+ }
+ }
+ // none of the awaiting identifiers is the completion one
+ return -1;
+ }
+
+ public void initialize() {
+ super.initialize();
+ this.flushAssistState();
+ this.invocationPtr = -1;
+ this.inMethodStack[this.inMethodPtr = 0] = false;
+ this.inInitializerStack[this.inInitializerPtr = 0] = false;
+ this.previousIdentifierPtr = -1;
+ }
+
+ public abstract void initializeScanner();
+ /**
+ * Parse the block statements inside the given method declaration and try to complete at the
+ * cursor location.
+ */
+ public void parseBlockStatements(
+ AbstractMethodDeclaration md,
+ CompilationUnitDeclaration unit) {
+ if (md instanceof MethodDeclaration) {
+ parseBlockStatements((MethodDeclaration) md, unit);
+ } else
+ if (md instanceof ConstructorDeclaration) {
+ parseBlockStatements((ConstructorDeclaration) md, unit);
+ }
+ }
+
+ /**
+ * Parse the block statements inside the given constructor declaration and try to complete at the
+ * cursor location.
+ */
+ public void parseBlockStatements(
+ ConstructorDeclaration cd,
+ CompilationUnitDeclaration unit) {
+ //only parse the method body of cd
+ //fill out its statements
+
+ //convert bugs into parse error
+
+ initialize();
+
+ // simulate goForConstructorBody except that we don't want to balance brackets because they are not going to be balanced
+ goForConstructorBlockStatementsopt();
+
+ referenceContext = cd;
+ compilationUnit = unit;
+
+ scanner.resetTo(cd.bodyStart, bodyEnd(cd));
+ consumeNestedMethod();
+ try {
+ parse();
+ } catch (AbortCompilation ex) {
+ lastAct = ERROR_ACTION;
+ }
+ }
+
+ /**
+ * Parse the block statements inside the given initializer and try to complete at the
+ * cursor location.
+ */
+ public void parseBlockStatements(
+ Initializer ini,
+ TypeDeclaration type,
+ CompilationUnitDeclaration unit) {
+
+ initialize();
+
+ // simulate goForInitializer except that we don't want to balance brackets because they are not going to be balanced
+ goForBlockStatementsopt();
+
+ referenceContext = type;
+ compilationUnit = unit;
+
+ scanner.resetTo(ini.sourceStart, bodyEnd(ini)); // just after the beginning {
+ consumeNestedMethod();
+ try {
+ parse();
+ } catch (AbortCompilation ex) {
+ lastAct = ERROR_ACTION;
+ } finally {
+ nestedMethod[nestedType]--;
+ }
+ }
+
+ /**
+ * Parse the block statements inside the given method declaration and try to complete at the
+ * cursor location.
+ */
+ public void parseBlockStatements(
+ MethodDeclaration md,
+ CompilationUnitDeclaration unit) {
+ //only parse the method body of md
+ //fill out method statements
+
+ //convert bugs into parse error
+
+ if (md.isAbstract())
+ return;
+ if (md.isNative())
+ return;
+ if ((md.modifiers & AccSemicolonBody) != 0)
+ return;
+
+ initialize();
+
+ // simulate goForMethodBody except that we don't want to balance brackets because they are not going to be balanced
+ goForBlockStatementsopt();
+
+ referenceContext = md;
+ compilationUnit = unit;
+
+ scanner.resetTo(md.bodyStart, bodyEnd(md));
+ // reset the scanner to parser from { down to the cursor location
+ consumeNestedMethod();
+ try {
+ parse();
+ } catch (AbortCompilation ex) {
+ lastAct = ERROR_ACTION;
+ } finally {
+ nestedMethod[nestedType]--;
+ }
+ }
+
+ /*
+ * Prepares the state of the parser to go for BlockStatements.
+ */
+ protected void prepareForBlockStatements() {
+ this.nestedMethod[this.nestedType = 0] = 1;
+ this.variablesCounter[this.nestedType] = 0;
+ this.realBlockStack[this.realBlockPtr = 1] = 0;
+ this.invocationPtr = -1;
+ }
+
+ /*
+ * Pushes 'false' on the inInitializerStack.
+ */
+ protected void pushNotInInitializer() {
+ try {
+ this.inInitializerStack[++this.inInitializerPtr] = false;
+ } catch (IndexOutOfBoundsException e) {
+ //except in test's cases, it should never raise
+ int oldStackLength = this.inInitializerStack.length;
+ System.arraycopy(
+ this.inInitializerStack,
+ 0,
+ (this.inInitializerStack = new boolean[oldStackLength + StackIncrement]),
+ 0,
+ oldStackLength);
+ this.inInitializerStack[this.inInitializerPtr] = false;
+ }
+ }
+
+ /*
+ * Pushes 'false' on the inMethodStack.
+ */
+ protected void pushNotInMethod() {
+ try {
+ this.inMethodStack[++this.inMethodPtr] = false;
+ } catch (IndexOutOfBoundsException e) {
+ //except in test's cases, it should never raise
+ int oldStackLength = this.inMethodStack.length;
+ System.arraycopy(
+ this.inMethodStack,
+ 0,
+ (this.inMethodStack = new boolean[oldStackLength + StackIncrement]),
+ 0,
+ oldStackLength);
+ this.inMethodStack[this.inMethodPtr] = false;
+ }
+ }
+
+ /**
+ * Pushes the given the given selector (an identifier pointer to the identifier stack) on the selector stack.
+ */
+ protected void pushOnSelectorStack(int selectorIdPtr) {
+ if (this.invocationPtr < -1)
+ return;
+ try {
+ this.selectorStack[++this.invocationPtr] = selectorIdPtr;
+ } catch (IndexOutOfBoundsException e) {
+ int oldStackLength = this.selectorStack.length;
+ int oldSelectorStack[] = this.selectorStack;
+ this.selectorStack = new int[oldStackLength + StackIncrement];
+ System.arraycopy(oldSelectorStack, 0, this.selectorStack, 0, oldStackLength);
+ this.selectorStack[this.invocationPtr] = selectorIdPtr;
+ }
+ }
+
+ public void reset() {
+ this.flushAssistState();
+ }
+
+ /*
+ * Reset context so as to resume to regular parse loop
+ */
+ protected void resetStacks() {
+ super.resetStacks();
+ this.inInitializerStack[this.inInitializerPtr = 0] = false;
+ this.inMethodStack[this.inMethodPtr = 0] = false;
+ }
+
+ /*
+ * Reset context so as to resume to regular parse loop
+ * If unable to reset for resuming, answers false.
+ *
+ * Move checkpoint location, reset internal stacks and
+ * decide which grammar goal is activated.
+ */
+ protected boolean resumeAfterRecovery() {
+
+ // reset internal stacks
+ astPtr = -1;
+ astLengthPtr = -1;
+ expressionPtr = -1;
+ expressionLengthPtr = -1;
+ identifierPtr = -1;
+ identifierLengthPtr = -1;
+ intPtr = -1;
+ dimensions = 0;
+ recoveredStaticInitializerStart = 0;
+
+ // if in diet mode, reset the diet counter because we're going to restart outside an initializer.
+ if (diet)
+ dietInt = 0;
+
+ /* attempt to move checkpoint location */
+ if (!this.moveRecoveryCheckpoint())
+ return false;
+
+ // only look for headers
+ if (referenceContext instanceof CompilationUnitDeclaration
+ || this.assistNode != null) {
+ nestedMethod[nestedType = 0] = 0;
+ variablesCounter[nestedType] = 0;
+ realBlockStack[realBlockPtr = 0] = 0;
+ goForHeaders();
+ diet = true; // passed this point, will not consider method bodies
+ return true;
+ }
+ if (referenceContext instanceof AbstractMethodDeclaration
+ || referenceContext instanceof TypeDeclaration) {
+
+ if (currentElement instanceof RecoveredType) {
+ nestedMethod[nestedType = 0] = 0;
+ variablesCounter[nestedType] = 0;
+ realBlockStack[realBlockPtr = 0] = 0;
+ goForHeaders();
+ } else {
+ this.prepareForBlockStatements();
+ goForBlockStatementsOrMethodHeaders();
+ }
+ return true;
+ }
+ // does not know how to restart
+ return false;
+ }
+
+ public abstract void setAssistIdentifier(char[] assistIdent);
+ /**
+ * If the given ast node is inside an explicit constructor call
+ * then wrap it with a fake constructor call.
+ * Returns the wrapped completion node or the completion node itself.
+ */
+ protected AstNode wrapWithExplicitConstructorCallIfNeeded(AstNode ast) {
+ int selector;
+ if (ast != null
+ && this.invocationPtr >= 0
+ && ast instanceof Expression
+ && (((selector = this.selectorStack[this.invocationPtr]) == THIS_CONSTRUCTOR)
+ || (selector == SUPER_CONSTRUCTOR))) {
+ ExplicitConstructorCall call =
+ new ExplicitConstructorCall(
+ (selector == THIS_CONSTRUCTOR)
+ ? ExplicitConstructorCall.This
+ : ExplicitConstructorCall.Super);
+ call.arguments = new Expression[] {(Expression) ast };
+ call.sourceStart = ast.sourceStart;
+ call.sourceEnd = ast.sourceEnd;
+ return call;
+ } else {
+ return ast;
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/Engine.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/Engine.java
new file mode 100644
index 0000000000..9250559c81
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/Engine.java
@@ -0,0 +1,141 @@
+package org.eclipse.jdt.internal.codeassist.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.Locale;
+
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.*;
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.parser.*;
+import org.eclipse.jdt.internal.compiler.impl.*;
+
+public abstract class Engine implements ITypeRequestor {
+ public LookupEnvironment lookupEnvironment;
+ /**
+ * Add an additional binary type
+ */
+
+ public void accept(IBinaryType binaryType, PackageBinding packageBinding) {
+ lookupEnvironment.createBinaryTypeFrom(binaryType, packageBinding);
+ }
+
+ /**
+ * Add an additional compilation unit.
+ */
+
+ public void accept(ICompilationUnit sourceUnit) {
+ CompilationResult result = new CompilationResult(sourceUnit, 1, 1);
+ CompilationUnitDeclaration parsedUnit =
+ this.getParser().dietParse(sourceUnit, result);
+
+ lookupEnvironment.buildTypeBindings(parsedUnit);
+ lookupEnvironment.completeTypeBindings(parsedUnit, true);
+ }
+
+ /**
+ * Add an additional source type
+ */
+
+ public void accept(ISourceType sourceType, PackageBinding packageBinding) {
+ CompilationResult result =
+ new CompilationResult(sourceType.getFileName(), 1, 1);
+ // need to hold onto this
+ CompilationUnitDeclaration unit =
+ SourceTypeConverter.buildCompilationUnit(
+ sourceType,
+ true,
+ true,
+ lookupEnvironment.problemReporter,
+ result);
+
+ if (unit != null) {
+ lookupEnvironment.buildTypeBindings(unit);
+ lookupEnvironment.completeTypeBindings(unit, true);
+ }
+ }
+
+ /**
+ * Answer an array of descriptions for the configurable options.
+ * The descriptions may be changed and passed back to a different
+ * compiler.
+ *
+ * @return ConfigurableOption[] - array of configurable options
+ */
+ public static ConfigurableOption[] getDefaultOptions(Locale locale) {
+ return Compiler.getDefaultOptions(locale);
+ }
+
+ public abstract AssistParser getParser();
+ protected void parseMethod(CompilationUnitDeclaration unit, int position) {
+ for (int i = unit.types.length; --i >= 0;) {
+ TypeDeclaration type = unit.types[i];
+ if (type.declarationSourceStart < position
+ && type.declarationSourceEnd >= position) {
+ getParser().scanner.setSourceBuffer(
+ unit.compilationResult.compilationUnit.getContents());
+ parseMethod(type, unit, position);
+ return;
+ }
+ }
+ }
+
+ private void parseMethod(
+ TypeDeclaration type,
+ CompilationUnitDeclaration unit,
+ int position) {
+ //members
+ TypeDeclaration[] memberTypes = type.memberTypes;
+ if (memberTypes != null) {
+ for (int i = memberTypes.length; --i >= 0;) {
+ TypeDeclaration memberType = memberTypes[i];
+ if (memberType.bodyStart > position)
+ continue;
+ if (memberType.declarationSourceEnd >= position) {
+ parseMethod(memberType, unit, position);
+ return;
+ }
+ }
+ }
+
+ //methods
+ AbstractMethodDeclaration[] methods = type.methods;
+ if (methods != null) {
+ for (int i = methods.length; --i >= 0;) {
+ AbstractMethodDeclaration method = methods[i];
+ if (method.bodyStart > position)
+ continue;
+ if (method.declarationSourceEnd >= position) {
+ getParser().parseBlockStatements(method, unit);
+ return;
+ }
+ }
+ }
+
+ //initializers
+ FieldDeclaration[] fields = type.fields;
+ if (fields != null) {
+ for (int i = fields.length; --i >= 0;) {
+ if (!(fields[i] instanceof Initializer))
+ continue;
+ Initializer initializer = (Initializer) fields[i];
+ if (initializer.bodyStart > position)
+ continue;
+ if (initializer.declarationSourceEnd >= position) {
+ getParser().parseBlockStatements(initializer, type, unit);
+ return;
+ }
+ }
+ }
+ }
+
+ protected void reset() {
+ lookupEnvironment.reset();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionNodeFound.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionNodeFound.java
new file mode 100644
index 0000000000..fc992ee960
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionNodeFound.java
@@ -0,0 +1,23 @@
+package org.eclipse.jdt.internal.codeassist.select;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.*;
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class SelectionNodeFound extends RuntimeException {
+ public Binding binding;
+ public SelectionNodeFound() {
+ this(null); // we found a problem in the selection node
+ }
+
+ public SelectionNodeFound(Binding binding) {
+ this.binding = binding;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnExplicitConstructorCall.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnExplicitConstructorCall.java
new file mode 100644
index 0000000000..56a905f978
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnExplicitConstructorCall.java
@@ -0,0 +1,66 @@
+package org.eclipse.jdt.internal.codeassist.select;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Selection node build by the parser in any case it was intending to
+ * reduce an explicit constructor call containing the cursor.
+ * e.g.
+ *
+ * class X {
+ * void foo() {
+ * Y.[start]super[end](1, 2)
+ * }
+ * }
+ *
+ * ---> class X {
+ * void foo() {
+ * <SelectOnExplicitConstructorCall:this.bar(1, 2)>
+ * }
+ * }
+ *
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class SelectionOnExplicitConstructorCall
+ extends ExplicitConstructorCall {
+ public SelectionOnExplicitConstructorCall(int accessMode) {
+ super(accessMode);
+ }
+
+ public void resolve(BlockScope scope) {
+ super.resolve(scope);
+
+ if (binding == null || !binding.isValidBinding())
+ throw new SelectionNodeFound();
+ else
+ throw new SelectionNodeFound(binding);
+ }
+
+ public String toString(int tab) {
+ String s = tabString(tab);
+ s += "<SelectOnExplicitConstructorCall:";
+ if (qualification != null)
+ s = s + qualification.toStringExpression() + ".";
+ if (accessMode == This) {
+ s = s + "this(";
+ } else {
+ s = s + "super(";
+ }
+ if (arguments != null) {
+ for (int i = 0; i < arguments.length; i++) {
+ s += arguments[i].toStringExpression();
+ if (i != arguments.length - 1) {
+ s += ", ";
+ }
+ };
+ }
+ s += ")>";
+ return s;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnFieldReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnFieldReference.java
new file mode 100644
index 0000000000..8d061d4ca5
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnFieldReference.java
@@ -0,0 +1,49 @@
+package org.eclipse.jdt.internal.codeassist.select;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Selection node build by the parser in any case it was intending to
+ * reduce a field reference containing the cursor.
+ * e.g.
+ *
+ * class X {
+ * void foo() {
+ * bar().[start]fred[end]
+ * }
+ * }
+ *
+ * ---> class X {
+ * void foo() {
+ * <SelectOnFieldReference:bar().fred>
+ * }
+ * }
+ *
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class SelectionOnFieldReference extends FieldReference {
+ public SelectionOnFieldReference(char[] source, long pos) {
+ super(source, pos);
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ super.resolveType(scope);
+
+ if (binding == null || !binding.isValidBinding())
+ throw new SelectionNodeFound();
+ else
+ throw new SelectionNodeFound(binding);
+ }
+
+ public String toStringExpression() {
+ /* slow code */
+
+ return "<SelectionOnFieldReference:" + super.toStringExpression() + ">";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnImportReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnImportReference.java
new file mode 100644
index 0000000000..a10661b6d2
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnImportReference.java
@@ -0,0 +1,48 @@
+package org.eclipse.jdt.internal.codeassist.select;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Selection node build by the parser in any case it was intending to
+ * reduce an import reference containing the assist identifier.
+ * e.g.
+ *
+ * import java.[start]io[end].*;
+ * class X {
+ * void foo() {
+ * }
+ * }
+ *
+ * ---> <SelectOnImport:java.io>
+ * class X {
+ * void foo() {
+ * }
+ * }
+ *
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+
+public class SelectionOnImportReference extends ImportReference {
+
+ public SelectionOnImportReference(char[][] tokens, long[] positions) {
+ super(tokens, positions, false);
+ }
+
+ public String toString(int tab, boolean withOnDemand) {
+
+ StringBuffer buffer = new StringBuffer(tabString(tab));
+ buffer.append("<SelectOnImport:");
+ for (int i = 0; i < tokens.length; i++) {
+ buffer.append(tokens[i]);
+ if (i < (tokens.length - 1)) {
+ buffer.append(".");
+ }
+ }
+ buffer.append(">");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnMessageSend.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnMessageSend.java
new file mode 100644
index 0000000000..efb09aa02e
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnMessageSend.java
@@ -0,0 +1,58 @@
+package org.eclipse.jdt.internal.codeassist.select;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Selection node build by the parser in any case it was intending to
+ * reduce a message send containing the cursor.
+ * e.g.
+ *
+ * class X {
+ * void foo() {
+ * this.[start]bar[end](1, 2)
+ * }
+ * }
+ *
+ * ---> class X {
+ * void foo() {
+ * <SelectOnMessageSend:this.bar(1, 2)>
+ * }
+ * }
+ *
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class SelectionOnMessageSend extends MessageSend {
+ public TypeBinding resolveType(BlockScope scope) {
+ super.resolveType(scope);
+
+ if (binding == null || !binding.isValidBinding())
+ throw new SelectionNodeFound();
+ else
+ throw new SelectionNodeFound(binding);
+ }
+
+ public String toStringExpression() {
+ /*slow code*/
+
+ String s = "<SelectOnMessageSend:";
+ if (receiver != ThisReference.ThisImplicit)
+ s = s + receiver.toStringExpression() + ".";
+ s = s + new String(selector) + "(";
+ if (arguments != null) {
+ for (int i = 0; i < arguments.length; i++) {
+ s += arguments[i].toStringExpression();
+ if (i != arguments.length - 1) {
+ s += ", ";
+ }
+ };
+ }
+ s = s + ")>";
+ return s;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnPackageReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnPackageReference.java
new file mode 100644
index 0000000000..53edc39251
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnPackageReference.java
@@ -0,0 +1,46 @@
+package org.eclipse.jdt.internal.codeassist.select;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Selection node build by the parser in any case it was intending to
+ * reduce an package statement containing the assist identifier.
+ * e.g.
+ *
+ * package java.[start]io[end];
+ * class X {
+ * void foo() {
+ * }
+ * }
+ *
+ * ---> <SelectOnPackage:java.io>
+ * class X {
+ * void foo() {
+ * }
+ * }
+ *
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+
+public class SelectionOnPackageReference extends ImportReference {
+ public SelectionOnPackageReference(char[][] tokens, long[] positions) {
+ super(tokens, positions, true);
+ }
+
+ public String toString(int tab, boolean withOnDemand) {
+ StringBuffer buffer = new StringBuffer(tabString(tab));
+ buffer.append("<SelectOnPackage:");
+ for (int i = 0; i < tokens.length; i++) {
+ buffer.append(tokens[i]);
+ if (i < (tokens.length - 1)) {
+ buffer.append(".");
+ }
+ }
+ buffer.append(">");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnQualifiedAllocationExpression.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnQualifiedAllocationExpression.java
new file mode 100644
index 0000000000..3269677868
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnQualifiedAllocationExpression.java
@@ -0,0 +1,71 @@
+package org.eclipse.jdt.internal.codeassist.select;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Selection node build by the parser in any case it was intending to
+ * reduce an allocation expression containing the cursor.
+ * If the allocation expression is not qualified, the enclosingInstance field
+ * is null.
+ * e.g.
+ *
+ * class X {
+ * void foo() {
+ * new [start]Bar[end](1, 2)
+ * }
+ * }
+ *
+ * ---> class X {
+ * void foo() {
+ * <SelectOnAllocationExpression:new Bar(1, 2)>
+ * }
+ * }
+ *
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class SelectionOnQualifiedAllocationExpression
+ extends QualifiedAllocationExpression {
+ public SelectionOnQualifiedAllocationExpression() {
+ }
+
+ public SelectionOnQualifiedAllocationExpression(AnonymousLocalTypeDeclaration anonymous) {
+ anonymousType = anonymous;
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ super.resolveType(scope);
+
+ if (binding == null || !binding.isValidBinding())
+ throw new SelectionNodeFound();
+ if (anonymousType == null)
+ throw new SelectionNodeFound(binding);
+
+ // if selecting a type for an anonymous type creation, we have to
+ // find its target super constructor (if extending a class) or its target
+ // super interface (if extending an interface)
+ if (anonymousType.binding.superInterfaces == NoSuperInterfaces) {
+ // find the constructor binding inside the super constructor call
+ ConstructorDeclaration constructor =
+ (ConstructorDeclaration) anonymousType.declarationOf(binding);
+ throw new SelectionNodeFound(constructor.constructorCall.binding);
+ } else {
+ // open on the only superinterface
+ throw new SelectionNodeFound(anonymousType.binding.superInterfaces[0]);
+ }
+ }
+
+ public String toStringExpression(int tab) {
+ return (
+ (this.enclosingInstance == null)
+ ? "<SelectOnAllocationExpression:"
+ : "<SelectOnQualifiedAllocationExpression:")
+ + super.toStringExpression(tab)
+ + ">";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnQualifiedNameReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnQualifiedNameReference.java
new file mode 100644
index 0000000000..7ba0832451
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnQualifiedNameReference.java
@@ -0,0 +1,76 @@
+package org.eclipse.jdt.internal.codeassist.select;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Selection node build by the parser in any case it was intending to
+ * reduce a qualified name reference containing the assist identifier.
+ * e.g.
+ *
+ * class X {
+ * Y y;
+ * void foo() {
+ * y.fred.[start]ba[end]
+ * }
+ * }
+ *
+ * ---> class X {
+ * Y y;
+ * void foo() {
+ * <SelectOnName:y.fred.ba>
+ * }
+ * }
+ *
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+
+public class SelectionOnQualifiedNameReference extends QualifiedNameReference {
+ public long[] sourcePositions;
+ // positions of each token, the last one being the positions of the completion identifier
+ public SelectionOnQualifiedNameReference(
+ char[][] previousIdentifiers,
+ char[] selectionIdentifier,
+ long[] positions) {
+ super(
+ CharOperation.arrayConcat(previousIdentifiers, selectionIdentifier),
+ (int) (positions[0] >>> 32),
+ (int) positions[positions.length - 1]);
+ this.sourcePositions = positions;
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ // it can be a package, type, member type, local variable or field
+ binding = scope.getBinding(tokens, this);
+ if (!binding.isValidBinding()) {
+ if (binding instanceof ProblemFieldBinding) {
+ scope.problemReporter().invalidField(this, (FieldBinding) binding);
+ } else
+ if (binding instanceof ProblemReferenceBinding) {
+ scope.problemReporter().invalidType(this, (TypeBinding) binding);
+ } else {
+ scope.problemReporter().unresolvableReference(this, binding);
+ }
+ throw new SelectionNodeFound();
+ }
+
+ throw new SelectionNodeFound(binding);
+ }
+
+ public String toStringExpression() {
+
+ StringBuffer buffer = new StringBuffer("<SelectOnName:");
+ for (int i = 0, length = tokens.length; i < length; i++) {
+ buffer.append(tokens[i]);
+ if (i != length - 1)
+ buffer.append(".");
+ }
+ buffer.append(">");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnQualifiedSuperReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnQualifiedSuperReference.java
new file mode 100644
index 0000000000..d0e5c5277f
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnQualifiedSuperReference.java
@@ -0,0 +1,60 @@
+package org.eclipse.jdt.internal.codeassist.select;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Selection node build by the parser in any case it was intending to
+ * reduce a qualified super reference containing the assist identifier.
+ * e.g.
+ *
+ * class X extends Z {
+ * class Y {
+ * void foo() {
+ * X.[start]super[end].bar();
+ * }
+ * }
+ * }
+ *
+ * ---> class X {
+ * class Y {
+ * void foo() {
+ * <SelectOnQualifiedSuper:X.super>
+ * }
+ * }
+ * }
+ *
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+
+public class SelectionOnQualifiedSuperReference
+ extends QualifiedSuperReference {
+ public SelectionOnQualifiedSuperReference(
+ TypeReference name,
+ int pos,
+ int sourceEnd) {
+ super(name, pos, sourceEnd);
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ TypeBinding binding = super.resolveType(scope);
+
+ if (binding == null || !binding.isValidBinding())
+ throw new SelectionNodeFound();
+ else
+ throw new SelectionNodeFound(binding);
+ }
+
+ public String toStringExpression() {
+
+ StringBuffer buffer = new StringBuffer("<SelectOnQualifiedSuper:");
+ buffer.append(super.toStringExpression());
+ buffer.append(">");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnQualifiedTypeReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnQualifiedTypeReference.java
new file mode 100644
index 0000000000..b5c3e14769
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnQualifiedTypeReference.java
@@ -0,0 +1,61 @@
+package org.eclipse.jdt.internal.codeassist.select;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Selection node build by the parser in any case it was intending to
+ * reduce a type reference containing the completion identifier as part
+ * of a qualified name.
+ * e.g.
+ *
+ * class X extends java.lang.[start]Object[end]
+ *
+ * ---> class X extends <SelectOnType:java.lang.Object>
+ *
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+
+public class SelectionOnQualifiedTypeReference extends QualifiedTypeReference {
+ public SelectionOnQualifiedTypeReference(
+ char[][] previousIdentifiers,
+ char[] selectionIdentifier,
+ long[] positions) {
+ super(
+ CharOperation.arrayConcat(previousIdentifiers, selectionIdentifier),
+ positions);
+ }
+
+ public void aboutToResolve(Scope scope) {
+ getTypeBinding(scope.parent); // step up from the ClassScope
+ }
+
+ public TypeBinding getTypeBinding(Scope scope) {
+ // it can be a package, type or member type
+ Binding binding = scope.getTypeOrPackage(tokens);
+ if (!binding.isValidBinding()) {
+ scope.problemReporter().invalidType(this, (TypeBinding) binding);
+ throw new SelectionNodeFound();
+ }
+
+ throw new SelectionNodeFound(binding);
+ }
+
+ public String toStringExpression(int tab) {
+
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("<SelectOnType:");
+ for (int i = 0, length = tokens.length; i < length; i++) {
+ buffer.append(tokens[i]);
+ if (i != length - 1)
+ buffer.append(".");
+ }
+ buffer.append(">");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnSingleNameReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnSingleNameReference.java
new file mode 100644
index 0000000000..0de9a022c9
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnSingleNameReference.java
@@ -0,0 +1,56 @@
+package org.eclipse.jdt.internal.codeassist.select;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Selection node build by the parser in any case it was intending to
+ * reduce a single name reference containing the assist identifier.
+ * e.g.
+ *
+ * class X {
+ * void foo() {
+ * [start]ba[end]
+ * }
+ * }
+ *
+ * ---> class X {
+ * void foo() {
+ * <SelectOnName:ba>
+ * }
+ * }
+ *
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class SelectionOnSingleNameReference extends SingleNameReference {
+ public SelectionOnSingleNameReference(char[] source, long pos) {
+ super(source, pos);
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ // it can be a package, type, member type, local variable or field
+ binding = scope.getBinding(token, VARIABLE | TYPE | PACKAGE, this);
+ if (!binding.isValidBinding()) {
+ if (binding instanceof ProblemFieldBinding) {
+ scope.problemReporter().invalidField(this, (FieldBinding) binding);
+ } else
+ if (binding instanceof ProblemReferenceBinding) {
+ scope.problemReporter().invalidType(this, (TypeBinding) binding);
+ } else {
+ scope.problemReporter().unresolvableReference(this, binding);
+ }
+ throw new SelectionNodeFound();
+ }
+
+ throw new SelectionNodeFound(binding);
+ }
+
+ public String toStringExpression() {
+ return "<SelectOnName:" + super.toStringExpression() + ">";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnSingleTypeReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnSingleTypeReference.java
new file mode 100644
index 0000000000..cf4acffd43
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnSingleTypeReference.java
@@ -0,0 +1,58 @@
+package org.eclipse.jdt.internal.codeassist.select;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Selection node build by the parser in any case it was intending to
+ * reduce a type reference containing the selection identifier as a single
+ * name reference.
+ * e.g.
+ *
+ * class X extends [start]Object[end]
+ *
+ * ---> class X extends <SelectOnType:Object>
+ *
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class SelectionOnSingleTypeReference extends SingleTypeReference {
+ public SelectionOnSingleTypeReference(char[] source, long pos) {
+ super(source, pos);
+ }
+
+ public void aboutToResolve(Scope scope) {
+ getTypeBinding(scope.parent); // step up from the ClassScope
+ }
+
+ public TypeBinding getTypeBinding(Scope scope) {
+ // it can be a package, type or member type
+ Binding binding = scope.getTypeOrPackage(new char[][] { token });
+ if (!binding.isValidBinding()) {
+ scope.problemReporter().invalidType(this, (TypeBinding) binding);
+ throw new SelectionNodeFound();
+ }
+
+ throw new SelectionNodeFound(binding);
+ }
+
+ public TypeBinding resolveTypeEnclosing(
+ BlockScope scope,
+ ReferenceBinding enclosingType) {
+ super.resolveTypeEnclosing(scope, enclosingType);
+
+ if (binding == null || !binding.isValidBinding())
+ throw new SelectionNodeFound();
+ else
+ throw new SelectionNodeFound(binding);
+ }
+
+ public String toStringExpression(int tab) {
+
+ return "<SelectOnType:" + new String(token) + ">";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnSuperReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnSuperReference.java
new file mode 100644
index 0000000000..403e977ada
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnSuperReference.java
@@ -0,0 +1,55 @@
+package org.eclipse.jdt.internal.codeassist.select;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Selection node build by the parser in any case it was intending to
+ * reduce a super reference containing the assist identifier.
+ * e.g.
+ *
+ * class X extends Z {
+ * class Y {
+ * void foo() {
+ * [start]super[end].bar();
+ * }
+ * }
+ * }
+ *
+ * ---> class X {
+ * class Y {
+ * void foo() {
+ * <SelectOnQualifiedSuper:super>
+ * }
+ * }
+ * }
+ *
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+
+public class SelectionOnSuperReference extends SuperReference {
+
+ public SelectionOnSuperReference(int pos, int sourceEnd) {
+ super(pos, sourceEnd);
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ TypeBinding binding = super.resolveType(scope);
+
+ if (binding == null || !binding.isValidBinding())
+ throw new SelectionNodeFound();
+ else
+ throw new SelectionNodeFound(binding);
+ }
+
+ public String toStringExpression() {
+
+ return "<SelectOnSuper:" + super.toStringExpression() + ">";
+
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionParser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionParser.java
new file mode 100644
index 0000000000..a13352e9f4
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionParser.java
@@ -0,0 +1,577 @@
+package org.eclipse.jdt.internal.codeassist.select;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Parser able to build specific completion parse nodes, given a cursorLocation.
+ *
+ * Cursor location denotes the position of the last character behind which completion
+ * got requested:
+ * -1 means completion at the very beginning of the source
+ * 0 means completion behind the first character
+ * n means completion behind the n-th character
+ */
+
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.*;
+
+import org.eclipse.jdt.internal.codeassist.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.parser.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+
+public class SelectionParser extends AssistParser {
+
+ /* public fields */
+
+ public int selectionStart, selectionEnd;
+ public AstNode selectionNode;
+
+ public static final char[] SUPER = "super".toCharArray();
+ public SelectionParser(ProblemReporter problemReporter) {
+ super(problemReporter);
+ }
+
+ public char[] assistIdentifier() {
+ return ((SelectionScanner) scanner).selectionIdentifier;
+ }
+
+ protected void attachOrphanCompletionNode() {
+ if (isOrphanCompletionNode) {
+ isOrphanCompletionNode = false;
+ Statement statement =
+ (Statement) wrapWithExplicitConstructorCallIfNeeded(this.assistNode);
+ currentElement = currentElement.add(statement, 0);
+ currentToken = 0;
+ // given we are not on an eof, we do not want side effects caused by looked-ahead token
+ }
+ }
+
+ protected void classInstanceCreation(boolean alwaysQualified) {
+ // ClassInstanceCreationExpression ::= 'new' ClassType '(' ArgumentListopt ')' ClassBodyopt
+
+ // ClassBodyopt produces a null item on the astStak if it produces NO class body
+ // An empty class body produces a 0 on the length stack.....
+
+ if (this.indexOfAssistIdentifier() < 0) {
+ super.classInstanceCreation(alwaysQualified);
+ return;
+ }
+ QualifiedAllocationExpression alloc;
+ int length;
+ if (((length = astLengthStack[astLengthPtr--]) == 1)
+ && (astStack[astPtr] == null)) {
+ //NO ClassBody
+ astPtr--;
+ alloc = new SelectionOnQualifiedAllocationExpression();
+ alloc.sourceEnd = endPosition; //the position has been stored explicitly
+
+ if ((length = expressionLengthStack[expressionLengthPtr--]) != 0) {
+ expressionPtr -= length;
+ System.arraycopy(
+ expressionStack,
+ expressionPtr + 1,
+ alloc.arguments = new Expression[length],
+ 0,
+ length);
+ }
+ // trick to avoid creating a selection on type reference
+ char[] oldIdent = this.assistIdentifier();
+ this.setAssistIdentifier(null);
+ alloc.type = getTypeReference(0);
+ this.setAssistIdentifier(oldIdent);
+
+ //the default constructor with the correct number of argument
+ //will be created and added by the TC (see createsInternalConstructorWithBinding)
+ alloc.sourceStart = intStack[intPtr--];
+ pushOnExpressionStack(alloc);
+
+ this.assistNode = alloc;
+ this.lastCheckPoint = alloc.sourceEnd + 1;
+ restartRecovery = true; // force to restart into recovery mode
+ isOrphanCompletionNode = true;
+ }
+ }
+
+ protected void consumeArrayCreationExpression() {
+ // ArrayCreationExpression ::= 'new' PrimitiveType DimWithOrWithOutExprs ArrayInitializeropt
+ // ArrayCreationExpression ::= 'new' ClassOrInterfaceType DimWithOrWithOutExprs ArrayInitializeropt
+
+ super.consumeArrayCreationExpression();
+
+ ArrayAllocationExpression alloc =
+ (ArrayAllocationExpression) expressionStack[expressionPtr];
+ if (alloc.type == assistNode) {
+ restartRecovery = true;
+ isOrphanCompletionNode = true;
+ }
+ }
+
+ protected void consumeEnterAnonymousClassBody() {
+ // EnterAnonymousClassBody ::= $empty
+
+ if (this.indexOfAssistIdentifier() < 0) {
+ super.consumeEnterAnonymousClassBody();
+ return;
+ }
+ QualifiedAllocationExpression alloc;
+ AnonymousLocalTypeDeclaration anonymousType =
+ new AnonymousLocalTypeDeclaration();
+ alloc =
+ anonymousType.allocation =
+ new SelectionOnQualifiedAllocationExpression(anonymousType);
+ pushOnAstStack(anonymousType);
+
+ alloc.sourceEnd = rParenPos; //the position has been stored explicitly
+ int argumentLength;
+ if ((argumentLength = expressionLengthStack[expressionLengthPtr--]) != 0) {
+ expressionPtr -= argumentLength;
+ System.arraycopy(
+ expressionStack,
+ expressionPtr + 1,
+ alloc.arguments = new Expression[argumentLength],
+ 0,
+ argumentLength);
+ }
+ // trick to avoid creating a selection on type reference
+ char[] oldIdent = this.assistIdentifier();
+ this.setAssistIdentifier(null);
+ alloc.type = getTypeReference(0);
+ this.setAssistIdentifier(oldIdent);
+
+ anonymousType.sourceEnd = alloc.sourceEnd;
+ //position at the type while it impacts the anonymous declaration
+ anonymousType.sourceStart =
+ anonymousType.declarationSourceStart = alloc.type.sourceStart;
+ alloc.sourceStart = intStack[intPtr--];
+ pushOnExpressionStack(alloc);
+
+ assistNode = alloc;
+ this.lastCheckPoint = alloc.sourceEnd + 1;
+ restartRecovery = true; // force to restart into recovery mode
+ isOrphanCompletionNode = true;
+
+ anonymousType.bodyStart = scanner.currentPosition;
+ listLength = 0; // will be updated when reading super-interfaces
+ // recovery
+ if (currentElement != null) {
+ lastCheckPoint = anonymousType.bodyStart;
+ currentElement = currentElement.add(anonymousType, 0);
+ // the recoveryTokenCheck will deal with the open brace
+ lastIgnoredToken = -1;
+ }
+ }
+
+ protected void consumeEnterVariable() {
+ // EnterVariable ::= $empty
+ // do nothing by default
+
+ super.consumeEnterVariable();
+
+ AbstractVariableDeclaration variable =
+ (AbstractVariableDeclaration) astStack[astPtr];
+ if (variable.type == assistNode) {
+ restartRecovery = true;
+ isOrphanCompletionNode = false; // already attached inside variable decl
+ }
+ }
+
+ protected void consumeFieldAccess(boolean isSuperAccess) {
+ // FieldAccess ::= Primary '.' 'Identifier'
+ // FieldAccess ::= 'super' '.' 'Identifier'
+
+ if (this.indexOfAssistIdentifier() < 0) {
+ super.consumeFieldAccess(isSuperAccess);
+ return;
+ }
+ FieldReference fieldReference =
+ new SelectionOnFieldReference(
+ identifierStack[identifierPtr],
+ identifierPositionStack[identifierPtr--]);
+ identifierLengthPtr--;
+ if (isSuperAccess) { //considerates the fieldReferenceerence beginning at the 'super' ....
+ fieldReference.sourceStart = intStack[intPtr--];
+ fieldReference.receiver =
+ new SuperReference(fieldReference.sourceStart, endPosition);
+ pushOnExpressionStack(fieldReference);
+ } else { //optimize push/pop
+ if ((fieldReference.receiver = expressionStack[expressionPtr]).isThis()) {
+ //fieldReferenceerence begins at the this
+ fieldReference.sourceStart = fieldReference.receiver.sourceStart;
+ }
+ expressionStack[expressionPtr] = fieldReference;
+ }
+ assistNode = fieldReference;
+ this.lastCheckPoint = fieldReference.sourceEnd + 1;
+ restartRecovery = true; // force to restart in recovery mode
+ isOrphanCompletionNode = true;
+ }
+
+ protected void consumeMethodInvocationName() {
+ // MethodInvocation ::= Name '(' ArgumentListopt ')'
+
+ // when the name is only an identifier...we have a message send to "this" (implicit)
+
+ char[] selector = identifierStack[identifierPtr];
+ if (!(selector == this.assistIdentifier()
+ && CharOperation.equals(selector, SUPER))) {
+ super.consumeMethodInvocationName();
+ return;
+ }
+ ExplicitConstructorCall constructorCall =
+ new SelectionOnExplicitConstructorCall(ExplicitConstructorCall.Super);
+ constructorCall.sourceEnd = rParenPos;
+ constructorCall.sourceStart =
+ (int) (identifierPositionStack[identifierPtr] >>> 32);
+ int length;
+ if ((length = expressionLengthStack[expressionLengthPtr--]) != 0) {
+ expressionPtr -= length;
+ System.arraycopy(
+ expressionStack,
+ expressionPtr + 1,
+ constructorCall.arguments = new Expression[length],
+ 0,
+ length);
+ }
+
+ pushOnAstStack(constructorCall);
+ this.assistNode = constructorCall;
+ this.lastCheckPoint = constructorCall.sourceEnd + 1;
+ restartRecovery = true; // force to restart in recovery mode
+ isOrphanCompletionNode = true;
+ }
+
+ protected void consumeMethodInvocationPrimary() {
+ //optimize the push/pop
+ //MethodInvocation ::= Primary '.' 'Identifier' '(' ArgumentListopt ')'
+
+ char[] selector = identifierStack[identifierPtr];
+ if (!(selector == this.assistIdentifier()
+ && CharOperation.equals(selector, SUPER))) {
+ super.consumeMethodInvocationPrimary();
+ return;
+ }
+ ExplicitConstructorCall constructorCall =
+ new SelectionOnExplicitConstructorCall(ExplicitConstructorCall.Super);
+ constructorCall.sourceEnd = rParenPos;
+ int length;
+ if ((length = expressionLengthStack[expressionLengthPtr--]) != 0) {
+ expressionPtr -= length;
+ System.arraycopy(
+ expressionStack,
+ expressionPtr + 1,
+ constructorCall.arguments = new Expression[length],
+ 0,
+ length);
+ }
+ constructorCall.qualification = expressionStack[expressionPtr--];
+ constructorCall.sourceStart = constructorCall.qualification.sourceStart;
+
+ pushOnAstStack(constructorCall);
+ this.assistNode = constructorCall;
+ this.lastCheckPoint = constructorCall.sourceEnd + 1;
+ restartRecovery = true; // force to restart in recovery mode
+ isOrphanCompletionNode = true;
+ }
+
+ protected void consumeTypeImportOnDemandDeclarationName() {
+ // TypeImportOnDemandDeclarationName ::= 'import' Name '.' '*'
+ /* push an ImportRef build from the last name
+ stored in the identifier stack. */
+
+ int index;
+
+ /* no need to take action if not inside assist identifiers */
+ if ((index = indexOfAssistIdentifier()) < 0) {
+ super.consumeTypeImportOnDemandDeclarationName();
+ return;
+ }
+ /* retrieve identifiers subset and whole positions, the assist node positions
+ should include the entire replaced source. */
+ int length = identifierLengthStack[identifierLengthPtr];
+ char[][] subset = identifierSubSet(index + 1); // include the assistIdentifier
+ identifierLengthPtr--;
+ identifierPtr -= length;
+ long[] positions = new long[length];
+ System.arraycopy(
+ identifierPositionStack,
+ identifierPtr + 1,
+ positions,
+ 0,
+ length);
+
+ /* build specific assist node on import statement */
+ ImportReference reference = this.createAssistImportReference(subset, positions);
+ reference.onDemand = true;
+ assistNode = reference;
+ this.lastCheckPoint = reference.sourceEnd + 1;
+
+ pushOnAstStack(reference);
+
+ if (currentToken == TokenNameSEMICOLON) {
+ reference.declarationSourceEnd = scanner.currentPosition - 1;
+ } else {
+ reference.declarationSourceEnd = (int) positions[length - 1];
+ }
+ //endPosition is just before the ;
+ reference.declarationSourceStart = intStack[intPtr--];
+ // flush annotations defined prior to import statements
+ reference.declarationSourceEnd =
+ this.flushAnnotationsDefinedPriorTo(reference.declarationSourceEnd);
+
+ // recovery
+ if (currentElement != null) {
+ lastCheckPoint = reference.declarationSourceEnd + 1;
+ currentElement = currentElement.add(reference, 0);
+ lastIgnoredToken = -1;
+ restartRecovery = true;
+ // used to avoid branching back into the regular automaton
+ }
+ }
+
+ public ImportReference createAssistImportReference(
+ char[][] tokens,
+ long[] positions) {
+ return new SelectionOnImportReference(tokens, positions);
+ }
+
+ public ImportReference createAssistPackageReference(
+ char[][] tokens,
+ long[] positions) {
+ return new SelectionOnPackageReference(tokens, positions);
+ }
+
+ public NameReference createQualifiedAssistNameReference(
+ char[][] previousIdentifiers,
+ char[] name,
+ long[] positions) {
+ return new SelectionOnQualifiedNameReference(
+ previousIdentifiers,
+ name,
+ positions);
+ }
+
+ public TypeReference createQualifiedAssistTypeReference(
+ char[][] previousIdentifiers,
+ char[] name,
+ long[] positions) {
+ return new SelectionOnQualifiedTypeReference(
+ previousIdentifiers,
+ name,
+ positions);
+ }
+
+ public NameReference createSingleAssistNameReference(
+ char[] name,
+ long position) {
+ return new SelectionOnSingleNameReference(name, position);
+ }
+
+ public TypeReference createSingleAssistTypeReference(
+ char[] name,
+ long position) {
+ return new SelectionOnSingleTypeReference(name, position);
+ }
+
+ public CompilationUnitDeclaration dietParse(
+ ICompilationUnit sourceUnit,
+ CompilationResult compilationResult,
+ int selectionStart,
+ int selectionEnd) {
+
+ this.selectionStart = selectionStart;
+ this.selectionEnd = selectionEnd;
+ SelectionScanner selectionScanner = (SelectionScanner) this.scanner;
+ selectionScanner.selectionIdentifier = null;
+ selectionScanner.selectionStart = selectionStart;
+ selectionScanner.selectionEnd = selectionEnd;
+ return this.dietParse(sourceUnit, compilationResult);
+ }
+
+ /*
+ * Flush parser/scanner state regarding to code assist
+ */
+ public void flushAssistState() {
+
+ super.flushAssistState();
+ this.selectionNode = null;
+ this.setAssistIdentifier(null);
+ }
+
+ protected NameReference getUnspecifiedReference() {
+ /* build a (unspecified) NameReference which may be qualified*/
+
+ int completionIndex;
+
+ /* no need to take action if not inside completed identifiers */
+ if ((completionIndex = indexOfAssistIdentifier()) < 0) {
+ return super.getUnspecifiedReference();
+ }
+
+ int length = identifierLengthStack[identifierLengthPtr];
+ if (CharOperation.equals(assistIdentifier(), SUPER)) {
+ Reference reference;
+ if (completionIndex > 0) { // qualified super
+ // discard 'super' from identifier stacks
+ identifierLengthStack[identifierLengthPtr] = completionIndex;
+ int ptr = identifierPtr -= (length - completionIndex);
+ reference =
+ new SelectionOnQualifiedSuperReference(
+ getTypeReference(0),
+ (int) (identifierPositionStack[ptr + 1] >>> 32),
+ (int) identifierPositionStack[ptr + 1]);
+ } else { // standard super
+ identifierPtr -= length;
+ identifierLengthPtr--;
+ reference =
+ new SelectionOnSuperReference(
+ (int) (identifierPositionStack[identifierPtr + 1] >>> 32),
+ (int) identifierPositionStack[identifierPtr + 1]);
+ }
+ pushOnAstStack(reference);
+ this.assistNode = reference;
+ this.lastCheckPoint = reference.sourceEnd + 1;
+ restartRecovery = true; // force to restart in recovery mode
+ isOrphanCompletionNode = true;
+ return new SingleNameReference(new char[0], 0); // dummy reference
+ }
+ NameReference nameReference;
+ /* retrieve identifiers subset and whole positions, the completion node positions
+ should include the entire replaced source. */
+ char[][] subset = identifierSubSet(completionIndex);
+ identifierLengthPtr--;
+ identifierPtr -= length;
+ long[] positions = new long[length];
+ System.arraycopy(
+ identifierPositionStack,
+ identifierPtr + 1,
+ positions,
+ 0,
+ length);
+ /* build specific completion on name reference */
+ if (completionIndex == 0) {
+ /* completion inside first identifier */
+ nameReference =
+ this.createSingleAssistNameReference(assistIdentifier(), positions[0]);
+ } else {
+ /* completion inside subsequent identifier */
+ nameReference =
+ this.createQualifiedAssistNameReference(subset, assistIdentifier(), positions);
+ }
+ assistNode = nameReference;
+ this.lastCheckPoint = nameReference.sourceEnd + 1;
+ isOrphanCompletionNode = true;
+ restartRecovery = true; // force to restart into recovery mode
+ return nameReference;
+ }
+
+ /*
+ * Copy of code from superclass with the following change:
+ * In the case of qualified name reference if the cursor location is on the
+ * qualified name reference, then create a CompletionOnQualifiedNameReference
+ * instead.
+ */
+ protected NameReference getUnspecifiedReferenceOptimized() {
+
+ int index = indexOfAssistIdentifier();
+ NameReference reference = super.getUnspecifiedReferenceOptimized();
+
+ if (index >= 0) {
+ restartRecovery = true; // force to stop and restart in recovery mode
+ isOrphanCompletionNode = true;
+ }
+ return reference;
+ }
+
+ public void initializeScanner() {
+ this.scanner = new SelectionScanner();
+ }
+
+ protected MessageSend newMessageSend() {
+ // '(' ArgumentListopt ')'
+ // the arguments are on the expression stack
+
+ char[] selector = identifierStack[identifierPtr];
+ if (selector != this.assistIdentifier()) {
+ return super.newMessageSend();
+ }
+ MessageSend messageSend = new SelectionOnMessageSend();
+ int length;
+ if ((length = expressionLengthStack[expressionLengthPtr--]) != 0) {
+ expressionPtr -= length;
+ System.arraycopy(
+ expressionStack,
+ expressionPtr + 1,
+ messageSend.arguments = new Expression[length],
+ 0,
+ length);
+ };
+ assistNode = messageSend;
+ restartRecovery = true; // force to restart in recovery mode
+ isOrphanCompletionNode = true;
+ return messageSend;
+ }
+
+ public CompilationUnitDeclaration parse(
+ ICompilationUnit sourceUnit,
+ CompilationResult compilationResult,
+ int selectionStart,
+ int selectionEnd) {
+
+ this.selectionStart = selectionStart;
+ this.selectionEnd = selectionEnd;
+ SelectionScanner selectionScanner = (SelectionScanner) this.scanner;
+ selectionScanner.selectionIdentifier = null;
+ selectionScanner.selectionStart = selectionStart;
+ selectionScanner.selectionEnd = selectionEnd;
+ return this.parse(sourceUnit, compilationResult);
+ }
+
+ /*
+ * Reset context so as to resume to regular parse loop
+ * If unable to reset for resuming, answers false.
+ *
+ * Move checkpoint location, reset internal stacks and
+ * decide which grammar goal is activated.
+ */
+ protected boolean resumeAfterRecovery() {
+
+ /* if reached assist node inside method body, but still inside nested type,
+ should continue in diet mode until the end of the method body */
+ if (this.assistNode != null
+ && !(referenceContext instanceof CompilationUnitDeclaration)) {
+ currentElement.preserveEnclosingBlocks();
+ if (currentElement.enclosingType() == null) {
+ this.resetStacks();
+ return false;
+ }
+ }
+ return super.resumeAfterRecovery();
+ }
+
+ public void setAssistIdentifier(char[] assistIdent) {
+ ((SelectionScanner) scanner).selectionIdentifier = assistIdent;
+ }
+
+ /*
+ * Update recovery state based on current parser/scanner state
+ */
+ protected void updateRecoveryState() {
+
+ /* expose parser state to recovery state */
+ currentElement.updateFromParserState();
+
+ /* may be able to retrieve completionNode as an orphan, and then attach it */
+ this.attachOrphanCompletionNode();
+
+ /* check and update recovered state based on current token,
+ this action is also performed when shifting token after recovery
+ got activated once.
+ */
+ this.recoveryTokenCheck();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionScanner.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionScanner.java
new file mode 100644
index 0000000000..c6d1122981
--- /dev/null
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionScanner.java
@@ -0,0 +1,68 @@
+package org.eclipse.jdt.internal.codeassist.select;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Scanner aware of a selection range. If finding an identifier which source range is exactly
+ * the same, then will record it so that the parser can make use of it.
+ *
+ * Source positions are zero-based and inclusive.
+ */
+import org.eclipse.jdt.internal.compiler.parser.*;
+
+public class SelectionScanner extends Scanner {
+
+ public char[] selectionIdentifier;
+ public int selectionStart, selectionEnd;
+ /*
+ * Truncate the current identifier if it is containing the cursor location. Since completion is performed
+ * on an identifier prefix.
+ *
+ */
+ public char[] getCurrentIdentifierSource() {
+
+ if (selectionIdentifier == null) {
+ if (selectionStart == startPosition && selectionEnd == currentPosition - 1) {
+ if (withoutUnicodePtr != 0) { // check unicode scenario
+ System.arraycopy(
+ withoutUnicodeBuffer,
+ 1,
+ selectionIdentifier = new char[withoutUnicodePtr],
+ 0,
+ withoutUnicodePtr);
+ } else {
+ int length = currentPosition - startPosition;
+ // no char[] sharing around completionIdentifier, we want it to be unique so as to use identity checks
+ System.arraycopy(
+ source,
+ startPosition,
+ (selectionIdentifier = new char[length]),
+ 0,
+ length);
+ }
+ return selectionIdentifier;
+ }
+ }
+ return super.getCurrentIdentifierSource();
+ }
+
+ /*
+ * In case we actually read a keyword which corresponds to the selected
+ * range, we pretend we read an identifier.
+ */
+ public int scanIdentifierOrKeyword() throws InvalidInputException {
+
+ int id = super.scanIdentifierOrKeyword();
+
+ // convert completed keyword into an identifier
+ if (id != TokenNameIdentifier
+ && startPosition == selectionStart
+ && currentPosition == selectionEnd + 1) {
+ return TokenNameIdentifier;
+ }
+ return id;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/AbstractSyntaxTreeVisitorAdapter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/AbstractSyntaxTreeVisitorAdapter.java
new file mode 100644
index 0000000000..3ab4034561
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/AbstractSyntaxTreeVisitorAdapter.java
@@ -0,0 +1,641 @@
+package org.eclipse.jdt.internal.compiler;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+/**
+ * An adapter class for interating through the parse tree.
+ */
+
+public class AbstractSyntaxTreeVisitorAdapter
+ implements IAbstractSyntaxTreeVisitor {
+
+ public void acceptProblem(IProblem problem) {
+ }
+
+ public void endVisit(
+ AllocationExpression allocationExpression,
+ BlockScope scope) {
+ }
+
+ public void endVisit(AND_AND_Expression and_and_Expression, BlockScope scope) {
+ }
+
+ public void endVisit(
+ AnonymousLocalTypeDeclaration anonymousTypeDeclaration,
+ BlockScope scope) {
+ }
+
+ public void endVisit(Argument argument, BlockScope scope) {
+ }
+
+ public void endVisit(
+ ArrayAllocationExpression arrayAllocationExpression,
+ BlockScope scope) {
+ }
+
+ public void endVisit(ArrayInitializer arrayInitializer, BlockScope scope) {
+ }
+
+ public void endVisit(
+ ArrayQualifiedTypeReference arrayQualifiedTypeReference,
+ BlockScope scope) {
+ }
+
+ public void endVisit(
+ ArrayQualifiedTypeReference arrayQualifiedTypeReference,
+ ClassScope scope) {
+ }
+
+ public void endVisit(ArrayReference arrayReference, BlockScope scope) {
+ }
+
+ public void endVisit(ArrayTypeReference arrayTypeReference, BlockScope scope) {
+ }
+
+ public void endVisit(ArrayTypeReference arrayTypeReference, ClassScope scope) {
+ }
+
+ public void endVisit(Assignment assignment, BlockScope scope) {
+ }
+
+ public void endVisit(BinaryExpression binaryExpression, BlockScope scope) {
+ }
+
+ public void endVisit(Block block, BlockScope scope) {
+ }
+
+ public void endVisit(Break breakStatement, BlockScope scope) {
+ }
+
+ public void endVisit(Case caseStatement, BlockScope scope) {
+ }
+
+ public void endVisit(CastExpression castExpression, BlockScope scope) {
+ }
+
+ public void endVisit(CharLiteral charLiteral, BlockScope scope) {
+ }
+
+ public void endVisit(ClassLiteralAccess classLiteral, BlockScope scope) {
+ }
+
+ public void endVisit(Clinit clinit, ClassScope scope) {
+ }
+
+ public void endVisit(
+ CompilationUnitDeclaration compilationUnitDeclaration,
+ CompilationUnitScope scope) {
+ }
+
+ public void endVisit(CompoundAssignment compoundAssignment, BlockScope scope) {
+ }
+
+ public void endVisit(
+ ConditionalExpression conditionalExpression,
+ BlockScope scope) {
+ }
+
+ public void endVisit(
+ ConstructorDeclaration constructorDeclaration,
+ ClassScope scope) {
+ }
+
+ public void endVisit(Continue continueStatement, BlockScope scope) {
+ }
+
+ public void endVisit(DefaultCase defaultCaseStatement, BlockScope scope) {
+ }
+
+ public void endVisit(DoStatement doStatement, BlockScope scope) {
+ }
+
+ public void endVisit(DoubleLiteral doubleLiteral, BlockScope scope) {
+ }
+
+ public void endVisit(EqualExpression equalExpression, BlockScope scope) {
+ }
+
+ public void endVisit(
+ ExplicitConstructorCall explicitConstructor,
+ BlockScope scope) {
+ }
+
+ public void endVisit(
+ ExtendedStringLiteral extendedStringLiteral,
+ BlockScope scope) {
+ }
+
+ public void endVisit(FalseLiteral falseLiteral, BlockScope scope) {
+ }
+
+ public void endVisit(FieldDeclaration fieldDeclaration, MethodScope scope) {
+ }
+
+ public void endVisit(FieldReference fieldReference, BlockScope scope) {
+ }
+
+ public void endVisit(FloatLiteral floatLiteral, BlockScope scope) {
+ }
+
+ public void endVisit(ForStatement forStatement, BlockScope scope) {
+ }
+
+ public void endVisit(IfStatement ifStatement, BlockScope scope) {
+ }
+
+ public void endVisit(ImportReference importRef, CompilationUnitScope scope) {
+ }
+
+ public void endVisit(Initializer initializer, MethodScope scope) {
+ }
+
+ public void endVisit(
+ InstanceOfExpression instanceOfExpression,
+ BlockScope scope) {
+ }
+
+ public void endVisit(IntLiteral intLiteral, BlockScope scope) {
+ }
+
+ public void endVisit(LabeledStatement labeledStatement, BlockScope scope) {
+ }
+
+ public void endVisit(LocalDeclaration localDeclaration, BlockScope scope) {
+ }
+
+ public void endVisit(
+ LocalTypeDeclaration localTypeDeclaration,
+ MethodScope scope) {
+ }
+
+ public void endVisit(LongLiteral longLiteral, BlockScope scope) {
+ }
+
+ public void endVisit(
+ MemberTypeDeclaration memberTypeDeclaration,
+ ClassScope scope) {
+ }
+
+ public void endVisit(MessageSend messageSend, BlockScope scope) {
+ }
+
+ public void endVisit(MethodDeclaration methodDeclaration, ClassScope scope) {
+ }
+
+ public void endVisit(NullLiteral nullLiteral, BlockScope scope) {
+ }
+
+ public void endVisit(OR_OR_Expression or_or_Expression, BlockScope scope) {
+ }
+
+ public void endVisit(PostfixExpression postfixExpression, BlockScope scope) {
+ }
+
+ public void endVisit(PrefixExpression prefixExpression, BlockScope scope) {
+ }
+
+ public void endVisit(
+ QualifiedAllocationExpression qualifiedAllocationExpression,
+ BlockScope scope) {
+ }
+
+ public void endVisit(
+ QualifiedNameReference qualifiedNameReference,
+ BlockScope scope) {
+ }
+
+ public void endVisit(
+ QualifiedSuperReference qualifiedSuperReference,
+ BlockScope scope) {
+ }
+
+ public void endVisit(
+ QualifiedThisReference qualifiedThisReference,
+ BlockScope scope) {
+ }
+
+ public void endVisit(
+ QualifiedTypeReference qualifiedTypeReference,
+ BlockScope scope) {
+ }
+
+ public void endVisit(
+ QualifiedTypeReference qualifiedTypeReference,
+ ClassScope scope) {
+ }
+
+ public void endVisit(ReturnStatement returnStatement, BlockScope scope) {
+ }
+
+ public void endVisit(
+ SingleNameReference singleNameReference,
+ BlockScope scope) {
+ }
+
+ public void endVisit(
+ SingleTypeReference singleTypeReference,
+ BlockScope scope) {
+ }
+
+ public void endVisit(
+ SingleTypeReference singleTypeReference,
+ ClassScope scope) {
+ }
+
+ public void endVisit(StringLiteral stringLiteral, BlockScope scope) {
+ }
+
+ public void endVisit(SuperReference superReference, BlockScope scope) {
+ }
+
+ public void endVisit(SwitchStatement switchStatement, BlockScope scope) {
+ }
+
+ public void endVisit(
+ SynchronizedStatement synchronizedStatement,
+ BlockScope scope) {
+ }
+
+ public void endVisit(ThisReference thisReference, BlockScope scope) {
+ }
+
+ public void endVisit(ThrowStatement throwStatement, BlockScope scope) {
+ }
+
+ public void endVisit(TrueLiteral trueLiteral, BlockScope scope) {
+ }
+
+ public void endVisit(TryStatement tryStatement, BlockScope scope) {
+ }
+
+ public void endVisit(TypeDeclaration typeDeclaration, BlockScope scope) {
+ }
+
+ public void endVisit(TypeDeclaration typeDeclaration, ClassScope scope) {
+ }
+
+ public void endVisit(
+ TypeDeclaration typeDeclaration,
+ CompilationUnitScope scope) {
+ }
+
+ public void endVisit(UnaryExpression unaryExpression, BlockScope scope) {
+ }
+
+ public void endVisit(WhileStatement whileStatement, BlockScope scope) {
+ }
+
+ public boolean visit(
+ AllocationExpression allocationExpression,
+ BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(AND_AND_Expression and_and_Expression, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(
+ AnonymousLocalTypeDeclaration anonymousTypeDeclaration,
+ BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(Argument argument, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(
+ ArrayAllocationExpression arrayAllocationExpression,
+ BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(ArrayInitializer arrayInitializer, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(
+ ArrayQualifiedTypeReference arrayQualifiedTypeReference,
+ BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(
+ ArrayQualifiedTypeReference arrayQualifiedTypeReference,
+ ClassScope scope) {
+ return true;
+ }
+
+ public boolean visit(ArrayReference arrayReference, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(ArrayTypeReference arrayTypeReference, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(ArrayTypeReference arrayTypeReference, ClassScope scope) {
+ return true;
+ }
+
+ public boolean visit(Assignment assignment, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(BinaryExpression binaryExpression, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(Block block, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(Break breakStatement, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(Case caseStatement, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(CastExpression castExpression, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(CharLiteral charLiteral, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(ClassLiteralAccess classLiteral, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(Clinit clinit, ClassScope scope) {
+ return true;
+ }
+
+ public boolean visit(
+ CompilationUnitDeclaration compilationUnitDeclaration,
+ CompilationUnitScope scope) {
+ return true;
+ }
+
+ public boolean visit(CompoundAssignment compoundAssignment, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(
+ ConditionalExpression conditionalExpression,
+ BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(
+ ConstructorDeclaration constructorDeclaration,
+ ClassScope scope) {
+ return true;
+ }
+
+ public boolean visit(Continue continueStatement, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(DefaultCase defaultCaseStatement, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(DoStatement doStatement, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(DoubleLiteral doubleLiteral, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(EqualExpression equalExpression, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(
+ ExplicitConstructorCall explicitConstructor,
+ BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(
+ ExtendedStringLiteral extendedStringLiteral,
+ BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(FalseLiteral falseLiteral, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope) {
+ return true;
+ }
+
+ public boolean visit(FieldReference fieldReference, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(FloatLiteral floatLiteral, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(ForStatement forStatement, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(IfStatement ifStatement, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(ImportReference importRef, CompilationUnitScope scope) {
+ return true;
+ }
+
+ public boolean visit(Initializer initializer, MethodScope scope) {
+ return true;
+ }
+
+ public boolean visit(
+ InstanceOfExpression instanceOfExpression,
+ BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(IntLiteral intLiteral, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(LabeledStatement labeledStatement, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(LocalDeclaration localDeclaration, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(
+ LocalTypeDeclaration localTypeDeclaration,
+ MethodScope scope) {
+ return true;
+ }
+
+ public boolean visit(LongLiteral longLiteral, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(
+ MemberTypeDeclaration memberTypeDeclaration,
+ ClassScope scope) {
+ return true;
+ }
+
+ public boolean visit(MessageSend messageSend, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) {
+ return true;
+ }
+
+ public boolean visit(NullLiteral nullLiteral, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(OR_OR_Expression or_or_Expression, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(PostfixExpression postfixExpression, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(PrefixExpression prefixExpression, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(
+ QualifiedAllocationExpression qualifiedAllocationExpression,
+ BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(
+ QualifiedNameReference qualifiedNameReference,
+ BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(
+ QualifiedSuperReference qualifiedSuperReference,
+ BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(
+ QualifiedThisReference qualifiedThisReference,
+ BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(
+ QualifiedTypeReference qualifiedTypeReference,
+ BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(
+ QualifiedTypeReference qualifiedTypeReference,
+ ClassScope scope) {
+ return true;
+ }
+
+ public boolean visit(ReturnStatement returnStatement, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(
+ SingleNameReference singleNameReference,
+ BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(
+ SingleTypeReference singleTypeReference,
+ BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(
+ SingleTypeReference singleTypeReference,
+ ClassScope scope) {
+ return true;
+ }
+
+ public boolean visit(StringLiteral stringLiteral, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(SuperReference superReference, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(SwitchStatement switchStatement, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(
+ SynchronizedStatement synchronizedStatement,
+ BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(ThisReference thisReference, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(ThrowStatement throwStatement, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(TrueLiteral trueLiteral, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(TryStatement tryStatement, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(TypeDeclaration typeDeclaration, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(TypeDeclaration typeDeclaration, ClassScope scope) {
+ return true;
+ }
+
+ public boolean visit(
+ TypeDeclaration typeDeclaration,
+ CompilationUnitScope scope) {
+ return true;
+ }
+
+ public boolean visit(UnaryExpression unaryExpression, BlockScope scope) {
+ return true;
+ }
+
+ public boolean visit(WhileStatement whileStatement, BlockScope scope) {
+ return true;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java
new file mode 100644
index 0000000000..a0729e1a84
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java
@@ -0,0 +1,2866 @@
+package org.eclipse.jdt.internal.compiler;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/**
+ * Represents a class file wrapper on bytes, it is aware of its actual
+ * type name.
+ *
+ * Public APIs are listed below:
+ *
+ * byte[] getBytes();
+ * Answer the actual bytes of the class file
+ *
+ * char[][] getCompoundName();
+ * Answer the compound name of the class file.
+ * For example, {{java}, {util}, {Hashtable}}.
+ *
+ * byte[] getReducedBytes();
+ * Answer a smaller byte format, which is only contains some structural
+ * information. Those bytes are decodable with a regular class file reader,
+ * such as DietClassFileReader
+ */
+
+import java.io.*;
+import java.util.*;
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class ClassFile
+ implements AttributeNamesConstants, CompilerModifiers, TypeConstants, TypeIds {
+ public SourceTypeBinding referenceBinding;
+ public ConstantPool constantPool;
+ public ClassFile enclosingClassFile;
+ // used to generate private access methods
+ public int produceDebugAttributes;
+ public ReferenceBinding[] innerClassesBindings;
+ public int numberOfInnerClasses;
+ public byte[] header;
+ // the header contains all the bytes till the end of the constant pool
+ public byte[] contents;
+ // that collection contains all the remaining bytes of the .class file
+ public int headerOffset;
+ public int contentsOffset;
+ public int constantPoolOffset;
+ public int methodCountOffset;
+ public int methodCount;
+ protected boolean creatingProblemType;
+ public static final int INITIAL_CONTENTS_SIZE = 1000;
+ public static final int INITIAL_HEADER_SIZE = 1000;
+ public static final int INCREMENT_SIZE = 1000;
+ public static final int INNER_CLASSES_SIZE = 5;
+ protected CharArrayCache nameUsage;
+ public CodeStream codeStream;
+ protected int problemLine;
+ // used to create line number attributes for problem methods
+ /**
+ * INTERNAL USE-ONLY
+ * This methods creates a new instance of the receiver.
+ */
+ public ClassFile() {
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * This methods creates a new instance of the receiver.
+ *
+ * @param aType org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding
+ * @param enclosingClassFile org.eclipse.jdt.internal.compiler.ClassFile
+ * @param creatingProblemType <CODE>boolean</CODE>
+ */
+ public ClassFile(
+ SourceTypeBinding aType,
+ ClassFile enclosingClassFile,
+ boolean creatingProblemType) {
+ referenceBinding = aType;
+ header = new byte[INITIAL_HEADER_SIZE];
+ // generate the magic numbers inside the header
+ header[headerOffset++] = (byte) (0xCAFEBABEL >> 24);
+ header[headerOffset++] = (byte) (0xCAFEBABEL >> 16);
+ header[headerOffset++] = (byte) (0xCAFEBABEL >> 8);
+ header[headerOffset++] = (byte) (0xCAFEBABEL >> 0);
+ if (((SourceTypeBinding) referenceBinding)
+ .scope
+ .environment()
+ .options
+ .targetJDK
+ == CompilerOptions.JDK1_2) {
+ // Compatible with JDK 1.2
+ header[headerOffset++] = 0;
+ // minorVersion = 0 means we just need to offset the current offset by 2
+ header[headerOffset++] = 0;
+ header[headerOffset++] = 0;
+ header[headerOffset++] = 46;
+ } else {
+ // Compatible with JDK 1.1
+ header[headerOffset++] = 0;
+ header[headerOffset++] = 3;
+ header[headerOffset++] = 0;
+ header[headerOffset++] = 45;
+ }
+ constantPoolOffset = headerOffset;
+ headerOffset += 2;
+ constantPool = new ConstantPool(this);
+ int accessFlags = aType.getAccessFlags() | AccSuper;
+ if (aType.isNestedType()) {
+ if (aType.isStatic()) {
+ // clear Acc_Static
+ accessFlags &= ~AccStatic;
+ }
+ if (aType.isPrivate()) {
+ // clear Acc_Private and Acc_Public
+ accessFlags &= ~(AccPrivate | AccPublic);
+ }
+ if (aType.isProtected()) {
+ // clear Acc_Protected and set Acc_Public
+ accessFlags &= ~AccProtected;
+ accessFlags |= AccPublic;
+ }
+ }
+ // clear all bits that are illegal for a class or an interface
+ accessFlags
+ &= ~(
+ AccStrictfp
+ | AccProtected
+ | AccPrivate
+ | AccStatic
+ | AccSynchronized
+ | AccNative);
+
+ this.enclosingClassFile = enclosingClassFile;
+ // innerclasses get their names computed at code gen time
+ if (aType.isLocalType()) {
+ ((LocalTypeBinding) aType).constantPoolName(
+ computeConstantPoolName((LocalTypeBinding) aType));
+ ReferenceBinding[] memberTypes = aType.memberTypes();
+ for (int i = 0, max = memberTypes.length; i < max; i++) {
+ ((LocalTypeBinding) memberTypes[i]).constantPoolName(
+ computeConstantPoolName((LocalTypeBinding) memberTypes[i]));
+ }
+ }
+ contents = new byte[INITIAL_CONTENTS_SIZE];
+ // now we continue to generate the bytes inside the contents array
+ contents[contentsOffset++] = (byte) (accessFlags >> 8);
+ contents[contentsOffset++] = (byte) accessFlags;
+ int classNameIndex = constantPool.literalIndex(aType);
+ contents[contentsOffset++] = (byte) (classNameIndex >> 8);
+ contents[contentsOffset++] = (byte) classNameIndex;
+ int superclassNameIndex;
+ if (aType.isInterface()) {
+ superclassNameIndex = constantPool.literalIndexForJavaLangObject();
+ } else {
+ superclassNameIndex =
+ (aType.superclass == null ? 0 : constantPool.literalIndex(aType.superclass));
+ }
+ contents[contentsOffset++] = (byte) (superclassNameIndex >> 8);
+ contents[contentsOffset++] = (byte) superclassNameIndex;
+ ReferenceBinding[] superInterfacesBinding = aType.superInterfaces();
+ int interfacesCount = superInterfacesBinding.length;
+ contents[contentsOffset++] = (byte) (interfacesCount >> 8);
+ contents[contentsOffset++] = (byte) interfacesCount;
+ if (superInterfacesBinding != null) {
+ for (int i = 0; i < interfacesCount; i++) {
+ int interfaceIndex = constantPool.literalIndex(superInterfacesBinding[i]);
+ contents[contentsOffset++] = (byte) (interfaceIndex >> 8);
+ contents[contentsOffset++] = (byte) interfaceIndex;
+ }
+ }
+ produceDebugAttributes =
+ ((SourceTypeBinding) referenceBinding)
+ .scope
+ .environment()
+ .options
+ .produceDebugAttributes;
+ innerClassesBindings = new ReferenceBinding[INNER_CLASSES_SIZE];
+ this.creatingProblemType = creatingProblemType;
+ codeStream = new CodeStream(this);
+
+ // retrieve the enclosing one guaranteed to be the one matching the propagated flow info
+ // 1FF9ZBU: LFCOM:ALL - Local variable attributes busted (Sanity check)
+ ClassFile outermostClassFile = this.outerMostEnclosingClassFile();
+ if (this == outermostClassFile) {
+ codeStream.maxFieldCount = aType.scope.referenceType().maxFieldCount;
+ } else {
+ codeStream.maxFieldCount = outermostClassFile.codeStream.maxFieldCount;
+ }
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * Generate the byte for a problem method info that correspond to a boggus method.
+ *
+ * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
+ * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
+ */
+ public void addAbstractMethod(
+ AbstractMethodDeclaration method,
+ MethodBinding methodBinding) {
+
+ // force the modifiers to be public and abstract
+ methodBinding.modifiers = AccPublic | AccAbstract;
+
+ this.generateMethodInfoHeader(methodBinding);
+ int methodAttributeOffset = this.contentsOffset;
+ int attributeNumber = this.generateMethodInfoAttribute(methodBinding);
+ this.completeMethodInfo(methodAttributeOffset, attributeNumber);
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * This methods generate all the attributes for the receiver.
+ * For a class they could be:
+ * - source file attribute
+ * - inner classes attribute
+ * - deprecated attribute
+ */
+ public void addAttributes() {
+ // update the method count
+ contents[methodCountOffset++] = (byte) (methodCount >> 8);
+ contents[methodCountOffset] = (byte) methodCount;
+
+ int attributeNumber = 0;
+ // leave two bytes for the number of attributes and store the current offset
+ int attributeOffset = contentsOffset;
+ contentsOffset += 2;
+
+ // source attribute
+ if ((produceDebugAttributes & CompilerOptions.Source) != 0) {
+ String fullFileName =
+ new String(referenceBinding.scope.referenceCompilationUnit().getFileName());
+ fullFileName = fullFileName.replace('\\', '/');
+ int lastIndex = fullFileName.lastIndexOf('/');
+ if (lastIndex != -1) {
+ fullFileName = fullFileName.substring(lastIndex + 1, fullFileName.length());
+ }
+ // check that there is enough space to write all the bytes for the field info corresponding
+ // to the @fieldBinding
+ int contentsLength;
+ if (contentsOffset + 8 >= (contentsLength = contents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ int sourceAttributeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.SourceName);
+ contents[contentsOffset++] = (byte) (sourceAttributeNameIndex >> 8);
+ contents[contentsOffset++] = (byte) sourceAttributeNameIndex;
+ // The length of a source file attribute is 2. This is a fixed-length
+ // attribute
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 2;
+ // write the source file name
+ int fileNameIndex = constantPool.literalIndex(fullFileName.toCharArray());
+ contents[contentsOffset++] = (byte) (fileNameIndex >> 8);
+ contents[contentsOffset++] = (byte) fileNameIndex;
+ attributeNumber++;
+ }
+
+ // Deprecated attribute
+ if (referenceBinding.isDeprecated()) {
+ // check that there is enough space to write all the bytes for the field info corresponding
+ // to the @fieldBinding
+ int contentsLength;
+ if (contentsOffset + 6 >= (contentsLength = contents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ int deprecatedAttributeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
+ contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8);
+ contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex;
+ // the length of a deprecated attribute is equals to 0
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ attributeNumber++;
+ }
+
+ // Inner class attribute
+ if (numberOfInnerClasses != 0) {
+ // Generate the inner class attribute
+ int contentsLength;
+ int exSize;
+ if (contentsOffset + (exSize = (8 * numberOfInnerClasses + 8))
+ >= (contentsLength = contents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (contents =
+ new byte[contentsLength
+ + (exSize >= INCREMENT_SIZE ? exSize : INCREMENT_SIZE)]),
+ 0,
+ contentsLength);
+ }
+ // Now we now the size of the attribute and the number of entries
+ // attribute name
+ int attributeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.InnerClassName);
+ contents[contentsOffset++] = (byte) (attributeNameIndex >> 8);
+ contents[contentsOffset++] = (byte) attributeNameIndex;
+ int value = (numberOfInnerClasses << 3) + 2;
+ contents[contentsOffset++] = (byte) (value >> 24);
+ contents[contentsOffset++] = (byte) (value >> 16);
+ contents[contentsOffset++] = (byte) (value >> 8);
+ contents[contentsOffset++] = (byte) value;
+ contents[contentsOffset++] = (byte) (numberOfInnerClasses >> 8);
+ contents[contentsOffset++] = (byte) numberOfInnerClasses;
+ for (int i = 0; i < numberOfInnerClasses; i++) {
+ ReferenceBinding innerClass = innerClassesBindings[i];
+ int accessFlags = innerClass.getAccessFlags();
+ int innerClassIndex = constantPool.literalIndex(innerClass);
+ // inner class index
+ contents[contentsOffset++] = (byte) (innerClassIndex >> 8);
+ contents[contentsOffset++] = (byte) innerClassIndex;
+ // outer class index: anonymous and local have no outer class index
+ if (innerClass.isMemberType()) {
+ // member or member of local
+ int outerClassIndex = constantPool.literalIndex(innerClass.enclosingType());
+ contents[contentsOffset++] = (byte) (outerClassIndex >> 8);
+ contents[contentsOffset++] = (byte) outerClassIndex;
+ } else {
+ // equals to 0 if the innerClass is not a member type
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ }
+ // name index
+ if (!innerClass.isAnonymousType()) {
+ int nameIndex = constantPool.literalIndex(innerClass.sourceName());
+ contents[contentsOffset++] = (byte) (nameIndex >> 8);
+ contents[contentsOffset++] = (byte) nameIndex;
+ } else {
+ // equals to 0 if the innerClass is an anonymous type
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ }
+ // access flag
+ if (innerClass.isAnonymousType()) {
+ accessFlags |= AccPrivate;
+ } else
+ if (innerClass.isLocalType() && !innerClass.isMemberType()) {
+ accessFlags |= AccPrivate;
+ }
+ contents[contentsOffset++] = (byte) (accessFlags >> 8);
+ contents[contentsOffset++] = (byte) accessFlags;
+ }
+ attributeNumber++;
+ }
+ // update the number of attributes
+ contents[attributeOffset++] = (byte) (attributeNumber >> 8);
+ contents[attributeOffset] = (byte) attributeNumber;
+
+ // resynchronize all offsets of the classfile
+ header = constantPool.poolContent;
+ headerOffset = constantPool.currentOffset;
+ int constantPoolCount = constantPool.currentIndex;
+ header[constantPoolOffset++] = (byte) (constantPoolCount >> 8);
+ header[constantPoolOffset] = (byte) constantPoolCount;
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * This methods generate all the default abstract method infos that correpond to
+ * the abstract methods inherited from superinterfaces.
+ */
+ public void addDefaultAbstractMethods() { // default abstract methods
+ MethodBinding[] defaultAbstractMethods =
+ referenceBinding.getDefaultAbstractMethods();
+ for (int i = 0, max = defaultAbstractMethods.length; i < max; i++) {
+ generateMethodInfoHeader(defaultAbstractMethods[i]);
+ int methodAttributeOffset = contentsOffset;
+ int attributeNumber = generateMethodInfoAttribute(defaultAbstractMethods[i]);
+ completeMethodInfo(methodAttributeOffset, attributeNumber);
+ }
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * This methods generates the bytes for the field binding passed like a parameter
+ * @param fieldBinding org.eclipse.jdt.internal.compiler.lookup.FieldBinding
+ */
+ public void addFieldInfo(FieldBinding fieldBinding) {
+ int attributeNumber = 0;
+ // check that there is enough space to write all the bytes for the field info corresponding
+ // to the @fieldBinding
+ int contentsLength;
+ if (contentsOffset + 30 >= (contentsLength = contents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ // Generate two attribute: constantValueAttribute and SyntheticAttribute
+ // Now we can generate all entries into the byte array
+ // First the accessFlags
+ int accessFlags = fieldBinding.getAccessFlags();
+ contents[contentsOffset++] = (byte) (accessFlags >> 8);
+ contents[contentsOffset++] = (byte) accessFlags;
+ // Then the nameIndex
+ int nameIndex = constantPool.literalIndex(fieldBinding.name);
+ contents[contentsOffset++] = (byte) (nameIndex >> 8);
+ contents[contentsOffset++] = (byte) nameIndex;
+ // Then the descriptorIndex
+ int descriptorIndex = constantPool.literalIndex(fieldBinding.type.signature());
+ contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
+ contents[contentsOffset++] = (byte) descriptorIndex;
+ // leave some space for the number of attributes
+ int fieldAttributeOffset = contentsOffset;
+ contentsOffset += 2;
+ // 4.7.2 only static constant fields get a ConstantAttribute
+ if (fieldBinding.isStatic()
+ && fieldBinding.constant != Constant.NotAConstant
+ && fieldBinding.constant.typeID() != T_null) {
+ // Now we generate the constant attribute corresponding to the fieldBinding
+ int constantValueNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.ConstantValueName);
+ contents[contentsOffset++] = (byte) (constantValueNameIndex >> 8);
+ contents[contentsOffset++] = (byte) constantValueNameIndex;
+ // The attribute length = 2 in case of a constantValue attribute
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 2;
+ attributeNumber++;
+ // Need to add the constant_value_index
+ switch (fieldBinding.constant.typeID()) {
+ case T_boolean :
+ int booleanValueIndex =
+ constantPool.literalIndex(fieldBinding.constant.booleanValue() ? 1 : 0);
+ contents[contentsOffset++] = (byte) (booleanValueIndex >> 8);
+ contents[contentsOffset++] = (byte) booleanValueIndex;
+ break;
+ case T_byte :
+ case T_char :
+ case T_int :
+ case T_short :
+ int integerValueIndex =
+ constantPool.literalIndex(fieldBinding.constant.intValue());
+ contents[contentsOffset++] = (byte) (integerValueIndex >> 8);
+ contents[contentsOffset++] = (byte) integerValueIndex;
+ break;
+ case T_float :
+ int floatValueIndex =
+ constantPool.literalIndex(fieldBinding.constant.floatValue());
+ contents[contentsOffset++] = (byte) (floatValueIndex >> 8);
+ contents[contentsOffset++] = (byte) floatValueIndex;
+ break;
+ case T_double :
+ int doubleValueIndex =
+ constantPool.literalIndex(fieldBinding.constant.doubleValue());
+ contents[contentsOffset++] = (byte) (doubleValueIndex >> 8);
+ contents[contentsOffset++] = (byte) doubleValueIndex;
+ break;
+ case T_long :
+ int longValueIndex =
+ constantPool.literalIndex(fieldBinding.constant.longValue());
+ contents[contentsOffset++] = (byte) (longValueIndex >> 8);
+ contents[contentsOffset++] = (byte) longValueIndex;
+ break;
+ case T_String :
+ int stringValueIndex =
+ constantPool.literalIndex(
+ ((StringConstant) fieldBinding.constant).stringValue());
+ if (stringValueIndex == -1) {
+ if (!creatingProblemType) {
+ // report an error and abort: will lead to a problem type classfile creation
+ TypeDeclaration typeDeclaration = referenceBinding.scope.referenceContext;
+ FieldDeclaration[] fieldDecls = typeDeclaration.fields;
+ for (int i = 0, max = fieldDecls.length; i < max; i++) {
+ if (fieldDecls[i].binding == fieldBinding) {
+ // problem should abort
+ typeDeclaration.scope.problemReporter().stringConstantIsExceedingUtf8Limit(
+ fieldDecls[i]);
+ }
+ }
+ } else {
+ // already inside a problem type creation : no constant for this field
+ contentsOffset = fieldAttributeOffset + 2;
+ // +2 is necessary to keep the two byte space for the attribute number
+ attributeNumber--;
+ }
+ } else {
+ contents[contentsOffset++] = (byte) (stringValueIndex >> 8);
+ contents[contentsOffset++] = (byte) stringValueIndex;
+ }
+ }
+ }
+ if (fieldBinding.isSynthetic()) {
+ int syntheticAttributeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
+ contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
+ contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
+ // the length of a synthetic attribute is equals to 0
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ attributeNumber++;
+ }
+ if (fieldBinding.isDeprecated()) {
+ int deprecatedAttributeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
+ contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8);
+ contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex;
+ // the length of a deprecated attribute is equals to 0
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ attributeNumber++;
+ }
+ contents[fieldAttributeOffset++] = (byte) (attributeNumber >> 8);
+ contents[fieldAttributeOffset] = (byte) attributeNumber;
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * This methods generate all the fields infos for the receiver.
+ * This includes:
+ * - a field info for each defined field of that class
+ * - a field info for each synthetic field (e.g. this$0)
+ */
+ public void addFieldInfos() {
+ SourceTypeBinding currentBinding = referenceBinding;
+ FieldBinding[] syntheticFields = currentBinding.syntheticFields();
+ int fieldCount =
+ currentBinding.fieldCount()
+ + (syntheticFields == null ? 0 : syntheticFields.length);
+
+ // write the number of fields
+ contents[contentsOffset++] = (byte) (fieldCount >> 8);
+ contents[contentsOffset++] = (byte) fieldCount;
+
+ FieldBinding[] fieldBindings = currentBinding.fields();
+ for (int i = 0, max = fieldBindings.length; i < max; i++) {
+ addFieldInfo(fieldBindings[i]);
+ }
+ if (syntheticFields != null) {
+ for (int i = 0, max = syntheticFields.length; i < max; i++) {
+ addFieldInfo(syntheticFields[i]);
+ }
+ }
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * This methods stores the bindings for each inner class. They will be used to know which entries
+ * have to be generated for the inner classes attributes.
+ * @param referenceBinding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
+ */
+ public void addInnerClasses(ReferenceBinding referenceBinding) {
+ // check first if that reference binding is there
+ for (int i = 0; i < numberOfInnerClasses; i++) {
+ if (innerClassesBindings[i] == referenceBinding)
+ return;
+ }
+ int length = innerClassesBindings.length;
+ if (numberOfInnerClasses == length) {
+ System.arraycopy(
+ innerClassesBindings,
+ 0,
+ (innerClassesBindings = new ReferenceBinding[length * 2]),
+ 0,
+ length);
+ }
+ innerClassesBindings[numberOfInnerClasses++] = referenceBinding;
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * Generate the byte for a problem clinit method info that correspond to a boggus method.
+ *
+ * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[]
+ */
+ public void addProblemClinit(IProblem[] problems) {
+ generateMethodInfoHeaderForClinit();
+ // leave two spaces for the number of attributes
+ contentsOffset -= 2;
+ int attributeOffset = contentsOffset;
+ contentsOffset += 2;
+ ReferenceBinding[] thrownsExceptions;
+ int attributeNumber = 0;
+ int contentsLength;
+
+ int codeAttributeOffset = contentsOffset;
+ generateCodeAttributeHeader();
+ codeStream.resetForProblemClinit(this);
+ String problemString = "";
+ if (problems != null) {
+ int max = problems.length;
+ StringBuffer buffer = new StringBuffer(25);
+ int count = 0;
+ for (int i = 0; i < max; i++) {
+ IProblem problem = problems[i];
+ if ((problem != null) && (problem.isError())) {
+ buffer.append("\t" + problem.getMessage() + "\n");
+ count++;
+ if (problemLine == 0) {
+ problemLine = problem.getSourceLineNumber();
+ }
+ problems[i] = null;
+ }
+ } // insert the top line afterwards, once knowing how many problems we have to consider
+ if (count > 1) {
+ buffer.insert(0, "Unresolved compilation problems: \n");
+ } else {
+ buffer.insert(0, "Unresolved compilation problem: \n");
+ }
+ problemString = buffer.toString();
+ }
+
+ // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
+ int[] exceptionHandler =
+ codeStream.generateCodeAttributeForProblemMethod(
+ referenceBinding
+ .scope
+ .problemReporter()
+ .options
+ .runtimeExceptionNameForCompileError,
+ problemString);
+ attributeNumber++; // code attribute
+ completeCodeAttributeForClinit(
+ codeAttributeOffset,
+ exceptionHandler,
+ referenceBinding
+ .scope
+ .referenceCompilationUnit()
+ .compilationResult
+ .lineSeparatorPositions);
+ contents[attributeOffset++] = (byte) (attributeNumber >> 8);
+ contents[attributeOffset] = (byte) attributeNumber;
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * Generate the byte for a problem method info that correspond to a boggus constructor.
+ *
+ * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
+ * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
+ * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[]
+ */
+ public void addProblemConstructor(
+ AbstractMethodDeclaration method,
+ MethodBinding methodBinding,
+ IProblem[] problems) {
+
+ // always clear the strictfp/native/abstract bit for a problem method
+ methodBinding.modifiers &= ~(AccStrictfp | AccNative | AccAbstract);
+
+ generateMethodInfoHeader(methodBinding);
+ // We know that we won't get more than 1 attribute: the code attribute
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 1; // Code attribute
+ int codeAttributeOffset = contentsOffset;
+ generateCodeAttributeHeader();
+ final ProblemReporter problemReporter = method.scope.problemReporter();
+ codeStream.reset(method, this);
+ String problemString = "";
+ if (problems != null) {
+ int max = problems.length;
+ StringBuffer buffer = new StringBuffer(25);
+ int count = 0;
+ for (int i = 0; i < max; i++) {
+ IProblem problem = problems[i];
+ if ((problem != null) && (problem.isError())) {
+ buffer.append("\t" + problem.getMessage() + "\n");
+ count++;
+ if (problemLine == 0) {
+ problemLine = problem.getSourceLineNumber();
+ }
+ }
+ } // insert the top line afterwards, once knowing how many problems we have to consider
+ if (count > 1) {
+ buffer.insert(0, "Unresolved compilation problems: \n");
+ } else {
+ buffer.insert(0, "Unresolved compilation problem: \n");
+ }
+ problemString = buffer.toString();
+ }
+
+ // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
+ int[] exceptionHandler =
+ codeStream.generateCodeAttributeForProblemMethod(
+ problemReporter.options.runtimeExceptionNameForCompileError,
+ problemString);
+ completeCodeAttributeForProblemMethod(
+ method,
+ methodBinding,
+ codeAttributeOffset,
+ exceptionHandler,
+ ((SourceTypeBinding) methodBinding.declaringClass)
+ .scope
+ .referenceCompilationUnit()
+ .compilationResult
+ .lineSeparatorPositions);
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * Generate the byte for a problem method info that correspond to a boggus constructor.
+ * Reset the position inside the contents byte array to the savedOffset.
+ *
+ * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
+ * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
+ * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[]
+ * @param savedOffset <CODE>int</CODE>
+ */
+ public void addProblemConstructor(
+ AbstractMethodDeclaration method,
+ MethodBinding methodBinding,
+ IProblem[] problems,
+ int savedOffset) {
+ // we need to move back the contentsOffset to the value at the beginning of the method
+ contentsOffset = savedOffset;
+ methodCount--; // we need to remove the method that causes the problem
+ addProblemConstructor(method, methodBinding, problems);
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * Generate the byte for a problem method info that correspond to a boggus method.
+ *
+ * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
+ * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
+ * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[]
+ */
+ public void addProblemMethod(
+ AbstractMethodDeclaration method,
+ MethodBinding methodBinding,
+ IProblem[] problems) {
+ if (methodBinding.isAbstract() && methodBinding.declaringClass.isInterface()) {
+ method.abort(AbstractMethodDeclaration.AbortType);
+ }
+ // always clear the strictfp/native/abstract bit for a problem method
+ methodBinding.modifiers &= ~(AccStrictfp | AccNative | AccAbstract);
+
+ generateMethodInfoHeader(methodBinding);
+ // leave two spaces for the number of attributes
+ int attributeOffset = contentsOffset;
+ contentsOffset += 2;
+ ReferenceBinding[] thrownsExceptions;
+ int attributeNumber = 0;
+ int contentsLength;
+
+ if ((thrownsExceptions = methodBinding.thrownExceptions) != NoExceptions) {
+ // The method has a throw clause. So we need to add an exception attribute
+ // check that there is enough space to write all the bytes for the exception attribute
+ int length = thrownsExceptions.length;
+ if (contentsOffset + (8 + length * 2) >= (contentsLength = contents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (contents =
+ new byte[contentsLength + Math.max(INCREMENT_SIZE, (8 + length * 2))]),
+ 0,
+ contentsLength);
+ }
+ int exceptionNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.ExceptionsName);
+ contents[contentsOffset++] = (byte) (exceptionNameIndex >> 8);
+ contents[contentsOffset++] = (byte) exceptionNameIndex;
+ // The attribute length = length * 2 + 2 in case of a exception attribute
+ int attributeLength = length * 2 + 2;
+ contents[contentsOffset++] = (byte) (attributeLength >> 24);
+ contents[contentsOffset++] = (byte) (attributeLength >> 16);
+ contents[contentsOffset++] = (byte) (attributeLength >> 8);
+ contents[contentsOffset++] = (byte) attributeLength;
+ contents[contentsOffset++] = (byte) (length >> 8);
+ contents[contentsOffset++] = (byte) length;
+ for (int i = 0; i < length; i++) {
+ int exceptionIndex = constantPool.literalIndex(thrownsExceptions[i]);
+ contents[contentsOffset++] = (byte) (exceptionIndex >> 8);
+ contents[contentsOffset++] = (byte) exceptionIndex;
+ }
+ attributeNumber++;
+ }
+
+ // Deprecated attribute
+ // Check that there is enough space to write the deprecated attribute
+ if (contentsOffset + 6 >= (contentsLength = contents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ if (methodBinding.isDeprecated()) {
+ int deprecatedAttributeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
+ contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8);
+ contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex;
+ // the length of a deprecated attribute is equals to 0
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+
+ attributeNumber++;
+ }
+
+ int codeAttributeOffset = contentsOffset;
+ generateCodeAttributeHeader();
+ final ProblemReporter problemReporter = method.scope.problemReporter();
+ codeStream.reset(method, this);
+ String problemString = "";
+ if (problems != null) {
+ int max = problems.length;
+ StringBuffer buffer = new StringBuffer(25);
+ int count = 0;
+ for (int i = 0; i < max; i++) {
+ IProblem problem = problems[i];
+ if ((problem != null)
+ && (problem.isError())
+ && (problem.getSourceStart() >= method.declarationSourceStart)
+ && (problem.getSourceEnd() <= method.declarationSourceEnd)) {
+ buffer.append("\t" + problem.getMessage() + "\n");
+ count++;
+ if (problemLine == 0) {
+ problemLine = problem.getSourceLineNumber();
+ }
+ problems[i] = null;
+ }
+ } // insert the top line afterwards, once knowing how many problems we have to consider
+ if (count > 1) {
+ buffer.insert(0, "Unresolved compilation problems: \n");
+ } else {
+ buffer.insert(0, "Unresolved compilation problem: \n");
+ }
+ problemString = buffer.toString();
+ }
+
+ // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
+ int[] exceptionHandler =
+ codeStream.generateCodeAttributeForProblemMethod(
+ problemReporter.options.runtimeExceptionNameForCompileError,
+ problemString);
+ attributeNumber++; // code attribute
+ completeCodeAttributeForProblemMethod(
+ method,
+ methodBinding,
+ codeAttributeOffset,
+ exceptionHandler,
+ ((SourceTypeBinding) methodBinding.declaringClass)
+ .scope
+ .referenceCompilationUnit()
+ .compilationResult
+ .lineSeparatorPositions);
+ contents[attributeOffset++] = (byte) (attributeNumber >> 8);
+ contents[attributeOffset] = (byte) attributeNumber;
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * Generate the byte for a problem method info that correspond to a boggus method.
+ * Reset the position inside the contents byte array to the savedOffset.
+ *
+ * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
+ * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
+ * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[]
+ * @param savedOffset <CODE>int</CODE>
+ */
+ public void addProblemMethod(
+ AbstractMethodDeclaration method,
+ MethodBinding methodBinding,
+ IProblem[] problems,
+ int savedOffset) {
+ // we need to move back the contentsOffset to the value at the beginning of the method
+ contentsOffset = savedOffset;
+ methodCount--; // we need to remove the method that causes the problem
+ addProblemMethod(method, methodBinding, problems);
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * Generate the byte for all the special method infos.
+ * They are:
+ * - synthetic access methods
+ * - default abstract methods
+ */
+ public void addSpecialMethods() {
+ // add all methods (default abstract methods and synthetic)
+
+ // default abstract methods
+ SourceTypeBinding currentBinding = referenceBinding;
+ MethodBinding[] defaultAbstractMethods =
+ currentBinding.getDefaultAbstractMethods();
+ for (int i = 0, max = defaultAbstractMethods.length; i < max; i++) {
+ generateMethodInfoHeader(defaultAbstractMethods[i]);
+ int methodAttributeOffset = contentsOffset;
+ int attributeNumber = generateMethodInfoAttribute(defaultAbstractMethods[i]);
+ completeMethodInfo(methodAttributeOffset, attributeNumber);
+ }
+
+ // add synthetic methods infos
+ SyntheticAccessMethodBinding[] syntheticAccessMethods =
+ currentBinding.syntheticAccessMethods();
+ if (syntheticAccessMethods != null) {
+ for (int i = 0, max = syntheticAccessMethods.length; i < max; i++) {
+ SyntheticAccessMethodBinding accessMethodBinding = syntheticAccessMethods[i];
+ switch (accessMethodBinding.accessType) {
+ case SyntheticAccessMethodBinding.FieldReadAccess :
+ // generate a method info to emulate an reading access to
+ // a private field
+ addSyntheticFieldReadAccessMethod(syntheticAccessMethods[i]);
+ break;
+ case SyntheticAccessMethodBinding.FieldWriteAccess :
+ // generate a method info to emulate an writing access to
+ // a private field
+ addSyntheticFieldWriteAccessMethod(syntheticAccessMethods[i]);
+ break;
+ case SyntheticAccessMethodBinding.MethodAccess :
+ // generate a method info to emulate an access to a private method
+ addSyntheticMethodAccessMethod(syntheticAccessMethods[i]);
+ break;
+ case SyntheticAccessMethodBinding.ConstructorAccess :
+ // generate a method info to emulate an access to a private method
+ addSyntheticConstructorAccessMethod(syntheticAccessMethods[i]);
+ }
+ }
+ }
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * Generate the byte for a problem method info that correspond to a synthetic method that
+ * generate an access to a private constructor.
+ *
+ * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
+ */
+ public void addSyntheticConstructorAccessMethod(SyntheticAccessMethodBinding methodBinding) {
+ generateMethodInfoHeader(methodBinding);
+ // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 2;
+ // Code attribute
+ int codeAttributeOffset = contentsOffset;
+ generateCodeAttributeHeader();
+ codeStream.init(this);
+ codeStream.generateSyntheticBodyForConstructorAccess(methodBinding);
+ completeCodeAttributeForSyntheticAccessMethod(
+ methodBinding,
+ codeAttributeOffset,
+ ((SourceTypeBinding) methodBinding.declaringClass)
+ .scope
+ .referenceCompilationUnit()
+ .compilationResult
+ .lineSeparatorPositions);
+ // add the synthetic attribute
+ int syntheticAttributeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
+ contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
+ contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
+ // the length of a synthetic attribute is equals to 0
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * Generate the byte for a problem method info that correspond to a synthetic method that
+ * generate an read access to a private field.
+ *
+ * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
+ */
+ public void addSyntheticFieldReadAccessMethod(SyntheticAccessMethodBinding methodBinding) {
+ generateMethodInfoHeader(methodBinding);
+ // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 2;
+ // Code attribute
+ int codeAttributeOffset = contentsOffset;
+ generateCodeAttributeHeader();
+ codeStream.init(this);
+ codeStream.generateSyntheticBodyForFieldReadAccess(methodBinding);
+ completeCodeAttributeForSyntheticAccessMethod(
+ methodBinding,
+ codeAttributeOffset,
+ ((SourceTypeBinding) methodBinding.declaringClass)
+ .scope
+ .referenceCompilationUnit()
+ .compilationResult
+ .lineSeparatorPositions);
+ // add the synthetic attribute
+ int syntheticAttributeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
+ contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
+ contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
+ // the length of a synthetic attribute is equals to 0
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * Generate the byte for a problem method info that correspond to a synthetic method that
+ * generate an write access to a private field.
+ *
+ * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
+ */
+ public void addSyntheticFieldWriteAccessMethod(SyntheticAccessMethodBinding methodBinding) {
+ generateMethodInfoHeader(methodBinding);
+ // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 2;
+ // Code attribute
+ int codeAttributeOffset = contentsOffset;
+ generateCodeAttributeHeader();
+ codeStream.init(this);
+ codeStream.generateSyntheticBodyForFieldWriteAccess(methodBinding);
+ completeCodeAttributeForSyntheticAccessMethod(
+ methodBinding,
+ codeAttributeOffset,
+ ((SourceTypeBinding) methodBinding.declaringClass)
+ .scope
+ .referenceCompilationUnit()
+ .compilationResult
+ .lineSeparatorPositions);
+ // add the synthetic attribute
+ int syntheticAttributeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
+ contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
+ contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
+ // the length of a synthetic attribute is equals to 0
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * Generate the byte for a problem method info that correspond to a synthetic method that
+ * generate an access to a private method.
+ *
+ * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
+ */
+ public void addSyntheticMethodAccessMethod(SyntheticAccessMethodBinding methodBinding) {
+ generateMethodInfoHeader(methodBinding);
+ // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 2;
+ // Code attribute
+ int codeAttributeOffset = contentsOffset;
+ generateCodeAttributeHeader();
+ codeStream.init(this);
+ codeStream.generateSyntheticBodyForMethodAccess(methodBinding);
+ completeCodeAttributeForSyntheticAccessMethod(
+ methodBinding,
+ codeAttributeOffset,
+ ((SourceTypeBinding) methodBinding.declaringClass)
+ .scope
+ .referenceCompilationUnit()
+ .compilationResult
+ .lineSeparatorPositions);
+ // add the synthetic attribute
+ int syntheticAttributeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
+ contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
+ contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
+ // the length of a synthetic attribute is equals to 0
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * Build all the directories and subdirectories corresponding to the packages names
+ * into the directory specified in parameters.
+ *
+ * outputPath is formed like:
+ * c:\temp\ the last character is a file separator
+ * relativeFileName is formed like:
+ * java\lang\String.class *
+ *
+ * @param outputPath java.lang.String
+ * @param relativeFileName java.lang.String
+ * @return java.lang.String
+ */
+ public static String buildAllDirectoriesInto(
+ String outputPath,
+ String relativeFileName)
+ throws IOException {
+ char fileSeparatorChar = File.separatorChar;
+ String fileSeparator = File.separator;
+ File f;
+ // First we ensure that the outputPath exists
+ outputPath = outputPath.replace('/', fileSeparatorChar);
+ // To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name
+ if (outputPath.endsWith(fileSeparator)) {
+ outputPath = outputPath.substring(0, outputPath.length() - 1);
+ }
+ f = new File(outputPath);
+ if (f.exists()) {
+ if (!f.isDirectory()) {
+ System.out.println(" The outDir is a file = " + f.getAbsolutePath());
+ throw new IOException("The outDir is a file not a directory.");
+ }
+ } else {
+ // we have to create that directory
+ if (!f.mkdirs()) {
+ System.out.println(" The output dir name is = " + f.getAbsolutePath());
+ throw new IOException("The outDir is not a valid directory name. All the directories cannot be created.");
+ }
+ }
+ StringBuffer outDir = new StringBuffer(outputPath);
+ outDir.append(fileSeparator);
+ StringTokenizer tokenizer =
+ new StringTokenizer(relativeFileName, fileSeparator);
+ String token = tokenizer.nextToken();
+ while (tokenizer.hasMoreTokens()) {
+ f = new File(outDir.append(token).append(fileSeparator).toString());
+ if (f.exists()) {
+ // The outDir already exists, so we proceed the next entry
+ // System.out.println("outDir: " + outDir + " already exists.");
+ } else {
+ // Need to add the outDir
+ if (!f.mkdir()) {
+ System.out.println(" file name = " + f.getName());
+ throw new IOException("The outDir is not a valid directory name. The directory cannot be created.");
+ }
+ }
+ token = tokenizer.nextToken();
+ }
+ // token contains the last one
+ return outDir.append(token).toString();
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * That method completes the creation of the code attribute by setting
+ * - the attribute_length
+ * - max_stack
+ * - max_locals
+ * - code_length
+ * - exception table
+ * - and debug attributes if necessary.
+ *
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param codeAttributeOffset <CODE>int</CODE>
+ */
+ public void completeCodeAttribute(int codeAttributeOffset) {
+ // reinitialize the localContents with the byte modified by the code stream
+ byte[] localContents = contents = codeStream.bCodeStream;
+ int localContentsOffset = codeStream.classFileOffset;
+ // codeAttributeOffset is the position inside localContents byte array before we started to write
+ // any information about the codeAttribute
+ // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
+ // to get the right position, 6 for the max_stack etc...
+ int contentsLength;
+ int code_length = codeStream.position;
+ if (code_length > 65535) {
+ codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(
+ codeStream.methodDeclaration);
+ }
+ if (localContentsOffset + 20 >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ int max_stack = codeStream.stackMax;
+ localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
+ localContents[codeAttributeOffset + 7] = (byte) max_stack;
+ int max_locals = codeStream.maxLocals;
+ localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
+ localContents[codeAttributeOffset + 9] = (byte) max_locals;
+ localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
+ localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
+ localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
+ localContents[codeAttributeOffset + 13] = (byte) code_length;
+
+ // write the exception table
+ int exceptionHandlersNumber = codeStream.exceptionHandlersNumber;
+ ExceptionLabel[] exceptionHandlers = codeStream.exceptionHandlers;
+ int exSize;
+ if (localContentsOffset + (exSize = (exceptionHandlersNumber * 8 + 2))
+ >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents =
+ contents =
+ new byte[contentsLength + (exSize > INCREMENT_SIZE ? exSize : INCREMENT_SIZE)]),
+ 0,
+ contentsLength);
+ }
+ // there is no exception table, so we need to offset by 2 the current offset and move
+ // on the attribute generation
+ localContents[localContentsOffset++] = (byte) (exceptionHandlersNumber >> 8);
+ localContents[localContentsOffset++] = (byte) exceptionHandlersNumber;
+ for (int i = 0; i < exceptionHandlersNumber; i++) {
+ ExceptionLabel exceptionHandler = exceptionHandlers[i];
+ int start = exceptionHandler.start;
+ localContents[localContentsOffset++] = (byte) (start >> 8);
+ localContents[localContentsOffset++] = (byte) start;
+ int end = exceptionHandler.end;
+ localContents[localContentsOffset++] = (byte) (end >> 8);
+ localContents[localContentsOffset++] = (byte) end;
+ int handlerPC = exceptionHandler.position;
+ localContents[localContentsOffset++] = (byte) (handlerPC >> 8);
+ localContents[localContentsOffset++] = (byte) handlerPC;
+ if (exceptionHandler.exceptionType == null) {
+ // any exception handler
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = 0;
+ } else {
+ int nameIndex;
+ if (exceptionHandler.exceptionType == TypeBinding.NullBinding) {
+ /* represents ClassNotFoundException, see class literal access*/
+ nameIndex = constantPool.literalIndexForJavaLangClassNotFoundException();
+ } else {
+ nameIndex = constantPool.literalIndex(exceptionHandler.exceptionType);
+ }
+ localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
+ localContents[localContentsOffset++] = (byte) nameIndex;
+ }
+ }
+
+ // debug attributes
+ int codeAttributeAttributeOffset = localContentsOffset;
+ int attributeNumber = 0;
+ // leave two bytes for the attribute_length
+ localContentsOffset += 2;
+
+ // first we handle the linenumber attribute
+ if (codeStream.generateLineNumberAttributes) {
+ /* Create and add the line number attribute (used for debugging)
+ * Build the pairs of:
+ * (bytecodePC lineNumber)
+ * according to the table of start line indexes and the pcToSourceMap table
+ * contained into the codestream
+ */
+ /** OLD CODE
+ int[][] pcToSourceMapTable;
+ int previousLineNumber;
+ int[] flatTable;
+ int index;
+ int startLineIndexes[] = codeStream.methodDeclaration.scope.referenceCompilationUnit().compilationResult.lineSeparatorPositions;
+ int max = startLineIndexes.length;
+ */
+ int[] pcToSourceMapTable;
+ if (((pcToSourceMapTable = codeStream.pcToSourceMap) != null)
+ && (codeStream.pcToSourceMapSize != 0)) {
+ int lineNumberNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
+ if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
+ localContents[localContentsOffset++] = (byte) lineNumberNameIndex;
+ int lineNumberTableOffset = localContentsOffset;
+ localContentsOffset += 6;
+ // leave space for attribute_length and line_number_table_length
+ /** OLD CODE
+ previousLineNumber = 0;
+
+ // Seems like do would be better, but this preserves the existing behavior.
+
+ flatTable = new int[code_length];
+ for (int i = codeStream.pcToSourceMapSize - 1; i >= 0; i--) {
+ // entry contains the following structure:
+ // position 1: startPC
+ // position 2: endPC
+ // position 3: sourceStart
+ // position 4: sourceEnd
+ // Compute the line number for a given source position
+ index = searchLineNumber(startLineIndexes, pcToSourceMapTable[i][2]);
+ for (int j = pcToSourceMapTable[i][0]; j < pcToSourceMapTable[i][1]; j++)
+ flatTable[j] = index;
+ }
+ previousLineNumber = -1;
+
+ */
+ int numberOfEntries = 0;
+ int length = codeStream.pcToSourceMapSize;
+ /** OLD CODE
+ int length = flatTable.length;
+ for (int i = 0; i < length; i++) {
+ if (flatTable[i] != previousLineNumber) {
+ previousLineNumber = flatTable[i];
+ // write the entry
+ if (localContentsOffset + 4 >= (contentsLength = localContents.length)) {
+ System.arraycopy(contents, 0, (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]), 0, contentsLength);
+ }
+ localContents[localContentsOffset++] = (byte) (i >> 8);
+ localContents[localContentsOffset++] = (byte) i;
+ localContents[localContentsOffset++] = (byte) (previousLineNumber >> 8);
+ localContents[localContentsOffset++] = (byte) previousLineNumber;
+ numberOfEntries++;
+ }
+ }
+ */
+ for (int i = 0; i < length;) {
+ // write the entry
+ if (localContentsOffset + 4 >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ int pc = pcToSourceMapTable[i++];
+ localContents[localContentsOffset++] = (byte) (pc >> 8);
+ localContents[localContentsOffset++] = (byte) pc;
+ int lineNumber = pcToSourceMapTable[i++];
+ localContents[localContentsOffset++] = (byte) (lineNumber >> 8);
+ localContents[localContentsOffset++] = (byte) lineNumber;
+ numberOfEntries++;
+ }
+ // now we change the size of the line number attribute
+ int lineNumberAttr_length = numberOfEntries * 4 + 2;
+ localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 24);
+ localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 16);
+ localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 8);
+ localContents[lineNumberTableOffset++] = (byte) lineNumberAttr_length;
+ localContents[lineNumberTableOffset++] = (byte) (numberOfEntries >> 8);
+ localContents[lineNumberTableOffset++] = (byte) numberOfEntries;
+ attributeNumber++;
+ }
+ }
+
+ // then we do the local variable attribute
+ if (codeStream.generateLocalVariableTableAttributes) {
+ int localVariableTableOffset = localContentsOffset;
+ int numberOfEntries = 0;
+ int localVariableNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
+ if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ localContents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
+ localContents[localContentsOffset++] = (byte) localVariableNameIndex;
+ localContentsOffset += 6;
+ // leave space for attribute_length and local_variable_table_length
+ int nameIndex;
+ int descriptorIndex;
+ if (!codeStream.methodDeclaration.isStatic()) {
+ numberOfEntries++;
+ if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ localContentsOffset += 2; // the startPC for this is always 0
+ localContents[localContentsOffset++] = (byte) (code_length >> 8);
+ localContents[localContentsOffset++] = (byte) code_length;
+ nameIndex = constantPool.literalIndex(QualifiedNamesConstants.This);
+ localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
+ localContents[localContentsOffset++] = (byte) nameIndex;
+ descriptorIndex =
+ constantPool.literalIndex(
+ codeStream.methodDeclaration.binding.declaringClass.signature());
+ localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
+ localContents[localContentsOffset++] = (byte) descriptorIndex;
+ localContentsOffset += 2; // the resolved position for this is always 0
+ }
+ for (int i = 0; i < codeStream.allLocalsCounter; i++) {
+ LocalVariableBinding localVariable = codeStream.locals[i];
+ for (int j = 0; j < localVariable.initializationCount; j++) {
+ int startPC = localVariable.initializationPCs[j << 1];
+ int endPC = localVariable.initializationPCs[(j << 1) + 1];
+ if (startPC != endPC) { // only entries for non zero length
+ int currentLength;
+ if (endPC == -1) {
+ localVariable.declaringScope.problemReporter().abortDueToInternalError(
+ "SANITY CHECK: Invalid attribute for local variable "
+ + new String(localVariable.name),
+ (AstNode) localVariable.declaringScope.methodScope().referenceContext);
+ }
+ if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ // now we can safely add the local entry
+ numberOfEntries++;
+ localContents[localContentsOffset++] = (byte) (startPC >> 8);
+ localContents[localContentsOffset++] = (byte) startPC;
+ int length = endPC - startPC;
+ localContents[localContentsOffset++] = (byte) (length >> 8);
+ localContents[localContentsOffset++] = (byte) length;
+ nameIndex = constantPool.literalIndex(localVariable.name);
+ localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
+ localContents[localContentsOffset++] = (byte) nameIndex;
+ descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
+ localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
+ localContents[localContentsOffset++] = (byte) descriptorIndex;
+ int resolvedPosition = localVariable.resolvedPosition;
+ localContents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
+ localContents[localContentsOffset++] = (byte) resolvedPosition;
+ }
+ }
+ }
+ int value = numberOfEntries * 10 + 2;
+ localVariableTableOffset += 2;
+ localContents[localVariableTableOffset++] = (byte) (value >> 24);
+ localContents[localVariableTableOffset++] = (byte) (value >> 16);
+ localContents[localVariableTableOffset++] = (byte) (value >> 8);
+ localContents[localVariableTableOffset++] = (byte) value;
+ localContents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
+ localContents[localVariableTableOffset] = (byte) numberOfEntries;
+ attributeNumber++;
+ }
+ // update the number of attributes
+ // ensure first that there is enough space available inside the localContents array
+ if (codeAttributeAttributeOffset + 2
+ >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
+ localContents[codeAttributeAttributeOffset] = (byte) attributeNumber;
+
+ // update the attribute length
+ int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
+ localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
+ localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
+ localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
+ localContents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
+ contentsOffset = localContentsOffset;
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * That method completes the creation of the code attribute by setting
+ * - the attribute_length
+ * - max_stack
+ * - max_locals
+ * - code_length
+ * - exception table
+ * - and debug attributes if necessary.
+ *
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param codeAttributeOffset <CODE>int</CODE>
+ */
+ public void completeCodeAttributeForClinit(int codeAttributeOffset) {
+ // reinitialize the contents with the byte modified by the code stream
+ byte[] localContents = contents = codeStream.bCodeStream;
+ int localContentsOffset = codeStream.classFileOffset;
+ // codeAttributeOffset is the position inside contents byte array before we started to write
+ // any information about the codeAttribute
+ // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
+ // to get the right position, 6 for the max_stack etc...
+ int contentsLength;
+ int code_length = codeStream.position;
+ if (code_length > 65535) {
+ codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(
+ codeStream.methodDeclaration.scope.referenceType());
+ }
+ if (localContentsOffset + 20 >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ int max_stack = codeStream.stackMax;
+ localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
+ localContents[codeAttributeOffset + 7] = (byte) max_stack;
+ int max_locals = codeStream.maxLocals;
+ localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
+ localContents[codeAttributeOffset + 9] = (byte) max_locals;
+ localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
+ localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
+ localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
+ localContents[codeAttributeOffset + 13] = (byte) code_length;
+
+ // write the exception table
+ int exceptionHandlersNumber = codeStream.exceptionHandlersNumber;
+ ExceptionLabel[] exceptionHandlers = codeStream.exceptionHandlers;
+ int exSize;
+ if (localContentsOffset + (exSize = (exceptionHandlersNumber * 8 + 2))
+ >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents =
+ contents =
+ new byte[contentsLength + (exSize > INCREMENT_SIZE ? exSize : INCREMENT_SIZE)]),
+ 0,
+ contentsLength);
+ }
+ // there is no exception table, so we need to offset by 2 the current offset and move
+ // on the attribute generation
+ localContents[localContentsOffset++] = (byte) (exceptionHandlersNumber >> 8);
+ localContents[localContentsOffset++] = (byte) exceptionHandlersNumber;
+ for (int i = 0; i < exceptionHandlersNumber; i++) {
+ ExceptionLabel exceptionHandler = exceptionHandlers[i];
+ int start = exceptionHandler.start;
+ localContents[localContentsOffset++] = (byte) (start >> 8);
+ localContents[localContentsOffset++] = (byte) start;
+ int end = exceptionHandler.end;
+ localContents[localContentsOffset++] = (byte) (end >> 8);
+ localContents[localContentsOffset++] = (byte) end;
+ int handlerPC = exceptionHandler.position;
+ localContents[localContentsOffset++] = (byte) (handlerPC >> 8);
+ localContents[localContentsOffset++] = (byte) handlerPC;
+ if (exceptionHandler.exceptionType == null) {
+ // any exception handler
+ localContentsOffset += 2;
+ } else {
+ int nameIndex;
+ if (exceptionHandler.exceptionType == TypeBinding.NullBinding) {
+ /* represents denote ClassNotFoundException, see class literal access*/
+ nameIndex = constantPool.literalIndexForJavaLangClassNotFoundException();
+ } else {
+ nameIndex = constantPool.literalIndex(exceptionHandler.exceptionType);
+ }
+ localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
+ localContents[localContentsOffset++] = (byte) nameIndex;
+ }
+ }
+
+ // debug attributes
+ int codeAttributeAttributeOffset = localContentsOffset;
+ int attributeNumber = 0;
+ // leave two bytes for the attribute_length
+ localContentsOffset += 2;
+
+ // first we handle the linenumber attribute
+ if (codeStream.generateLineNumberAttributes) {
+ /* Create and add the line number attribute (used for debugging)
+ * Build the pairs of:
+ * (bytecodePC lineNumber)
+ * according to the table of start line indexes and the pcToSourceMap table
+ * contained into the codestream
+ */
+ int[] pcToSourceMapTable;
+ if (((pcToSourceMapTable = codeStream.pcToSourceMap) != null)
+ && (codeStream.pcToSourceMapSize != 0)) {
+ int lineNumberNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
+ if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
+ localContents[localContentsOffset++] = (byte) lineNumberNameIndex;
+ int lineNumberTableOffset = localContentsOffset;
+ localContentsOffset += 6;
+ // leave space for attribute_length and line_number_table_length
+ int numberOfEntries = 0;
+ int length = codeStream.pcToSourceMapSize;
+ for (int i = 0; i < length;) {
+ // write the entry
+ if (localContentsOffset + 4 >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ int pc = pcToSourceMapTable[i++];
+ localContents[localContentsOffset++] = (byte) (pc >> 8);
+ localContents[localContentsOffset++] = (byte) pc;
+ int lineNumber = pcToSourceMapTable[i++];
+ localContents[localContentsOffset++] = (byte) (lineNumber >> 8);
+ localContents[localContentsOffset++] = (byte) lineNumber;
+ numberOfEntries++;
+ }
+ // now we change the size of the line number attribute
+ int lineNumberAttr_length = numberOfEntries * 4 + 2;
+ localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 24);
+ localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 16);
+ localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 8);
+ localContents[lineNumberTableOffset++] = (byte) lineNumberAttr_length;
+ localContents[lineNumberTableOffset++] = (byte) (numberOfEntries >> 8);
+ localContents[lineNumberTableOffset++] = (byte) numberOfEntries;
+ attributeNumber++;
+ }
+ }
+
+ // then we do the local variable attribute
+ if (codeStream.generateLocalVariableTableAttributes) {
+ int localVariableTableOffset = localContentsOffset;
+ int numberOfEntries = 0;
+ // codeAttribute.addLocalVariableTableAttribute(this);
+ if ((codeStream.pcToSourceMap != null)
+ && (codeStream.pcToSourceMapSize != 0)) {
+ int localVariableNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
+ if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ localContents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
+ localContents[localContentsOffset++] = (byte) localVariableNameIndex;
+ localContentsOffset += 6;
+ // leave space for attribute_length and local_variable_table_length
+ int nameIndex;
+ int descriptorIndex;
+ for (int i = 0; i < codeStream.allLocalsCounter; i++) {
+ LocalVariableBinding localVariable = codeStream.locals[i];
+ for (int j = 0; j < localVariable.initializationCount; j++) {
+ int startPC = localVariable.initializationPCs[j << 1];
+ int endPC = localVariable.initializationPCs[(j << 1) + 1];
+ if (startPC != endPC) { // only entries for non zero length
+ int currentLength;
+ if (endPC == -1) {
+ localVariable.declaringScope.problemReporter().abortDueToInternalError(
+ "SANITY CHECK: Invalid attribute for local variable "
+ + new String(localVariable.name),
+ (AstNode) localVariable.declaringScope.methodScope().referenceContext);
+ }
+ if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ // now we can safely add the local entry
+ numberOfEntries++;
+ localContents[localContentsOffset++] = (byte) (startPC >> 8);
+ localContents[localContentsOffset++] = (byte) startPC;
+ int length = endPC - startPC;
+ localContents[localContentsOffset++] = (byte) (length >> 8);
+ localContents[localContentsOffset++] = (byte) length;
+ nameIndex = constantPool.literalIndex(localVariable.name);
+ localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
+ localContents[localContentsOffset++] = (byte) nameIndex;
+ descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
+ localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
+ localContents[localContentsOffset++] = (byte) descriptorIndex;
+ int resolvedPosition = localVariable.resolvedPosition;
+ localContents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
+ localContents[localContentsOffset++] = (byte) resolvedPosition;
+ }
+ }
+ }
+ int value = numberOfEntries * 10 + 2;
+ localVariableTableOffset += 2;
+ localContents[localVariableTableOffset++] = (byte) (value >> 24);
+ localContents[localVariableTableOffset++] = (byte) (value >> 16);
+ localContents[localVariableTableOffset++] = (byte) (value >> 8);
+ localContents[localVariableTableOffset++] = (byte) value;
+ localContents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
+ localContents[localVariableTableOffset] = (byte) numberOfEntries;
+ attributeNumber++;
+ }
+ }
+ // update the number of attributes
+ // ensure first that there is enough space available inside the contents array
+ if (codeAttributeAttributeOffset + 2
+ >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
+ localContents[codeAttributeAttributeOffset] = (byte) attributeNumber;
+ // update the attribute length
+ int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
+ localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
+ localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
+ localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
+ localContents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
+ contentsOffset = localContentsOffset;
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * That method completes the creation of the code attribute by setting
+ * - the attribute_length
+ * - max_stack
+ * - max_locals
+ * - code_length
+ * - exception table
+ * - and debug attributes if necessary.
+ *
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param codeAttributeOffset <CODE>int</CODE>
+ * @param exceptionHandler int[]
+ * @param startIndexes int[]
+ */
+ public void completeCodeAttributeForClinit(
+ int codeAttributeOffset,
+ int[] exceptionHandler,
+ int[] startLineIndexes) {
+ // reinitialize the contents with the byte modified by the code stream
+ byte[] localContents = contents = codeStream.bCodeStream;
+ int localContentsOffset = codeStream.classFileOffset;
+ // codeAttributeOffset is the position inside contents byte array before we started to write
+ // any information about the codeAttribute
+ // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
+ // to get the right position, 6 for the max_stack etc...
+ int contentsLength;
+ int code_length = codeStream.position;
+ if (code_length > 65535) {
+ codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(
+ codeStream.methodDeclaration.scope.referenceType());
+ }
+ if (localContentsOffset + 20 >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ int max_stack = codeStream.stackMax;
+ localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
+ localContents[codeAttributeOffset + 7] = (byte) max_stack;
+ int max_locals = codeStream.maxLocals;
+ localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
+ localContents[codeAttributeOffset + 9] = (byte) max_locals;
+ localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
+ localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
+ localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
+ localContents[codeAttributeOffset + 13] = (byte) code_length;
+
+ // write the exception table
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = 1;
+ int start = exceptionHandler[0];
+ localContents[localContentsOffset++] = (byte) (start >> 8);
+ localContents[localContentsOffset++] = (byte) start;
+ int end = exceptionHandler[1];
+ localContents[localContentsOffset++] = (byte) (end >> 8);
+ localContents[localContentsOffset++] = (byte) end;
+ int handlerPC = exceptionHandler[2];
+ localContents[localContentsOffset++] = (byte) (handlerPC >> 8);
+ localContents[localContentsOffset++] = (byte) handlerPC;
+ int nameIndex = constantPool.literalIndexForJavaLangException();
+ localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
+ localContents[localContentsOffset++] = (byte) nameIndex;
+
+ // debug attributes
+ int codeAttributeAttributeOffset = localContentsOffset;
+ int attributeNumber = 0; // leave two bytes for the attribute_length
+ localContentsOffset += 2; // first we handle the linenumber attribute
+
+ // first we handle the linenumber attribute
+ if (codeStream.generateLineNumberAttributes) {
+ /* Create and add the line number attribute (used for debugging)
+ * Build the pairs of:
+ * (bytecodePC lineNumber)
+ * according to the table of start line indexes and the pcToSourceMap table
+ * contained into the codestream
+ */
+ int index = 0, max = startLineIndexes.length;
+ int lineNumberNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
+ localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
+ localContents[localContentsOffset++] = (byte) lineNumberNameIndex;
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = 6;
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = 1;
+ // first entry at pc = 0
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = (byte) (problemLine >> 8);
+ localContents[localContentsOffset++] = (byte) problemLine;
+ // now we change the size of the line number attribute
+ attributeNumber++;
+ }
+
+ // then we do the local variable attribute
+ if (codeStream.generateLocalVariableTableAttributes) {
+ int localVariableNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
+ if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ localContents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
+ localContents[localContentsOffset++] = (byte) localVariableNameIndex;
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = 2;
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = 0;
+ attributeNumber++;
+ }
+
+ // update the number of attributes
+ // ensure first that there is enough space available inside the contents array
+ if (codeAttributeAttributeOffset + 2
+ >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
+ localContents[codeAttributeAttributeOffset] = (byte) attributeNumber;
+ // update the attribute length
+ int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
+ localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
+ localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
+ localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
+ localContents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
+ contentsOffset = localContentsOffset;
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * That method completes the creation of the code attribute by setting
+ * - the attribute_length
+ * - max_stack
+ * - max_locals
+ * - code_length
+ * - exception table
+ * - and debug attributes if necessary.
+ *
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param codeAttributeOffset <CODE>int</CODE>
+ * @param exceptionHandler int[]
+ */
+ public void completeCodeAttributeForProblemMethod(
+ AbstractMethodDeclaration method,
+ MethodBinding binding,
+ int codeAttributeOffset,
+ int[] exceptionHandler,
+ int[] startLineIndexes) {
+ // reinitialize the localContents with the byte modified by the code stream
+ byte[] localContents = contents = codeStream.bCodeStream;
+ int localContentsOffset = codeStream.classFileOffset;
+ // codeAttributeOffset is the position inside localContents byte array before we started to write// any information about the codeAttribute// That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset// to get the right position, 6 for the max_stack etc...
+ int max_stack = codeStream.stackMax;
+ localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
+ localContents[codeAttributeOffset + 7] = (byte) max_stack;
+ int max_locals = codeStream.maxLocals;
+ localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
+ localContents[codeAttributeOffset + 9] = (byte) max_locals;
+ int code_length = codeStream.position;
+ localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
+ localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
+ localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
+ localContents[codeAttributeOffset + 13] = (byte) code_length;
+ // write the exception table
+ int contentsLength;
+ if (localContentsOffset + 50 >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = 1;
+ int start = exceptionHandler[0];
+ localContents[localContentsOffset++] = (byte) (start >> 8);
+ localContents[localContentsOffset++] = (byte) start;
+ int end = exceptionHandler[1];
+ localContents[localContentsOffset++] = (byte) (end >> 8);
+ localContents[localContentsOffset++] = (byte) end;
+ int handlerPC = exceptionHandler[2];
+ localContents[localContentsOffset++] = (byte) (handlerPC >> 8);
+ localContents[localContentsOffset++] = (byte) handlerPC;
+ int nameIndex = constantPool.literalIndexForJavaLangException();
+ localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
+ localContents[localContentsOffset++] = (byte) nameIndex; // debug attributes
+ int codeAttributeAttributeOffset = localContentsOffset;
+ int attributeNumber = 0; // leave two bytes for the attribute_length
+ localContentsOffset += 2; // first we handle the linenumber attribute
+
+ if (codeStream.generateLineNumberAttributes) {
+ /* Create and add the line number attribute (used for debugging)
+ * Build the pairs of:
+ * (bytecodePC lineNumber)
+ * according to the table of start line indexes and the pcToSourceMap table
+ * contained into the codestream
+ */
+ int lineNumberNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
+ localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
+ localContents[localContentsOffset++] = (byte) lineNumberNameIndex;
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = 6;
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = 1;
+ if (problemLine == 0) {
+ problemLine = searchLineNumber(startLineIndexes, binding.sourceStart());
+ }
+ // first entry at pc = 0
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = (byte) (problemLine >> 8);
+ localContents[localContentsOffset++] = (byte) problemLine;
+ // now we change the size of the line number attribute
+ attributeNumber++;
+ }
+
+ // then we do the local variable attribute
+ if (codeStream.generateLocalVariableTableAttributes) {
+ // compute the resolved position for the arguments of the method
+ int argSize;
+ int localVariableTableOffset = localContentsOffset;
+ int numberOfEntries = 0;
+ // codeAttribute.addLocalVariableTableAttribute(this);
+ int localVariableNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
+ if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ localContents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
+ localContents[localContentsOffset++] = (byte) localVariableNameIndex;
+ localContentsOffset += 6;
+ // leave space for attribute_length and local_variable_table_length
+ int descriptorIndex;
+ if (!codeStream.methodDeclaration.isStatic()) {
+ numberOfEntries++;
+ if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = (byte) (code_length >> 8);
+ localContents[localContentsOffset++] = (byte) code_length;
+ nameIndex = constantPool.literalIndex(QualifiedNamesConstants.This);
+ localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
+ localContents[localContentsOffset++] = (byte) nameIndex;
+ descriptorIndex =
+ constantPool.literalIndex(
+ codeStream.methodDeclaration.binding.declaringClass.signature());
+ localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
+ localContents[localContentsOffset++] = (byte) descriptorIndex;
+ // the resolved position for this is always 0
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = 0;
+ }
+ if (binding.isConstructor()) {
+ ReferenceBinding declaringClass = binding.declaringClass;
+ if (declaringClass.isNestedType()) {
+ NestedTypeBinding methodDeclaringClass = (NestedTypeBinding) declaringClass;
+ argSize = methodDeclaringClass.syntheticArgumentsOffset;
+ SyntheticArgumentBinding[] syntheticArguments;
+ if ((syntheticArguments = methodDeclaringClass.syntheticEnclosingInstances())
+ != null) {
+ for (int i = 0, max = syntheticArguments.length; i < max; i++) {
+ LocalVariableBinding localVariable = syntheticArguments[i];
+ int currentLength;
+ if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ // now we can safely add the local entry
+ numberOfEntries++;
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = (byte) (code_length >> 8);
+ localContents[localContentsOffset++] = (byte) code_length;
+ nameIndex = constantPool.literalIndex(localVariable.name);
+ localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
+ localContents[localContentsOffset++] = (byte) nameIndex;
+ descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
+ localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
+ localContents[localContentsOffset++] = (byte) descriptorIndex;
+ int resolvedPosition = localVariable.resolvedPosition;
+ localContents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
+ localContents[localContentsOffset++] = (byte) resolvedPosition;
+ }
+ }
+ } else {
+ argSize = 1;
+ }
+ } else {
+ argSize = binding.isStatic() ? 0 : 1;
+ }
+ if (method.binding != null) {
+ TypeBinding[] parameters = method.binding.parameters;
+ Argument[] arguments = method.arguments;
+ if ((parameters != null) && (arguments != null)) {
+ for (int i = 0, max = parameters.length; i < max; i++) {
+ TypeBinding argumentBinding = parameters[i];
+ int currentLength;
+ if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ // now we can safely add the local entry
+ numberOfEntries++;
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = 0;
+ localContents[localContentsOffset++] = (byte) (code_length >> 8);
+ localContents[localContentsOffset++] = (byte) code_length;
+ nameIndex = constantPool.literalIndex(arguments[i].name);
+ localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
+ localContents[localContentsOffset++] = (byte) nameIndex;
+ descriptorIndex = constantPool.literalIndex(argumentBinding.signature());
+ localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
+ localContents[localContentsOffset++] = (byte) descriptorIndex;
+ int resolvedPosition = argSize;
+ if ((argumentBinding == TypeBinding.LongBinding)
+ || (argumentBinding == TypeBinding.DoubleBinding))
+ argSize += 2;
+ else
+ argSize++;
+ localContents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
+ localContents[localContentsOffset++] = (byte) resolvedPosition;
+ }
+ }
+ }
+ int value = numberOfEntries * 10 + 2;
+ localVariableTableOffset += 2;
+ localContents[localVariableTableOffset++] = (byte) (value >> 24);
+ localContents[localVariableTableOffset++] = (byte) (value >> 16);
+ localContents[localVariableTableOffset++] = (byte) (value >> 8);
+ localContents[localVariableTableOffset++] = (byte) value;
+ localContents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
+ localContents[localVariableTableOffset] = (byte) numberOfEntries;
+ attributeNumber++;
+ }
+
+ // update the number of attributes// ensure first that there is enough space available inside the localContents array
+ if (codeAttributeAttributeOffset + 2
+ >= (contentsLength = localContents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
+ localContents[codeAttributeAttributeOffset] = (byte) attributeNumber;
+ // update the attribute length
+ int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
+ localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
+ localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
+ localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
+ localContents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
+ contentsOffset = localContentsOffset;
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * That method completes the creation of the code attribute by setting
+ * - the attribute_length
+ * - max_stack
+ * - max_locals
+ * - code_length
+ * - exception table
+ * - and debug attributes if necessary.
+ *
+ * @param binding org.eclipse.jdt.internal.compiler.lookup.SyntheticAccessMethodBinding
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param codeAttributeOffset <CODE>int</CODE>
+ */
+ public void completeCodeAttributeForSyntheticAccessMethod(
+ SyntheticAccessMethodBinding binding,
+ int codeAttributeOffset,
+ int[] startLineIndexes) {
+ // reinitialize the contents with the byte modified by the code stream
+ contents = codeStream.bCodeStream;
+ int localContentsOffset = codeStream.classFileOffset;
+ // codeAttributeOffset is the position inside contents byte array before we started to write
+ // any information about the codeAttribute
+ // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
+ // to get the right position, 6 for the max_stack etc...
+ int max_stack = codeStream.stackMax;
+ contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
+ contents[codeAttributeOffset + 7] = (byte) max_stack;
+ int max_locals = codeStream.maxLocals;
+ contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
+ contents[codeAttributeOffset + 9] = (byte) max_locals;
+ int code_length = codeStream.position;
+ contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
+ contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
+ contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
+ contents[codeAttributeOffset + 13] = (byte) code_length;
+ int contentsLength;
+ if ((localContentsOffset + 40) >= (contentsLength = contents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ // there is no exception table, so we need to offset by 2 the current offset and move
+ // on the attribute generation
+ localContentsOffset += 2;
+ // debug attributes
+ int codeAttributeAttributeOffset = localContentsOffset;
+ int attributeNumber = 0;
+ // leave two bytes for the attribute_length
+ localContentsOffset += 2;
+
+ // first we handle the linenumber attribute
+ if (codeStream.generateLineNumberAttributes) {
+ int index = 0, max = startLineIndexes.length;
+ int lineNumberNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
+ contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
+ contents[localContentsOffset++] = (byte) lineNumberNameIndex;
+ int lineNumberTableOffset = localContentsOffset;
+ localContentsOffset += 6;
+ // leave space for attribute_length and line_number_table_length
+ // Seems like do would be better, but this preserves the existing behavior.
+ index = searchLineNumber(startLineIndexes, binding.sourceStart);
+ contents[localContentsOffset++] = 0;
+ contents[localContentsOffset++] = 0;
+ contents[localContentsOffset++] = (byte) (index >> 8);
+ contents[localContentsOffset++] = (byte) index;
+ // now we change the size of the line number attribute
+ contents[lineNumberTableOffset++] = 0;
+ contents[lineNumberTableOffset++] = 0;
+ contents[lineNumberTableOffset++] = 0;
+ contents[lineNumberTableOffset++] = 6;
+ contents[lineNumberTableOffset++] = 0;
+ contents[lineNumberTableOffset++] = 1;
+ attributeNumber++;
+ }
+
+ // then we do the local variable attribute
+ if (codeStream.generateLocalVariableTableAttributes) {
+ int localVariableTableOffset = localContentsOffset;
+ int numberOfEntries = 0;
+ int localVariableNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
+ if (localContentsOffset + 8 > (contentsLength = contents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
+ contents[localContentsOffset++] = (byte) localVariableNameIndex;
+ localContentsOffset += 6;
+ // leave space for attribute_length and local_variable_table_length
+ int nameIndex;
+ int descriptorIndex;
+ for (int i = 0; i < codeStream.allLocalsCounter; i++) {
+ LocalVariableBinding localVariable = codeStream.locals[i];
+ for (int j = 0; j < localVariable.initializationCount; j++) {
+ int startPC = localVariable.initializationPCs[j << 1];
+ int endPC = localVariable.initializationPCs[(j << 1) + 1];
+ if (startPC != endPC) { // only entries for non zero length
+ int currentLength;
+ if (endPC == -1) {
+ localVariable.declaringScope.problemReporter().abortDueToInternalError(
+ "SANITY CHECK: Invalid attribute for local variable "
+ + new String(localVariable.name),
+ (AstNode) localVariable.declaringScope.methodScope().referenceContext);
+ }
+ if (localContentsOffset + 10 > (contentsLength = contents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ // now we can safely add the local entry
+ numberOfEntries++;
+ contents[localContentsOffset++] = (byte) (startPC >> 8);
+ contents[localContentsOffset++] = (byte) startPC;
+ int length = endPC - startPC;
+ contents[localContentsOffset++] = (byte) (length >> 8);
+ contents[localContentsOffset++] = (byte) length;
+ nameIndex = constantPool.literalIndex(localVariable.name);
+ contents[localContentsOffset++] = (byte) (nameIndex >> 8);
+ contents[localContentsOffset++] = (byte) nameIndex;
+ descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
+ contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
+ contents[localContentsOffset++] = (byte) descriptorIndex;
+ int resolvedPosition = localVariable.resolvedPosition;
+ contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
+ contents[localContentsOffset++] = (byte) resolvedPosition;
+ }
+ }
+ }
+ int value = numberOfEntries * 10 + 2;
+ localVariableTableOffset += 2;
+ contents[localVariableTableOffset++] = (byte) (value >> 24);
+ contents[localVariableTableOffset++] = (byte) (value >> 16);
+ contents[localVariableTableOffset++] = (byte) (value >> 8);
+ contents[localVariableTableOffset++] = (byte) value;
+ contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
+ contents[localVariableTableOffset] = (byte) numberOfEntries;
+ attributeNumber++;
+ }
+
+ // update the number of attributes
+ // ensure first that there is enough space available inside the contents array
+ if (codeAttributeAttributeOffset + 2 >= (contentsLength = contents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
+ contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
+
+ // update the attribute length
+ int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
+ contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
+ contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
+ contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
+ contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
+ contentsOffset = localContentsOffset;
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * Complete the creation of a method info by setting up the number of attributes at the right offset.
+ *
+ * @param methodAttributeOffset <CODE>int</CODE>
+ * @param attributeNumber <CODE>int</CODE>
+ */
+ public void completeMethodInfo(
+ int methodAttributeOffset,
+ int attributeNumber) {
+ // update the number of attributes
+ contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8);
+ contents[methodAttributeOffset] = (byte) attributeNumber;
+ }
+
+ /*
+ * INTERNAL USE-ONLY
+ * Innerclasses get their name computed as they are generated, since some may not
+ * be actually outputed if sitting inside unreachable code.
+ *
+ * @param localType org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding
+ */
+ public char[] computeConstantPoolName(LocalTypeBinding localType) {
+ if (localType.constantPoolName() != null) {
+ return localType.constantPoolName();
+ }
+
+ // delegates to the outermost enclosing classfile, since it is the only one with a global vision of its innertypes.
+ if (enclosingClassFile != null) {
+ return this.outerMostEnclosingClassFile().computeConstantPoolName(localType);
+ }
+
+ if (nameUsage == null) {
+ nameUsage = new CharArrayCache();
+ }
+ if (localType.isMemberType()) { // catches member types of local types
+ return CharOperation.concat(
+ localType.enclosingType().constantPoolName(),
+ localType.sourceName,
+ '$');
+ } else {
+ char[][] compoundName = (char[][]) referenceBinding.compoundName.clone();
+ int last = compoundName.length - 1;
+ StringBuffer nameBuffer = new StringBuffer().append(compoundName[last]);
+ // retrieve the number of use of the combination
+ char[] simpleName = localType.sourceName;
+ //if (simpleName == null) simpleName = new char[]{}; // for anonymous
+ int nameCount = nameUsage.get(simpleName); // -1 if not found
+ nameCount = nameCount == -1 ? 1 : nameCount + 1;
+ nameBuffer.append('$').append(nameCount);
+ nameUsage.put(simpleName, nameCount);
+ if (!localType.isAnonymousType()) { // named local type
+ nameBuffer.append('$').append(simpleName);
+ }
+ compoundName[last] = nameBuffer.toString().toCharArray();
+ return CharOperation.concatWith(compoundName, '/');
+ }
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * Request the creation of a ClassFile compatible representation of a problematic type
+ *
+ * @param typeDeclaration org.eclipse.jdt.internal.compiler.ast.TypeDeclaration
+ * @param unitResult org.eclipse.jdt.internal.compiler.CompilationUnitResult
+ */
+ public static void createProblemType(
+ TypeDeclaration typeDeclaration,
+ CompilationResult unitResult) {
+ SourceTypeBinding typeBinding = typeDeclaration.binding;
+ ClassFile classFile = new ClassFile(typeBinding, null, true);
+
+ // inner attributes
+ if (typeBinding.isMemberType())
+ classFile.recordEnclosingTypeAttributes(typeBinding);
+
+ // add its fields
+ FieldBinding[] fields = typeBinding.fields;
+ if ((fields != null) && (fields != NoFields)) {
+ for (int i = 0, max = fields.length; i < max; i++) {
+ if (fields[i].constant == null) {
+ FieldReference.getConstantFor(fields[i], false, null, 0);
+ }
+ }
+ classFile.addFieldInfos();
+ } else {
+ // we have to set the number of fields to be equals to 0
+ classFile.contents[classFile.contentsOffset++] = 0;
+ classFile.contents[classFile.contentsOffset++] = 0;
+ }
+ // leave some space for the methodCount
+ classFile.setForMethodInfos();
+ // add its user defined methods
+ MethodBinding[] methods = typeBinding.methods;
+ AbstractMethodDeclaration[] methodDeclarations = typeDeclaration.methods;
+ int maxMethodDecl = methodDeclarations == null ? 0 : methodDeclarations.length;
+ int problemsLength;
+ IProblem[] problems = unitResult.getProblems();
+ if (problems == null) {
+ problems = new IProblem[0];
+ }
+ IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
+ System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
+ if (methods != null) {
+ if (typeBinding.isInterface()) {
+ // we cannot create problem methods for an interface. So we have to generate a clinit
+ // which should contain all the problem
+ classFile.addProblemClinit(problemsCopy);
+ for (int i = 0, max = methods.length; i < max; i++) {
+ MethodBinding methodBinding;
+ if ((methodBinding = methods[i]) != null) {
+ // find the corresponding method declaration
+ for (int j = 0; j < maxMethodDecl; j++) {
+ if ((methodDeclarations[j] != null)
+ && (methodDeclarations[j].binding == methods[i])) {
+ if (!methodBinding.isConstructor()) {
+ classFile.addAbstractMethod(methodDeclarations[j], methodBinding);
+ }
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ for (int i = 0, max = methods.length; i < max; i++) {
+ MethodBinding methodBinding;
+ if ((methodBinding = methods[i]) != null) {
+ // find the corresponding method declaration
+ for (int j = 0; j < maxMethodDecl; j++) {
+ if ((methodDeclarations[j] != null)
+ && (methodDeclarations[j].binding == methods[i])) {
+ AbstractMethodDeclaration methodDecl;
+ if ((methodDecl = methodDeclarations[j]).isConstructor()) {
+ classFile.addProblemConstructor(methodDecl, methodBinding, problemsCopy);
+ } else {
+ classFile.addProblemMethod(methodDecl, methodBinding, problemsCopy);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ // add abstract methods
+ classFile.addDefaultAbstractMethods();
+ }
+ // propagate generation of (problem) member types
+ if (typeDeclaration.memberTypes != null) {
+ CompilationResult result =
+ typeDeclaration.scope.referenceCompilationUnit().compilationResult;
+ for (int i = 0, max = typeDeclaration.memberTypes.length; i < max; i++) {
+ TypeDeclaration memberType = typeDeclaration.memberTypes[i];
+ if (memberType.binding != null) {
+ classFile.recordNestedMemberAttribute(memberType.binding);
+ ClassFile.createProblemType(memberType, unitResult);
+ }
+ }
+ }
+ classFile.addAttributes();
+ unitResult.record(typeBinding.constantPoolName(), classFile);
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * This methods returns a char[] representing the file name of the receiver
+ *
+ * @return char[]
+ */
+ public char[] fileName() {
+ return constantPool.UTF8Cache.returnKeyFor(1);
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * That method generates the header of a code attribute.
+ * - the index inside the constant pool for the attribute name (i.e. Code)
+ * - leave some space for attribute_length(4), max_stack(2), max_locals(2), code_length(4).
+ */
+ public void generateCodeAttributeHeader() {
+ int contentsLength;
+ if (contentsOffset + 20 >= (contentsLength = contents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ int constantValueNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.CodeName);
+ contents[contentsOffset++] = (byte) (constantValueNameIndex >> 8);
+ contents[contentsOffset++] = (byte) constantValueNameIndex;
+ // leave space for attribute_length(4), max_stack(2), max_locals(2), code_length(4)
+ contentsOffset += 12;
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * That method generates the attributes of a code attribute.
+ * They could be:
+ * - an exception attribute for each try/catch found inside the method
+ * - a deprecated attribute
+ * - a synthetic attribute for synthetic access methods
+ *
+ * It returns the number of attributes created for the code attribute.
+ *
+ * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding
+ * @return <CODE>int</CODE>
+ */
+ public int generateMethodInfoAttribute(MethodBinding methodBinding) {
+ // leave two bytes for the attribute_number
+ contentsOffset += 2;
+ // now we can handle all the attribute for that method info:
+ // it could be:
+ // - a CodeAttribute
+ // - a ExceptionAttribute
+ // - a DeprecatedAttribute
+ // - a SyntheticAttribute
+
+ // Exception attribute
+ ReferenceBinding[] thrownsExceptions;
+ int contentsLength;
+ int attributeNumber = 0;
+ if ((thrownsExceptions = methodBinding.thrownExceptions) != NoExceptions) {
+ // The method has a throw clause. So we need to add an exception attribute
+ // check that there is enough space to write all the bytes for the exception attribute
+ int length = thrownsExceptions.length;
+ if (contentsOffset + (8 + length * 2) >= (contentsLength = contents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (contents =
+ new byte[contentsLength + Math.max(INCREMENT_SIZE, (8 + length * 2))]),
+ 0,
+ contentsLength);
+ }
+ int exceptionNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.ExceptionsName);
+ contents[contentsOffset++] = (byte) (exceptionNameIndex >> 8);
+ contents[contentsOffset++] = (byte) exceptionNameIndex;
+ // The attribute length = length * 2 + 2 in case of a exception attribute
+ int attributeLength = length * 2 + 2;
+ contents[contentsOffset++] = (byte) (attributeLength >> 24);
+ contents[contentsOffset++] = (byte) (attributeLength >> 16);
+ contents[contentsOffset++] = (byte) (attributeLength >> 8);
+ contents[contentsOffset++] = (byte) attributeLength;
+ contents[contentsOffset++] = (byte) (length >> 8);
+ contents[contentsOffset++] = (byte) length;
+ for (int i = 0; i < length; i++) {
+ int exceptionIndex = constantPool.literalIndex(thrownsExceptions[i]);
+ contents[contentsOffset++] = (byte) (exceptionIndex >> 8);
+ contents[contentsOffset++] = (byte) exceptionIndex;
+ }
+ attributeNumber++;
+ }
+
+ // Deprecated attribute
+ // Check that there is enough space to write the deprecated attribute
+ if (contentsOffset + 6 >= (contentsLength = contents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ if (methodBinding.isDeprecated()) {
+ int deprecatedAttributeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
+ contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8);
+ contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex;
+ // the length of a deprecated attribute is equals to 0
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+
+ attributeNumber++;
+ }
+
+ // Synthetic attribute
+ // Check that there is enough space to write the deprecated attribute
+ if (contentsOffset + 6 >= (contentsLength = contents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ if (methodBinding.isSynthetic()) {
+ int syntheticAttributeNameIndex =
+ constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
+ contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
+ contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
+ // the length of a synthetic attribute is equals to 0
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 0;
+
+ attributeNumber++;
+ }
+ return attributeNumber;
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * That method generates the header of a method info:
+ * The header consists in:
+ * - the access flags
+ * - the name index of the method name inside the constant pool
+ * - the descriptor index of the signature of the method inside the constant pool.
+ *
+ * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding
+ */
+ public void generateMethodInfoHeader(MethodBinding methodBinding) {
+ // check that there is enough space to write all the bytes for the method info corresponding
+ // to the @methodBinding
+ int contentsLength;
+ methodCount++; // add one more method
+ if (contentsOffset + 10 >= (contentsLength = contents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ int accessFlags = methodBinding.getAccessFlags();
+ if (methodBinding.isRequiredToClearPrivateModifier()) {
+ accessFlags &= ~AccPrivate;
+ }
+ contents[contentsOffset++] = (byte) (accessFlags >> 8);
+ contents[contentsOffset++] = (byte) accessFlags;
+ int nameIndex = constantPool.literalIndex(methodBinding.selector);
+ contents[contentsOffset++] = (byte) (nameIndex >> 8);
+ contents[contentsOffset++] = (byte) nameIndex;
+ int descriptorIndex = constantPool.literalIndex(methodBinding.signature());
+ contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
+ contents[contentsOffset++] = (byte) descriptorIndex;
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * That method generates the method info header of a clinit:
+ * The header consists in:
+ * - the access flags (always default access + static)
+ * - the name index of the method name (always <clinit>) inside the constant pool
+ * - the descriptor index of the signature (always ()V) of the method inside the constant pool.
+ *
+ * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding
+ */
+ public void generateMethodInfoHeaderForClinit() {
+ // check that there is enough space to write all the bytes for the method info corresponding
+ // to the @methodBinding
+ int contentsLength;
+ methodCount++; // add one more method
+ if (contentsOffset + 10 >= (contentsLength = contents.length)) {
+ System.arraycopy(
+ contents,
+ 0,
+ (contents = new byte[contentsLength + INCREMENT_SIZE]),
+ 0,
+ contentsLength);
+ }
+ contents[contentsOffset++] = (byte) ((AccDefault | AccStatic) >> 8);
+ contents[contentsOffset++] = (byte) (AccDefault | AccStatic);
+ int nameIndex = constantPool.literalIndex(QualifiedNamesConstants.Clinit);
+ contents[contentsOffset++] = (byte) (nameIndex >> 8);
+ contents[contentsOffset++] = (byte) nameIndex;
+ int descriptorIndex =
+ constantPool.literalIndex(QualifiedNamesConstants.ClinitSignature);
+ contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
+ contents[contentsOffset++] = (byte) descriptorIndex;
+ // We know that we won't get more than 1 attribute: the code attribute
+ contents[contentsOffset++] = 0;
+ contents[contentsOffset++] = 1;
+ }
+
+ /**
+ * EXTERNAL API
+ * Answer the actual bytes of the class file
+ *
+ * This method encodes the receiver structure into a byte array which is the content of the classfile.
+ * Returns the byte array that represents the encoded structure of the receiver.
+ *
+ * @return byte[]
+ */
+ public byte[] getBytes() {
+ byte[] fullContents = new byte[headerOffset + contentsOffset];
+ System.arraycopy(header, 0, fullContents, 0, headerOffset);
+ System.arraycopy(contents, 0, fullContents, headerOffset, contentsOffset);
+ return fullContents;
+ }
+
+ /**
+ * EXTERNAL API
+ * Answer the compound name of the class file.
+ * @return char[][]
+ * e.g. {{java}, {util}, {Hashtable}}.
+ */
+ public char[][] getCompoundName() {
+ return CharOperation.splitOn('/', fileName());
+ }
+
+ /**
+ * EXTERNAL API
+ * Answer a smaller byte format, which is only contains some structural information.
+ *
+ * Those bytes are decodable with a regular class file reader, such as:
+ * DietClassFileReader
+ */
+
+ public byte[] getReducedBytes() {
+ return getBytes(); // might be improved
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * Returns the most enclosing classfile of the receiver. This is used know to store the constant pool name
+ * for all inner types of the receiver.
+ * @return org.eclipse.jdt.internal.compiler.codegen.ClassFile
+ */
+ public ClassFile outerMostEnclosingClassFile() {
+ ClassFile current = this;
+ while (current.enclosingClassFile != null)
+ current = current.enclosingClassFile;
+ return current;
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the
+ * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications.
+ *
+ * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
+ */
+ public void recordEnclosingTypeAttributes(ReferenceBinding binding) {
+ // add all the enclosing types
+ ReferenceBinding enclosingType = referenceBinding.enclosingType();
+ int depth = 0;
+ while (enclosingType != null) {
+ depth++;
+ enclosingType = enclosingType.enclosingType();
+ }
+ enclosingType = referenceBinding;
+ ReferenceBinding enclosingTypes[];
+ if (depth >= 2) {
+ enclosingTypes = new ReferenceBinding[depth];
+ for (int i = depth - 1; i >= 0; i--) {
+ enclosingTypes[i] = enclosingType;
+ enclosingType = enclosingType.enclosingType();
+ }
+ for (int i = 0; i < depth; i++) {
+ addInnerClasses(enclosingTypes[i]);
+ }
+ } else {
+ addInnerClasses(referenceBinding);
+ }
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the
+ * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications.
+ *
+ * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
+ */
+ public void recordNestedLocalAttribute(ReferenceBinding binding) {
+ // add all the enclosing types
+ ReferenceBinding enclosingType = referenceBinding.enclosingType();
+ int depth = 0;
+ while (enclosingType != null) {
+ depth++;
+ enclosingType = enclosingType.enclosingType();
+ }
+ enclosingType = referenceBinding;
+ ReferenceBinding enclosingTypes[];
+ if (depth >= 2) {
+ enclosingTypes = new ReferenceBinding[depth];
+ for (int i = depth - 1; i >= 0; i--) {
+ enclosingTypes[i] = enclosingType;
+ enclosingType = enclosingType.enclosingType();
+ }
+ for (int i = 0; i < depth; i++)
+ addInnerClasses(enclosingTypes[i]);
+ } else {
+ addInnerClasses(binding);
+ }
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the
+ * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications.
+ *
+ * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
+ */
+ public void recordNestedMemberAttribute(ReferenceBinding binding) {
+ addInnerClasses(binding);
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * Search the line number corresponding to a specific position
+ *
+ * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
+ */
+ public static final int searchLineNumber(
+ int[] startLineIndexes,
+ int position) {
+ // this code is completely useless, but it is the same implementation than
+ // org.eclipse.jdt.internal.compiler.problem.ProblemHandler.searchLineNumber(int[], int)
+ // if (startLineIndexes == null)
+ // return 1;
+ int length = startLineIndexes.length;
+ if (length == 0)
+ return 1;
+ int g = 0, d = length - 1;
+ int m = 0;
+ while (g <= d) {
+ m = (g + d) / 2;
+ if (position < startLineIndexes[m]) {
+ d = m - 1;
+ } else
+ if (position > startLineIndexes[m]) {
+ g = m + 1;
+ } else {
+ return m + 1;
+ }
+ }
+ if (position < startLineIndexes[m]) {
+ return m + 1;
+ }
+ return m + 2;
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * This methods leaves the space for method counts recording.
+ */
+ public void setForMethodInfos() {
+ // leave some space for the methodCount
+ methodCountOffset = contentsOffset;
+ contentsOffset += 2;
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * outputPath is formed like:
+ * c:\temp\ the last character is a file separator
+ * relativeFileName is formed like:
+ * java\lang\String.class
+ * @param fileName java.lang.String
+ * @param content byte[]
+ */
+ public static void writeToDisk(
+ String outputPath,
+ String relativeFileName,
+ byte[] contents)
+ throws IOException {
+ String fileName;
+ File file;
+ FileOutputStream output =
+ new FileOutputStream(
+ file =
+ new File((fileName = buildAllDirectoriesInto(outputPath, relativeFileName))));
+ output.write(contents);
+ output.flush();
+ output.close();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/CompilationResult.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/CompilationResult.java
new file mode 100644
index 0000000000..926fe2e846
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/CompilationResult.java
@@ -0,0 +1,225 @@
+package org.eclipse.jdt.internal.compiler;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/**
+ * A compilation result consists of all information returned by the compiler for
+ * a single compiled compilation source unit. This includes:
+ * <ul>
+ * <li> the compilation unit that was compiled
+ * <li> for each type produced by compiling the compilation unit, its binary and optionally its principal structure
+ * <li> any problems (errors or warnings) produced
+ * <li> dependency info
+ * </ul>
+ *
+ * The principle structure and binary may be null if the compiler could not produce them.
+ * If neither could be produced, there is no corresponding entry for the type.
+ *
+ * The dependency info includes type references such as supertypes, field types, method
+ * parameter and return types, local variable types, types of intermediate expressions, etc.
+ * It also includes the namespaces (packages) in which names were looked up.
+ * It does <em>not</em> include finer grained dependencies such as information about
+ * specific fields and methods which were referenced, but does contain their
+ * declaring types and any other types used to locate such fields or methods.
+ */
+
+import org.eclipse.jdt.internal.compiler.env.*;
+
+import java.util.*;
+
+public class CompilationResult {
+ public IProblem problems[];
+ public int problemCount;
+ public ICompilationUnit compilationUnit;
+
+ public char[][] namespaceDependencies;
+ public char[][] fileDependencies;
+ public int lineSeparatorPositions[];
+ public Hashtable compiledTypes = new Hashtable(11);
+ public int unitIndex, totalUnitsKnown;
+ public boolean hasBeenAccepted = false;
+ public char[] fileName;
+ public CompilationResult(char[] fileName, int unitIndex, int totalUnitsKnown) {
+
+ this.fileName = fileName;
+ this.unitIndex = unitIndex;
+ this.totalUnitsKnown = totalUnitsKnown;
+
+ }
+
+ public CompilationResult(
+ ICompilationUnit compilationUnit,
+ int unitIndex,
+ int totalUnitsKnown) {
+
+ this.fileName = compilationUnit.getFileName();
+ this.compilationUnit = compilationUnit;
+ this.unitIndex = unitIndex;
+ this.totalUnitsKnown = totalUnitsKnown;
+
+ }
+
+ public ClassFile[] getClassFiles() {
+ Enumeration enum = compiledTypes.elements();
+ ClassFile[] classFiles = new ClassFile[compiledTypes.size()];
+ int index = 0;
+ while (enum.hasMoreElements()) {
+ classFiles[index++] = (ClassFile) enum.nextElement();
+ }
+ return classFiles;
+ }
+
+ /**
+ * Answer the initial compilation unit corresponding to the present compilation result
+ */
+ public ICompilationUnit getCompilationUnit() {
+ return compilationUnit;
+ }
+
+ /**
+ * Answer the file names of the types on which the compilation unit depends.
+ * For example, if Foo.java refers to class p1.Bar, and p1.Bar is found,
+ * then the type dependency info for Foo.java will include the file name
+ * for p1.Bar.
+ * If a type is looked up in some package but is not found, this does not
+ * introduce a type dependency, but it does introduce a namespace dependency
+ * on that package.
+ * In general, if any of the types listed are deleted from the image, it will
+ * break the owner of the dependency info.
+ */
+
+ public char[][] getFileDependencies() {
+ return fileDependencies;
+ }
+
+ /**
+ * Answer the initial file name
+ */
+ public char[] getFileName() {
+ return fileName;
+ }
+
+ /**
+ * Answer the names of the packages on which the compilation result depends.
+ * That is, in order to compile the compilation unit, the compiler needed
+ * to look up names in these packages. Such dependencies usually arise
+ * from import statements and qualified type references.
+ * The names are qualified package names separated by periods.
+ * For example, {{{java.lang}, {java.io}}}.
+ * The default package is indicated by the char[0].
+ */
+
+ public char[][] getNamespaceDependencies() {
+ return namespaceDependencies;
+ }
+
+ /**
+ * Answer the problems (errors and warnings) encountered during compilation.
+ *
+ * This is not a compiler internal API - it has side-effects !
+ * It is intended to be used only once all problems have been detected,
+ * and makes sure the problems slot as the exact size of the number of
+ * problems.
+ */
+ public IProblem[] getProblems() {
+
+ // Re-adjust the size of the problems if necessary.
+ if (problems != null) {
+ if (problemCount != problems.length) {
+ System.arraycopy(
+ problems,
+ 0,
+ (problems = new IProblem[problemCount]),
+ 0,
+ problemCount);
+ }
+
+ // Sort problems per source positions.
+ quicksort(problems, 0, problems.length - 1);
+ }
+ return problems;
+ }
+
+ public boolean hasErrors() {
+ if (problems != null)
+ for (int i = 0; i < problemCount; i++) {
+ if (problems[i].isError())
+ return true;
+ }
+ return false;
+ }
+
+ public boolean hasProblems() {
+ return problemCount != 0;
+ }
+
+ public boolean hasWarnings() {
+ if (problems != null)
+ for (int i = 0; i < problemCount; i++) {
+ if (problems[i].isWarning())
+ return true;
+ }
+ return false;
+ }
+
+ private static void quicksort(IProblem arr[], int left, int right) {
+ int i, last, pos;
+
+ if (left >= right) {
+ /* do nothing if array contains fewer than two */
+ return;
+ /* two elements */
+ }
+
+ swap(arr, left, (left + right) / 2);
+ last = left;
+ pos = arr[left].getSourceStart();
+
+ for (i = left + 1; i <= right; i++) {
+ if (arr[i].getSourceStart() < pos) {
+ swap(arr, ++last, i);
+ }
+ }
+
+ swap(arr, left, last);
+ quicksort(arr, left, last - 1);
+ quicksort(arr, last + 1, right);
+ }
+
+ /**
+ * For now, remember the compiled type using its compound name.
+ */
+ public void record(char[] typeName, ClassFile classFile) {
+ compiledTypes.put(typeName, classFile);
+ }
+
+ public void record(IProblem newProblem) {
+ if (problemCount == 0) {
+ problems = new IProblem[5];
+ } else {
+ if (problemCount == problems.length)
+ System.arraycopy(
+ problems,
+ 0,
+ (problems = new IProblem[problemCount * 2]),
+ 0,
+ problemCount);
+ };
+ problems[problemCount++] = newProblem;
+ }
+
+ private static void swap(IProblem arr[], int i, int j) {
+ IProblem tmp;
+ tmp = arr[i];
+ arr[i] = arr[j];
+ arr[j] = tmp;
+ }
+
+ CompilationResult tagAsAccepted() {
+ this.hasBeenAccepted = true;
+ return this;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java
new file mode 100644
index 0000000000..fef1f0243e
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java
@@ -0,0 +1,508 @@
+package org.eclipse.jdt.internal.compiler;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.*;
+
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.parser.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+import java.io.*;
+import java.util.*;
+
+public class Compiler implements ITypeRequestor, ProblemSeverities {
+ public Parser parser;
+ ICompilerRequestor requestor;
+ public CompilerOptions options;
+ public ProblemReporter problemReporter;
+
+ // management of unit to be processed
+ //public CompilationUnitResult currentCompilationUnitResult;
+ CompilationUnitDeclaration[] unitsToProcess;
+ int totalUnits; // (totalUnits-1) gives the last unit in unitToProcess
+
+ // name lookup
+ public LookupEnvironment lookupEnvironment;
+
+ // ONCE STABILIZED, THESE SHOULD RETURN TO A FINAL FIELD
+ public static final boolean DEBUG = false;
+ public int parseThreshold = -1;
+ // number of initial units parsed at once (-1: none)
+ /**
+ * Answer a new compiler using the given name environment and compiler options.
+ * The environment and options will be in effect for the lifetime of the compiler.
+ * When the compiler is run, compilation results are sent to the given requestor.
+ *
+ * @param environment org.eclipse.jdt.internal.compiler.api.env.INameEnvironment
+ * Environment used by the compiler in order to resolve type and package
+ * names. The name environment implements the actual connection of the compiler
+ * to the outside world (e.g. in batch mode the name environment is performing
+ * pure file accesses, reuse previous build state or connection to repositories).
+ * Note: the name environment is responsible for implementing the actual classpath
+ * rules.
+ *
+ * @param policy org.eclipse.jdt.internal.compiler.api.problem.IErrorHandlingPolicy
+ * Configurable part for problem handling, allowing the compiler client to
+ * specify the rules for handling problems (stop on first error or accumulate
+ * them all) and at the same time perform some actions such as opening a dialog
+ * in UI when compiling interactively.
+ * @see org.eclipse.jdt.internal.compiler.api.problem.DefaultErrorHandlingPolicies
+ *
+ * @param requestor org.eclipse.jdt.internal.compiler.api.ICompilerRequestor
+ * Component which will receive and persist all compilation results and is intended
+ * to consume them as they are produced. Typically, in a batch compiler, it is
+ * responsible for writing out the actual .class files to the file system.
+ * @see org.eclipse.jdt.internal.compiler.api.CompilationResult
+ *
+ * @param problemFactory org.eclipse.jdt.internal.compiler.api.problem.IProblemFactory
+ * Factory used inside the compiler to create problem descriptors. It allows the
+ * compiler client to supply its own representation of compilation problems in
+ * order to avoid object conversions. Note that the factory is not supposed
+ * to accumulate the created problems, the compiler will gather them all and hand
+ * them back as part of the compilation unit result.
+ */
+ public Compiler(
+ INameEnvironment environment,
+ IErrorHandlingPolicy policy,
+ ConfigurableOption[] settings,
+ ICompilerRequestor requestor,
+ IProblemFactory problemFactory) {
+
+ // create a problem handler given a handling policy
+ this.options = new CompilerOptions(settings);
+ this.requestor = requestor;
+ this.problemReporter =
+ new ProblemReporter(policy, this.options, problemFactory);
+ this.lookupEnvironment =
+ new LookupEnvironment(this, options, problemReporter, environment);
+ this.parser =
+ new Parser(problemReporter, this.options.parseLiteralExpressionsAsConstants);
+ }
+
+ /**
+ * Add an additional binary type
+ */
+
+ public void accept(IBinaryType binaryType, PackageBinding packageBinding) {
+ lookupEnvironment.createBinaryTypeFrom(binaryType, packageBinding);
+ }
+
+ /**
+ * Add an additional compilation unit into the loop
+ * -> build compilation unit declarations, their bindings and record their results.
+ */
+
+ public void accept(ICompilationUnit sourceUnit) {
+ // Switch the current policy and compilation result for this unit to the requested one.
+ CompilationResult unitResult =
+ new CompilationResult(sourceUnit, totalUnits, totalUnits);
+ try {
+ // diet parsing for large collection of unit
+ CompilationUnitDeclaration parsedUnit;
+ if (totalUnits < parseThreshold) {
+ parsedUnit = parser.parse(sourceUnit, unitResult);
+ } else {
+ parsedUnit = parser.dietParse(sourceUnit, unitResult);
+ }
+
+ if (options.verbose) {
+ System.out.println(
+ "request "
+ + (totalUnits + 1)
+ + "/"
+ + (totalUnits + 1)
+ + " : "
+ + new String(sourceUnit.getFileName()));
+ }
+
+ // initial type binding creation
+ lookupEnvironment.buildTypeBindings(parsedUnit);
+ this.addCompilationUnit(sourceUnit, parsedUnit);
+
+ // binding resolution
+ lookupEnvironment.completeTypeBindings(parsedUnit);
+ } catch (AbortCompilationUnit e) {
+ // at this point, currentCompilationUnitResult may not be sourceUnit, but some other
+ // one requested further along to resolve sourceUnit.
+ if (unitResult.compilationUnit == sourceUnit) { // only report once
+ requestor.acceptResult(unitResult.tagAsAccepted());
+ } else {
+ throw e; // want to abort enclosing request to compile
+ }
+ }
+ }
+
+ /**
+ * Add an additional source type
+ */
+
+ public void accept(ISourceType sourceType, PackageBinding packageBinding) {
+ problemReporter.abortDueToInternalError(
+ new StringBuffer("Cannot compile against source model ")
+ .append(sourceType.getName())
+ .append(" issued from ")
+ .append(sourceType.getFileName())
+ .toString());
+ }
+
+ protected void addCompilationUnit(
+ ICompilationUnit sourceUnit,
+ CompilationUnitDeclaration parsedUnit) {
+
+ // append the unit to the list of ones to process later on
+ int size = unitsToProcess.length;
+ if (totalUnits == size)
+ // when growing reposition units starting at position 0
+ System.arraycopy(
+ unitsToProcess,
+ 0,
+ (unitsToProcess = new CompilationUnitDeclaration[size * 2]),
+ 0,
+ totalUnits);
+ unitsToProcess[totalUnits++] = parsedUnit;
+ }
+
+ /**
+ * Add the initial set of compilation units into the loop
+ * -> build compilation unit declarations, their bindings and record their results.
+ */
+ protected void beginToCompile(ICompilationUnit[] sourceUnits) {
+ int maxUnits = sourceUnits.length;
+ totalUnits = 0;
+ unitsToProcess = new CompilationUnitDeclaration[maxUnits];
+
+ // Switch the current policy and compilation result for this unit to the requested one.
+ for (int i = 0; i < maxUnits; i++) {
+ CompilationUnitDeclaration parsedUnit;
+ CompilationResult unitResult =
+ new CompilationResult(sourceUnits[i], i, maxUnits);
+ try {
+ // diet parsing for large collection of units
+ if (totalUnits < parseThreshold) {
+ parsedUnit = parser.parse(sourceUnits[i], unitResult);
+ } else {
+ parsedUnit = parser.dietParse(sourceUnits[i], unitResult);
+ }
+ if (options.verbose) {
+ System.out.println(
+ "request "
+ + (i + 1)
+ + "/"
+ + maxUnits
+ + " : "
+ + new String(sourceUnits[i].getFileName()));
+ }
+ // initial type binding creation
+ lookupEnvironment.buildTypeBindings(parsedUnit);
+ this.addCompilationUnit(sourceUnits[i], parsedUnit);
+ //} catch (AbortCompilationUnit e) {
+ // requestor.acceptResult(unitResult.tagAsAccepted());
+ } finally {
+ sourceUnits[i] = null; // no longer hold onto the unit
+ }
+ }
+ // binding resolution
+ lookupEnvironment.completeTypeBindings();
+ }
+
+ /**
+ * General API
+ * -> compile each of supplied files
+ * -> recompile any required types for which we have an incomplete principle structure
+ */
+
+ public void compile(ICompilationUnit[] sourceUnits) {
+ CompilationUnitDeclaration unit = null;
+ int i = 0;
+ try {
+ // build and record parsed units
+
+ beginToCompile(sourceUnits);
+
+ // process all units (some more could be injected in the loop by the lookup environment)
+ for (; i < totalUnits; i++) {
+ unit = unitsToProcess[i];
+ try {
+ if (options.verbose)
+ System.out.println(
+ "process "
+ + (i + 1)
+ + "/"
+ + totalUnits
+ + " : "
+ + new String(unitsToProcess[i].getFileName()));
+ process(unit, i);
+ } finally {
+ // cleanup compilation unit result
+ unit.cleanUp();
+ if (options.verbose)
+ System.out.println(
+ "done "
+ + (i + 1)
+ + "/"
+ + totalUnits
+ + " : "
+ + new String(unitsToProcess[i].getFileName()));
+ }
+ unitsToProcess[i] = null; // release reference to processed unit declaration
+ requestor.acceptResult(unit.compilationResult.tagAsAccepted());
+ }
+ } catch (AbortCompilation e) {
+ this.handleInternalException(e, unit);
+ } catch (Error e) {
+ this.handleInternalException(e, unit, null);
+ throw e; // rethrow
+ } catch (RuntimeException e) {
+ this.handleInternalException(e, unit, null);
+ throw e; // rethrow
+ } finally {
+ this.reset();
+ }
+ if (options.verbose) {
+ if (totalUnits > 1) {
+ System.out.println(totalUnits + " units compiled");
+ } else {
+ System.out.println(totalUnits + " unit compiled");
+ }
+ }
+ }
+
+ /**
+ * Answer an array of descriptions for the configurable options.
+ * The descriptions may be changed and passed back to a different
+ * compiler.
+ *
+ * @return ConfigurableOption[] - array of configurable options
+ */
+ public static ConfigurableOption[] getDefaultOptions(Locale locale) {
+ return new CompilerOptions().getConfigurableOptions(locale);
+ }
+
+ protected void getMethodBodies(CompilationUnitDeclaration unit, int place) {
+ //fill the methods bodies in order for the code to be generated
+
+ if (unit.ignoreMethodBodies) {
+ unit.ignoreFurtherInvestigation = true;
+ return;
+ // if initial diet parse did not work, no need to dig into method bodies.
+ }
+
+ if (place < parseThreshold)
+ return; //work already done ...
+
+ //real parse of the method....
+ parser.scanner.setSourceBuffer(
+ unit.compilationResult.compilationUnit.getContents());
+ if (unit.types != null) {
+ for (int i = unit.types.length; --i >= 0;)
+ unit.types[i].parseMethod(parser, unit);
+ }
+ }
+
+ /*
+ * Compiler crash recovery in case of unexpected runtime exceptions
+ */
+ protected void handleInternalException(
+ Throwable internalException,
+ CompilationUnitDeclaration unit,
+ CompilationResult result) {
+
+ /* dump a stack trace to the console */
+ internalException.printStackTrace();
+
+ /* find a compilation result */
+ if ((unit != null)) // basing result upon the current unit if available
+ result = unit.compilationResult; // current unit being processed ?
+ if ((result == null) && (unitsToProcess != null) && (totalUnits > 0))
+ result = unitsToProcess[totalUnits - 1].compilationResult;
+ // last unit in beginToCompile ?
+
+ if (result != null) {
+ /* create and record a compilation problem */
+ StringWriter stringWriter = new StringWriter();
+ PrintWriter writer = new PrintWriter(stringWriter);
+ internalException.printStackTrace(writer);
+ StringBuffer buffer = stringWriter.getBuffer();
+
+ result
+ .record(
+ problemReporter
+ .createProblem(
+ result.getFileName(),
+ ProblemIrritants.UnclassifiedProblem,
+ new String[] { "Internal compiler error\n" + buffer.toString()},
+ Error,
+ // severity
+ 0, // source start
+ 0, // source end
+ 0)); // line number
+
+ /* hand back the compilation result */
+ if (!result.hasBeenAccepted) {
+ requestor.acceptResult(result.tagAsAccepted());
+ }
+ }
+ }
+
+ /*
+ * Compiler recovery in case of internal AbortCompilation event
+ */
+ protected void handleInternalException(
+ AbortCompilation abortException,
+ CompilationUnitDeclaration unit) {
+
+ /* special treatment for SilentAbort: silently cancelling the compilation process */
+ if (abortException.isSilent) {
+ if (abortException.silentException == null) {
+ return;
+ } else {
+ throw abortException.silentException;
+ }
+ }
+
+ /* uncomment following line to see where the abort came from */
+ // abortException.printStackTrace();
+
+ // Exception may tell which compilation result it is related, and which problem caused it
+ CompilationResult result = abortException.compilationResult;
+ if ((result == null) && (unit != null))
+ result = unit.compilationResult; // current unit being processed ?
+ if ((result == null) && (unitsToProcess != null) && (totalUnits > 0))
+ result = unitsToProcess[totalUnits - 1].compilationResult;
+ // last unit in beginToCompile ?
+ if (result != null && !result.hasBeenAccepted) {
+ /* distant problem which could not be reported back there */
+ if (abortException.problemId != 0) {
+ result
+ .record(
+ problemReporter
+ .createProblem(
+ result.getFileName(),
+ abortException.problemId,
+ abortException.problemArguments,
+ Error,
+ // severity
+ 0, // source start
+ 0, // source end
+ 0)); // line number
+ } else {
+ /* distant internal exception which could not be reported back there */
+ if (abortException.exception != null) {
+ this.handleInternalException(abortException.exception, null, result);
+ return;
+ }
+ }
+ /* hand back the compilation result */
+ if (!result.hasBeenAccepted) {
+ requestor.acceptResult(result.tagAsAccepted());
+ }
+ } else {
+ /*
+ if (abortException.problemId != 0){
+ IProblem problem =
+ problemReporter.createProblem(
+ "???".toCharArray(),
+ abortException.problemId,
+ abortException.problemArguments,
+ Error, // severity
+ 0, // source start
+ 0, // source end
+ 0); // line number
+ System.out.println(problem.getMessage());
+ }
+ */
+ abortException.printStackTrace();
+ }
+ }
+
+ /**
+ * Process a compilation unit already parsed and build.
+ */
+ private void process(CompilationUnitDeclaration unit, int i) {
+
+ getMethodBodies(unit, i);
+
+ // fault in fields & methods
+ if (unit.scope != null)
+ unit.scope.faultInTypes();
+
+ // verify inherited methods
+ if (unit.scope != null)
+ unit.scope.verifyMethods(lookupEnvironment.methodVerifier());
+
+ // type checking
+ long startTime = System.currentTimeMillis();
+ unit.resolve();
+
+ // flow analysis
+ startTime = System.currentTimeMillis();
+ unit.analyseCode();
+
+ // code generation
+ startTime = System.currentTimeMillis();
+ unit.generateCode();
+
+ // reference info
+ if (options.produceReferenceInfo && unit.scope != null)
+ unit.scope.storeDependencyInfo();
+
+ // refresh the total number of units known at this stage
+ unit.compilationResult.totalUnitsKnown = totalUnits;
+ }
+
+ public void reset() {
+ lookupEnvironment.reset();
+ parser.scanner.source = null;
+ unitsToProcess = null;
+ }
+
+ /**
+ * Internal API used to resolve a compilation unit minimally for code assist engine
+ */
+
+ public CompilationUnitDeclaration resolve(ICompilationUnit sourceUnit) {
+ CompilationUnitDeclaration unit = null;
+ try {
+ // build and record parsed units
+ parseThreshold = 1; // will request a full parse
+ beginToCompile(new ICompilationUnit[] { sourceUnit });
+ // process all units (some more could be injected in the loop by the lookup environment)
+ unit = unitsToProcess[0];
+ //getMethodBodies(unit,i);
+ if (unit.scope != null) {
+ // fault in fields & methods
+ unit.scope.faultInTypes();
+ // type checking
+ unit.resolve();
+ }
+ unitsToProcess[0] = null; // release reference to processed unit declaration
+ requestor.acceptResult(unit.compilationResult.tagAsAccepted());
+ return unit;
+ } catch (AbortCompilation e) {
+ this.handleInternalException(e, unit);
+ return unit == null ? unitsToProcess[0] : unit;
+ } catch (Error e) {
+ this.handleInternalException(e, unit, null);
+ throw e; // rethrow
+ } catch (RuntimeException e) {
+ this.handleInternalException(e, unit, null);
+ throw e; // rethrow
+ } finally {
+ // No reset is performed there anymore since,
+ // within the CodeAssist (or related tools),
+ // the compiler may be called *after* a call
+ // to this resolve(...) method. And such a call
+ // needs to have a compiler with a non-empty
+ // environment.
+ // this.reset();
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ConfigurableOption.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ConfigurableOption.java
new file mode 100644
index 0000000000..8536a462b9
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ConfigurableOption.java
@@ -0,0 +1,227 @@
+package org.eclipse.jdt.internal.compiler;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/**
+ * Generic option description, which can be modified independently from the
+ * component it belongs to.
+ */
+
+import java.util.*;
+
+public class ConfigurableOption {
+ private String componentName;
+ private int id;
+
+ private String category;
+ private String name;
+ private String description;
+ private int currentValueIndex;
+ private int defaultValueIndex;
+ private String[] possibleValues;
+
+ // special value for <possibleValues> indicating that
+ // the <currentValueIndex> is the actual value
+ public final static String[] NoDiscreteValue = {
+ };
+
+ /**
+ * INTERNAL USE ONLY
+ *
+ * Initialize an instance of this class according to a specific locale
+ *
+ * @param loc java.util.Locale
+ */
+ public ConfigurableOption(
+ String componentName,
+ String optionName,
+ Locale loc,
+ int currentValueIndex) {
+
+ this.componentName = componentName;
+ this.currentValueIndex = currentValueIndex;
+
+ ResourceBundle resource = null;
+ try {
+ String location = componentName.substring(0, componentName.lastIndexOf('.'));
+ resource = ResourceBundle.getBundle(location + ".Options", loc);
+ } catch (MissingResourceException e) {
+ category = "Missing ressources entries for" + componentName + " options";
+ name = "Missing ressources entries for" + componentName + " options";
+ description = "Missing ressources entries for" + componentName + " options";
+ possibleValues = new String[0];
+ id = -1;
+ }
+ if (resource == null)
+ return;
+ try {
+ id = Integer.parseInt(resource.getString(optionName + ".number"));
+ } catch (MissingResourceException e) {
+ id = -1;
+ } catch (NumberFormatException e) {
+ id = -1;
+ }
+ try {
+ category = resource.getString(optionName + ".category");
+ } catch (MissingResourceException e) {
+ category = "Missing ressources entries for" + componentName + " options";
+ }
+ try {
+ name = resource.getString(optionName + ".name");
+ } catch (MissingResourceException e) {
+ name = "Missing ressources entries for" + componentName + " options";
+ }
+ try {
+ StringTokenizer tokenizer =
+ new StringTokenizer(resource.getString(optionName + ".possibleValues"), "|");
+ int numberOfValues = Integer.parseInt(tokenizer.nextToken());
+ if (numberOfValues == -1) {
+ possibleValues = NoDiscreteValue;
+ } else {
+ possibleValues = new String[numberOfValues];
+ int index = 0;
+ while (tokenizer.hasMoreTokens()) {
+ possibleValues[index] = tokenizer.nextToken();
+ index++;
+ }
+ }
+ } catch (MissingResourceException e) {
+ possibleValues = new String[0];
+ } catch (NoSuchElementException e) {
+ possibleValues = new String[0];
+ } catch (NumberFormatException e) {
+ possibleValues = new String[0];
+ }
+ try {
+ description = resource.getString(optionName + ".description");
+ } catch (MissingResourceException e) {
+ description = "Missing ressources entries for" + componentName + " options";
+ }
+ }
+
+ /**
+ * Return a String that represents the localized category of the receiver.
+ * @return java.lang.String
+ */
+ public String getCategory() {
+ return category;
+ }
+
+ /**
+ * Return a String that identifies the component owner (typically the qualified
+ * type name of the class which it corresponds to).
+ *
+ * e.g. "org.eclipse.jdt.internal.compiler.api.Compiler"
+ *
+ * @return java.lang.String
+ */
+ public String getComponentName() {
+ return componentName;
+ }
+
+ /**
+ * Answer the index (in possibleValues array) of the current setting for this
+ * particular option.
+ *
+ * In case the set of possibleValues is NoDiscreteValue, then this index is the
+ * actual value (e.g. max line lenght set to 80).
+ *
+ * @return int
+ */
+ public int getCurrentValueIndex() {
+ return currentValueIndex;
+ }
+
+ /**
+ * Answer the index (in possibleValues array) of the default setting for this
+ * particular option.
+ *
+ * In case the set of possibleValues is NoDiscreteValue, then this index is the
+ * actual value (e.g. max line lenght set to 80).
+ *
+ * @return int
+ */
+ public int getDefaultValueIndex() {
+ return defaultValueIndex;
+ }
+
+ /**
+ * Return an String that represents the localized description of the receiver.
+ *
+ * @return java.lang.String
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Internal ID which allows the configurable component to identify this particular option.
+ *
+ * @return int
+ */
+ public int getID() {
+ return id;
+ }
+
+ /**
+ * Return a String that represents the localized name of the receiver.
+ * @return java.lang.String
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Return an array of String that represents the localized possible values of the receiver.
+ * @return java.lang.String[]
+ */
+ public String[] getPossibleValues() {
+ return possibleValues;
+ }
+
+ /**
+ * Change the index (in possibleValues array) of the current setting for this
+ * particular option.
+ *
+ * In case the set of possibleValues is NoDiscreteValue, then this index is the
+ * actual value (e.g. max line lenght set to 80).
+ *
+ * @return int
+ */
+ public void setValueIndex(int newIndex) {
+ currentValueIndex = newIndex;
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("Configurable option for ");
+ buffer.append(this.componentName).append("\n");
+ buffer.append("- category: ").append(this.category).append("\n");
+ buffer.append("- name: ").append(this.name).append("\n");
+ /* display current value */
+ buffer.append("- current value: ");
+ if (possibleValues == NoDiscreteValue) {
+ buffer.append(this.currentValueIndex);
+ } else {
+ buffer.append(this.possibleValues[this.currentValueIndex]);
+ }
+ buffer.append("\n");
+
+ /* display possible values */
+ if (possibleValues != NoDiscreteValue) {
+ buffer.append("- possible values: [");
+ for (int i = 0, max = possibleValues.length; i < max; i++) {
+ if (i != 0)
+ buffer.append(", ");
+ buffer.append(possibleValues[i]);
+ }
+ buffer.append("]\n");
+ buffer.append("- curr. val. index: ").append(currentValueIndex).append("\n");
+ }
+ buffer.append("- description: ").append(description).append("\n");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/DefaultErrorHandlingPolicies.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/DefaultErrorHandlingPolicies.java
new file mode 100644
index 0000000000..26307bf801
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/DefaultErrorHandlingPolicies.java
@@ -0,0 +1,69 @@
+package org.eclipse.jdt.internal.compiler;
+
+public class DefaultErrorHandlingPolicies {
+
+ /*
+ * Accumulate all problems, then exit without proceeding.
+ *
+ * Typically, the #proceedWithProblems(Problem[]) should
+ * show the problems.
+ *
+ */
+ public static IErrorHandlingPolicy exitAfterAllProblems() {
+ return new IErrorHandlingPolicy() {
+ public boolean stopOnFirstError() {
+ return false;
+ }
+ public boolean proceedOnErrors() {
+ return false;
+ }
+ };
+ }
+
+ /*
+ * Exit without proceeding on the first problem wich appears
+ * to be an error.
+ *
+ */
+ public static IErrorHandlingPolicy exitOnFirstError() {
+ return new IErrorHandlingPolicy() {
+ public boolean stopOnFirstError() {
+ return true;
+ }
+ public boolean proceedOnErrors() {
+ return false;
+ }
+ };
+ }
+
+ /*
+ * Proceed on the first error met.
+ *
+ */
+ public static IErrorHandlingPolicy proceedOnFirstError() {
+ return new IErrorHandlingPolicy() {
+ public boolean stopOnFirstError() {
+ return true;
+ }
+ public boolean proceedOnErrors() {
+ return true;
+ }
+ };
+ }
+
+ /*
+ * Accumulate all problems, then proceed with them.
+ *
+ */
+ public static IErrorHandlingPolicy proceedWithAllProblems() {
+ return new IErrorHandlingPolicy() {
+ public boolean stopOnFirstError() {
+ return false;
+ }
+ public boolean proceedOnErrors() {
+ return true;
+ }
+ };
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/DocumentElementParser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/DocumentElementParser.java
new file mode 100644
index 0000000000..7a52dca5b8
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/DocumentElementParser.java
@@ -0,0 +1,1377 @@
+package org.eclipse.jdt.internal.compiler;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * A document element parser extracts structural information
+ * from a piece of source, providing detailed source positions info.
+ *
+ * also see @IDocumentElementRequestor
+ *
+ * The structural investigation includes:
+ * - the package statement
+ * - import statements
+ * - top-level types: package member, member types (member types of member types...)
+ * - fields
+ * - methods
+ *
+ * Any (parsing) problem encountered is also provided.
+ */
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.env.*;
+
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.parser.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class DocumentElementParser extends Parser {
+ IDocumentElementRequestor requestor;
+ private int localIntPtr;
+ private int lastFieldEndPosition;
+ private int lastFieldBodyEndPosition;
+ private int typeStartPosition;
+ private long selectorSourcePositions;
+ private int typeDims;
+ private int extendsDim;
+ private int declarationSourceStart;
+
+ /* int[] stack for storing javadoc positions */
+ int[][] intArrayStack;
+ int intArrayPtr;
+ public DocumentElementParser(
+ final IDocumentElementRequestor requestor,
+ IProblemFactory problemFactory) {
+ super(new ProblemReporter(
+ DefaultErrorHandlingPolicies.exitAfterAllProblems(),
+ new CompilerOptions(),
+ problemFactory) {
+ public void record(IProblem problem, CompilationResult unitResult) {
+ requestor.acceptProblem(problem);
+ }
+ }, false);
+ this.requestor = requestor;
+ intArrayStack = new int[30][];
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void adjustInterfaceModifiers() {
+ intStack[intPtr - 2] |= AccInterface;
+ }
+
+ /*
+ * Will clear the comment stack when looking
+ * for a potential JavaDoc which might contain @deprecated.
+ *
+ * Additionally, before investigating for @deprecated, retrieve the positions
+ * of the JavaDoc comments so as to notify requestor with them.
+ */
+ public void checkAnnotation() {
+
+ /* persisting javadoc positions */
+ pushOnIntArrayStack(this.getJavaDocPositions());
+ boolean deprecated = false;
+ int lastAnnotationIndex = -1;
+
+ //since jdk1.2 look only in the last java doc comment...
+ found : {
+ if ((lastAnnotationIndex = scanner.commentPtr) >= 0) { //look for @deprecated
+ scanner.commentPtr = -1;
+ // reset the comment stack, since not necessary after having checked
+ int commentSourceStart = scanner.commentStarts[lastAnnotationIndex];
+ // javadoc only (non javadoc comment have negative end positions.)
+ int commentSourceEnd = scanner.commentStops[lastAnnotationIndex] - 1;
+ //stop is one over
+ char[] comment = scanner.source;
+
+ for (int i = commentSourceStart + 3; i < commentSourceEnd - 10; i++) {
+ if ((comment[i] == '@')
+ && (comment[i + 1] == 'd')
+ && (comment[i + 2] == 'e')
+ && (comment[i + 3] == 'p')
+ && (comment[i + 4] == 'r')
+ && (comment[i + 5] == 'e')
+ && (comment[i + 6] == 'c')
+ && (comment[i + 7] == 'a')
+ && (comment[i + 8] == 't')
+ && (comment[i + 9] == 'e')
+ && (comment[i + 10] == 'd')) {
+ // ensure the tag is properly ended: either followed by a space, line end or asterisk.
+ int nextPos = i + 11;
+ deprecated =
+ (comment[nextPos] == ' ')
+ || (comment[nextPos] == '\n')
+ || (comment[nextPos] == '\r')
+ || (comment[nextPos] == '*');
+ break found;
+ }
+ }
+ }
+ }
+ if (deprecated) {
+ checkAndSetModifiers(AccDeprecated);
+ }
+ // modify the modifier source start to point at the first comment
+ if (lastAnnotationIndex >= 0) {
+ declarationSourceStart = scanner.commentStarts[0];
+ }
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumeClassBodyDeclaration() {
+ // ClassBodyDeclaration ::= Diet Block
+ //push an Initializer
+ //optimize the push/pop
+
+ super.consumeClassBodyDeclaration();
+ Initializer initializer = (Initializer) astStack[astPtr];
+ requestor.acceptInitializer(
+ initializer.declarationSourceStart,
+ initializer.declarationSourceEnd,
+ intArrayStack[intArrayPtr--],
+ 0,
+ modifiersSourceStart,
+ initializer.block.sourceStart,
+ initializer.block.sourceEnd);
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumeClassDeclaration() {
+ super.consumeClassDeclaration();
+ // we know that we have a TypeDeclaration on the top of the astStack
+ if (isLocalDeclaration()) {
+ // we ignore the local variable declarations
+ return;
+ }
+ requestor.exitClass(endStatementPosition, // '}' is the end of the body
+ ((TypeDeclaration) astStack[astPtr]).declarationSourceEnd);
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumeClassHeader() {
+ //ClassHeader ::= $empty
+ super.consumeClassHeader();
+ if (isLocalDeclaration()) {
+ // we ignore the local variable declarations
+ intArrayPtr--;
+ return;
+ }
+ TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr];
+ TypeReference[] superInterfaces = typeDecl.superInterfaces;
+ char[][] interfaceNames = null;
+ int[] interfaceNameStarts = null;
+ int[] interfaceNameEnds = null;
+ if (superInterfaces != null) {
+ int superInterfacesLength = superInterfaces.length;
+ interfaceNames = new char[superInterfacesLength][];
+ interfaceNameStarts = new int[superInterfacesLength];
+ interfaceNameEnds = new int[superInterfacesLength];
+ for (int i = 0; i < superInterfacesLength; i++) {
+ TypeReference superInterface = superInterfaces[i];
+ interfaceNames[i] = CharOperation.concatWith(superInterface.getTypeName(), '.');
+ interfaceNameStarts[i] = superInterface.sourceStart();
+ interfaceNameEnds[i] = superInterface.sourceEnd();
+ }
+ }
+ // flush the comments related to the class header
+ scanner.commentPtr = -1;
+ TypeReference superclass = typeDecl.superclass;
+ if (superclass == null) {
+ requestor.enterClass(
+ typeDecl.declarationSourceStart,
+ intArrayStack[intArrayPtr--],
+ typeDecl.modifiers,
+ typeDecl.modifiersSourceStart,
+ typeStartPosition,
+ typeDecl.name,
+ typeDecl.sourceStart(),
+ typeDecl.sourceEnd(),
+ null,
+ -1,
+ -1,
+ interfaceNames,
+ interfaceNameStarts,
+ interfaceNameEnds,
+ scanner.currentPosition - 1);
+ } else {
+ requestor.enterClass(
+ typeDecl.declarationSourceStart,
+ intArrayStack[intArrayPtr--],
+ typeDecl.modifiers,
+ typeDecl.modifiersSourceStart,
+ typeStartPosition,
+ typeDecl.name,
+ typeDecl.sourceStart(),
+ typeDecl.sourceEnd(),
+ CharOperation.concatWith(superclass.getTypeName(), '.'),
+ superclass.sourceStart(),
+ superclass.sourceEnd(),
+ interfaceNames,
+ interfaceNameStarts,
+ interfaceNameEnds,
+ scanner.currentPosition - 1);
+
+ }
+ }
+
+ protected void consumeClassHeaderName() {
+ // ClassHeaderName ::= Modifiersopt 'class' 'Identifier'
+ TypeDeclaration typeDecl;
+ int length;
+ if (nestedMethod[nestedType] == 0) {
+ if (nestedType != 0) {
+ typeDecl = new MemberTypeDeclaration();
+ } else {
+ typeDecl = new TypeDeclaration();
+ }
+ } else {
+ // Record that the block has a declaration for local types
+ typeDecl = new LocalTypeDeclaration();
+ blockReal();
+ }
+
+ //highlight the name of the type
+ long pos = identifierPositionStack[identifierPtr];
+ typeDecl.sourceEnd = (int) pos;
+ typeDecl.sourceStart = (int) (pos >>> 32);
+ typeDecl.name = identifierStack[identifierPtr--];
+ identifierLengthPtr--;
+
+ //compute the declaration source too
+ // 'class' and 'interface' push an int position
+ typeStartPosition = typeDecl.declarationSourceStart = intStack[intPtr--];
+ int declarationSourceStart = intStack[intPtr--];
+ typeDecl.modifiersSourceStart = intStack[intPtr--];
+ typeDecl.modifiers = intStack[intPtr--];
+ if (typeDecl.declarationSourceStart > declarationSourceStart) {
+ typeDecl.declarationSourceStart = declarationSourceStart;
+ }
+ typeDecl.bodyStart = typeDecl.sourceEnd + 1;
+ pushOnAstStack(typeDecl);
+
+ length = 0; // will be updated when reading super-interfaces
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumeCompilationUnit() {
+ // CompilationUnit ::= EnterCompilationUnit PackageDeclarationopt ImportDeclarationsopt
+ requestor.exitCompilationUnit(scanner.source.length - 1);
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumeConstructorDeclaration() {
+ // ConstructorDeclaration ::= ConstructorHeader ConstructorBody
+ super.consumeConstructorDeclaration();
+ if (isLocalDeclaration()) {
+ // we ignore the local variable declarations
+ return;
+ }
+ ConstructorDeclaration cd = (ConstructorDeclaration) astStack[astPtr];
+ requestor.exitConstructor(endStatementPosition, cd.declarationSourceEnd);
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumeConstructorHeader() {
+ // ConstructorHeader ::= ConstructorHeaderName MethodHeaderParameters MethodHeaderThrowsClauseopt
+ super.consumeConstructorHeader();
+ if (isLocalDeclaration()) {
+ // we ignore the local variable declarations
+ intArrayPtr--;
+ return;
+ }
+ ConstructorDeclaration cd = (ConstructorDeclaration) astStack[astPtr];
+ Argument[] arguments = cd.arguments;
+ char[][] argumentTypes = null;
+ char[][] argumentNames = null;
+ int[] argumentTypeStarts = null;
+ int[] argumentTypeEnds = null;
+ int[] argumentNameStarts = null;
+ int[] argumentNameEnds = null;
+ if (arguments != null) {
+ int argumentLength = arguments.length;
+ argumentTypes = new char[argumentLength][];
+ argumentNames = new char[argumentLength][];
+ argumentNameStarts = new int[argumentLength];
+ argumentNameEnds = new int[argumentLength];
+ argumentTypeStarts = new int[argumentLength];
+ argumentTypeEnds = new int[argumentLength];
+ for (int i = 0; i < argumentLength; i++) {
+ Argument argument = arguments[i];
+ TypeReference argumentType = argument.type;
+ argumentTypes[i] = returnTypeName(argumentType);
+ argumentNames[i] = argument.name;
+ argumentNameStarts[i] = argument.sourceStart();
+ argumentNameEnds[i] = argument.sourceEnd();
+ argumentTypeStarts[i] = argumentType.sourceStart();
+ argumentTypeEnds[i] = argumentType.sourceEnd();
+ }
+ }
+ TypeReference[] thrownExceptions = cd.thrownExceptions;
+ char[][] exceptionTypes = null;
+ int[] exceptionTypeStarts = null;
+ int[] exceptionTypeEnds = null;
+ if (thrownExceptions != null) {
+ int thrownExceptionLength = thrownExceptions.length;
+ exceptionTypes = new char[thrownExceptionLength][];
+ exceptionTypeStarts = new int[thrownExceptionLength];
+ exceptionTypeEnds = new int[thrownExceptionLength];
+ for (int i = 0; i < thrownExceptionLength; i++) {
+ TypeReference exception = thrownExceptions[i];
+ exceptionTypes[i] = CharOperation.concatWith(exception.getTypeName(), '.');
+ exceptionTypeStarts[i] = exception.sourceStart();
+ exceptionTypeEnds[i] = exception.sourceEnd();
+ }
+ }
+ requestor
+ .enterConstructor(
+ cd.declarationSourceStart,
+ intArrayStack[intArrayPtr--],
+ cd.modifiers,
+ cd.modifiersSourceStart,
+ cd.selector,
+ cd.sourceStart(),
+ (int) (selectorSourcePositions & 0xFFFFFFFFL),
+ // retrieve the source end of the name
+ argumentTypes,
+ argumentTypeStarts,
+ argumentTypeEnds,
+ argumentNames,
+ argumentNameStarts,
+ argumentNameEnds,
+ rParenPos,
+ // right parenthesis
+ exceptionTypes,
+ exceptionTypeStarts,
+ exceptionTypeEnds,
+ scanner.currentPosition - 1);
+ }
+
+ protected void consumeConstructorHeaderName() {
+ // ConstructorHeaderName ::= Modifiersopt 'Identifier' '('
+ ConstructorDeclaration cd = new ConstructorDeclaration();
+
+ //name -- this is not really revelant but we do .....
+ cd.selector = identifierStack[identifierPtr];
+ selectorSourcePositions = identifierPositionStack[identifierPtr--];
+ identifierLengthPtr--;
+
+ //modifiers
+ cd.declarationSourceStart = intStack[intPtr--];
+ cd.modifiersSourceStart = intStack[intPtr--];
+ cd.modifiers = intStack[intPtr--];
+
+ //highlight starts at the selector starts
+ cd.sourceStart = (int) (selectorSourcePositions >>> 32);
+ pushOnAstStack(cd);
+
+ cd.sourceEnd = lParenPos;
+ cd.bodyStart = lParenPos + 1;
+ }
+
+ protected void consumeDefaultModifiers() {
+ checkAnnotation(); // might update modifiers with AccDeprecated
+ pushOnIntStack(modifiers); // modifiers
+ pushOnIntStack(-1);
+ pushOnIntStack(
+ declarationSourceStart >= 0 ? declarationSourceStart : scanner.startPosition);
+ resetModifiers();
+ }
+
+ protected void consumeDiet() {
+ // Diet ::= $empty
+ super.consumeDiet();
+ /* persisting javadoc positions
+ * Will be consume in consumeClassBodyDeclaration
+ */
+ pushOnIntArrayStack(this.getJavaDocPositions());
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumeEnterCompilationUnit() {
+ // EnterCompilationUnit ::= $empty
+ requestor.enterCompilationUnit();
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumeEnterVariable() {
+ // EnterVariable ::= $empty
+ boolean isLocalDeclaration = isLocalDeclaration();
+ if (!isLocalDeclaration && (variablesCounter[nestedType] != 0)) {
+ requestor.exitField(lastFieldBodyEndPosition, lastFieldEndPosition);
+ }
+ char[] name = identifierStack[identifierPtr];
+ long namePosition = identifierPositionStack[identifierPtr--];
+ int extendedTypeDimension = intStack[intPtr--];
+
+ AbstractVariableDeclaration declaration;
+ if (nestedMethod[nestedType] != 0) {
+ // create the local variable declarations
+ declaration =
+ new LocalDeclaration(
+ null,
+ name,
+ (int) (namePosition >>> 32),
+ (int) namePosition);
+ } else {
+ // create the field declaration
+ declaration =
+ new FieldDeclaration(
+ null,
+ name,
+ (int) (namePosition >>> 32),
+ (int) namePosition);
+ }
+ identifierLengthPtr--;
+ TypeReference type;
+ int variableIndex = variablesCounter[nestedType];
+ int typeDim = 0;
+ if (variableIndex == 0) {
+ // first variable of the declaration (FieldDeclaration or LocalDeclaration)
+ if (nestedMethod[nestedType] != 0) {
+ // local declaration
+ declaration.declarationSourceStart = intStack[intPtr--];
+ declaration.modifiersSourceStart = intStack[intPtr--];
+ declaration.modifiers = intStack[intPtr--];
+ type = getTypeReference(typeDim = intStack[intPtr--]); // type dimension
+ pushOnAstStack(type);
+ } else {
+ // field declaration
+ type = getTypeReference(typeDim = intStack[intPtr--]); // type dimension
+ pushOnAstStack(type);
+ declaration.declarationSourceStart = intStack[intPtr--];
+ declaration.modifiersSourceStart = intStack[intPtr--];
+ declaration.modifiers = intStack[intPtr--];
+ }
+ } else {
+ type = (TypeReference) astStack[astPtr - variableIndex];
+ typeDim = type.dimensions();
+ AbstractVariableDeclaration previousVariable =
+ (AbstractVariableDeclaration) astStack[astPtr];
+ declaration.declarationSourceStart = previousVariable.declarationSourceStart;
+ declaration.modifiers = previousVariable.modifiers;
+ declaration.modifiersSourceStart = previousVariable.modifiersSourceStart;
+ }
+
+ localIntPtr = intPtr;
+
+ if (extendedTypeDimension == 0) {
+ declaration.type = type;
+ } else {
+ int dimension = typeDim + extendedTypeDimension;
+ //on the identifierLengthStack there is the information about the type....
+ int baseType;
+ if ((baseType = identifierLengthStack[identifierLengthPtr + 1]) < 0) {
+ //it was a baseType
+ declaration.type = TypeReference.baseTypeReference(-baseType, dimension);
+ } else {
+ declaration.type = type.copyDims(dimension);
+ }
+ }
+ variablesCounter[nestedType]++;
+ nestedMethod[nestedType]++;
+ pushOnAstStack(declaration);
+
+ int[] javadocPositions = intArrayStack[intArrayPtr];
+ if (!isLocalDeclaration) {
+ requestor.enterField(
+ declaration.declarationSourceStart,
+ javadocPositions,
+ declaration.modifiers,
+ declaration.modifiersSourceStart,
+ returnTypeName(declaration.type),
+ type.sourceStart(),
+ type.sourceEnd(),
+ typeDims,
+ name,
+ (int) (namePosition >>> 32),
+ (int) namePosition,
+ extendedTypeDimension,
+ extendedTypeDimension == 0 ? -1 : endPosition);
+ }
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumeExitVariableWithInitialization() {
+ // ExitVariableWithInitialization ::= $empty
+ // the scanner is located after the comma or the semi-colon.
+ // we want to include the comma or the semi-colon
+ super.consumeExitVariableWithInitialization();
+ nestedMethod[nestedType]--;
+ lastFieldEndPosition = scanner.currentPosition - 1;
+ lastFieldBodyEndPosition =
+ ((AbstractVariableDeclaration) astStack[astPtr]).initialization.sourceEnd();
+ }
+
+ protected void consumeExitVariableWithoutInitialization() {
+ // ExitVariableWithoutInitialization ::= $empty
+ // do nothing by default
+ super.consumeExitVariableWithoutInitialization();
+ nestedMethod[nestedType]--;
+ lastFieldEndPosition = scanner.currentPosition - 1;
+ lastFieldBodyEndPosition = scanner.startPosition - 1;
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumeFieldDeclaration() {
+ // See consumeLocalVariableDeclarationDefaultModifier() in case of change: duplicated code
+ // FieldDeclaration ::= Modifiersopt Type VariableDeclarators ';'
+ // the super.consumeFieldDeclaration will reinitialize the variableCounter[nestedType]
+ int variableIndex = variablesCounter[nestedType];
+ super.consumeFieldDeclaration();
+ intArrayPtr--;
+ if (isLocalDeclaration())
+ return;
+ if (variableIndex != 0) {
+ requestor.exitField(lastFieldBodyEndPosition, lastFieldEndPosition);
+ }
+ }
+
+ protected void consumeFormalParameter() {
+ // FormalParameter ::= Type VariableDeclaratorId ==> false
+ // FormalParameter ::= Modifiers Type VariableDeclaratorId ==> true
+ /*
+ astStack :
+ identifierStack : type identifier
+ intStack : dim dim
+ ==>
+ astStack : Argument
+ identifierStack :
+ intStack :
+ */
+
+ identifierLengthPtr--;
+ char[] name = identifierStack[identifierPtr];
+ long namePositions = identifierPositionStack[identifierPtr--];
+ TypeReference type = getTypeReference(intStack[intPtr--] + intStack[intPtr--]);
+ intPtr -= 3;
+ Argument arg = new Argument(name, namePositions, type, intStack[intPtr + 1]);
+ // modifiers
+ pushOnAstStack(arg);
+ intArrayPtr--;
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumeInterfaceDeclaration() {
+ super.consumeInterfaceDeclaration();
+ // we know that we have a TypeDeclaration on the top of the astStack
+ if (isLocalDeclaration()) {
+ // we ignore the local variable declarations
+ return;
+ }
+ requestor.exitInterface(endStatementPosition,
+ // the '}' is the end of the body
+ ((TypeDeclaration) astStack[astPtr]).declarationSourceEnd);
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumeInterfaceHeader() {
+ //InterfaceHeader ::= $empty
+ super.consumeInterfaceHeader();
+ if (isLocalDeclaration()) {
+ // we ignore the local variable declarations
+ intArrayPtr--;
+ return;
+ }
+ TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr];
+ TypeReference[] superInterfaces = typeDecl.superInterfaces;
+ char[][] interfaceNames = null;
+ int[] interfaceNameStarts = null;
+ int[] interfacenameEnds = null;
+ int superInterfacesLength = 0;
+ if (superInterfaces != null) {
+ superInterfacesLength = superInterfaces.length;
+ interfaceNames = new char[superInterfacesLength][];
+ interfaceNameStarts = new int[superInterfacesLength];
+ interfacenameEnds = new int[superInterfacesLength];
+ }
+ if (superInterfaces != null) {
+ for (int i = 0; i < superInterfacesLength; i++) {
+ TypeReference superInterface = superInterfaces[i];
+ interfaceNames[i] = CharOperation.concatWith(superInterface.getTypeName(), '.');
+ interfaceNameStarts[i] = superInterface.sourceStart();
+ interfacenameEnds[i] = superInterface.sourceEnd();
+ }
+ }
+ // flush the comments related to the interface header
+ scanner.commentPtr = -1;
+ requestor.enterInterface(
+ typeDecl.declarationSourceStart,
+ intArrayStack[intArrayPtr--],
+ typeDecl.modifiers,
+ typeDecl.modifiersSourceStart,
+ typeStartPosition,
+ typeDecl.name,
+ typeDecl.sourceStart(),
+ typeDecl.sourceEnd(),
+ interfaceNames,
+ interfaceNameStarts,
+ interfacenameEnds,
+ scanner.currentPosition - 1);
+ }
+
+ protected void consumeInterfaceHeaderName() {
+ // InterfaceHeaderName ::= Modifiersopt 'interface' 'Identifier'
+ TypeDeclaration typeDecl;
+ int length;
+ if (nestedMethod[nestedType] == 0) {
+ if (nestedType != 0) {
+ typeDecl = new MemberTypeDeclaration();
+ } else {
+ typeDecl = new TypeDeclaration();
+ }
+ } else {
+ // Record that the block has a declaration for local types
+ typeDecl = new LocalTypeDeclaration();
+ blockReal();
+ }
+
+ //highlight the name of the type
+ long pos = identifierPositionStack[identifierPtr];
+ typeDecl.sourceEnd = (int) pos;
+ typeDecl.sourceStart = (int) (pos >>> 32);
+ typeDecl.name = identifierStack[identifierPtr--];
+ identifierLengthPtr--;
+
+ //compute the declaration source too
+ // 'class' and 'interface' push an int position
+ typeStartPosition = typeDecl.declarationSourceStart = intStack[intPtr--];
+ int declarationSourceStart = intStack[intPtr--];
+ typeDecl.modifiersSourceStart = intStack[intPtr--];
+ typeDecl.modifiers = intStack[intPtr--];
+ if (typeDecl.declarationSourceStart > declarationSourceStart) {
+ typeDecl.declarationSourceStart = declarationSourceStart;
+ }
+ typeDecl.bodyStart = typeDecl.sourceEnd + 1;
+ pushOnAstStack(typeDecl);
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumeLocalVariableDeclaration() {
+ // See consumeLocalVariableDeclarationDefaultModifier() in case of change: duplicated code
+ // FieldDeclaration ::= Modifiersopt Type VariableDeclarators ';'
+
+ super.consumeLocalVariableDeclaration();
+ intArrayPtr--;
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumeMethodDeclaration(boolean isNotAbstract) {
+ // MethodDeclaration ::= MethodHeader MethodBody
+ // AbstractMethodDeclaration ::= MethodHeader ';'
+ super.consumeMethodDeclaration(isNotAbstract);
+ if (isLocalDeclaration()) {
+ // we ignore the local variable declarations
+ return;
+ }
+ MethodDeclaration md = (MethodDeclaration) astStack[astPtr];
+ requestor.exitMethod(endStatementPosition, md.declarationSourceEnd);
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumeMethodHeader() {
+ // MethodHeader ::= MethodHeaderName MethodHeaderParameters MethodHeaderExtendedDims ThrowsClauseopt
+ super.consumeMethodHeader();
+ if (isLocalDeclaration()) {
+ // we ignore the local variable declarations
+ intArrayPtr--;
+ return;
+ }
+ int length;
+ MethodDeclaration md = (MethodDeclaration) astStack[astPtr];
+
+ TypeReference returnType = md.returnType;
+ char[] returnTypeName = returnTypeName(returnType);
+ Argument[] arguments = md.arguments;
+ char[][] argumentTypes = null;
+ char[][] argumentNames = null;
+ int[] argumentTypeStarts = null;
+ int[] argumentTypeEnds = null;
+ int[] argumentNameStarts = null;
+ int[] argumentNameEnds = null;
+ if (arguments != null) {
+ int argumentLength = arguments.length;
+ argumentTypes = new char[argumentLength][];
+ argumentNames = new char[argumentLength][];
+ argumentNameStarts = new int[argumentLength];
+ argumentNameEnds = new int[argumentLength];
+ argumentTypeStarts = new int[argumentLength];
+ argumentTypeEnds = new int[argumentLength];
+ for (int i = 0; i < argumentLength; i++) {
+ Argument argument = arguments[i];
+ TypeReference argumentType = argument.type;
+ argumentTypes[i] = returnTypeName(argumentType);
+ argumentNames[i] = argument.name;
+ argumentNameStarts[i] = argument.sourceStart();
+ argumentNameEnds[i] = argument.sourceEnd();
+ argumentTypeStarts[i] = argumentType.sourceStart();
+ argumentTypeEnds[i] = argumentType.sourceEnd();
+ }
+ }
+ TypeReference[] thrownExceptions = md.thrownExceptions;
+ char[][] exceptionTypes = null;
+ int[] exceptionTypeStarts = null;
+ int[] exceptionTypeEnds = null;
+ if (thrownExceptions != null) {
+ int thrownExceptionLength = thrownExceptions.length;
+ exceptionTypeStarts = new int[thrownExceptionLength];
+ exceptionTypeEnds = new int[thrownExceptionLength];
+ exceptionTypes = new char[thrownExceptionLength][];
+ for (int i = 0; i < thrownExceptionLength; i++) {
+ TypeReference exception = thrownExceptions[i];
+ exceptionTypes[i] = CharOperation.concatWith(exception.getTypeName(), '.');
+ exceptionTypeStarts[i] = exception.sourceStart();
+ exceptionTypeEnds[i] = exception.sourceEnd();
+ }
+ }
+ requestor.enterMethod(
+ md.declarationSourceStart,
+ intArrayStack[intArrayPtr--],
+ md.modifiers,
+ md.modifiersSourceStart,
+ returnTypeName,
+ returnType.sourceStart(),
+ returnType.sourceEnd(),
+ typeDims,
+ md.selector,
+ md.sourceStart(),
+ (int) (selectorSourcePositions & 0xFFFFFFFFL),
+ argumentTypes,
+ argumentTypeStarts,
+ argumentTypeEnds,
+ argumentNames,
+ argumentNameStarts,
+ argumentNameEnds,
+ rParenPos,
+ extendsDim,
+ extendsDim == 0 ? -1 : endPosition,
+ exceptionTypes,
+ exceptionTypeStarts,
+ exceptionTypeEnds,
+ scanner.currentPosition - 1);
+ }
+
+ protected void consumeMethodHeaderExtendedDims() {
+ // MethodHeaderExtendedDims ::= Dimsopt
+ // now we update the returnType of the method
+ MethodDeclaration md = (MethodDeclaration) astStack[astPtr];
+ int extendedDims = intStack[intPtr--];
+ extendsDim = extendedDims;
+ if (extendedDims != 0) {
+ TypeReference returnType = md.returnType;
+ md.sourceEnd = endPosition;
+ int dims = returnType.dimensions() + extendedDims;
+ int baseType;
+ if ((baseType = identifierLengthStack[identifierLengthPtr + 1]) < 0) {
+ //it was a baseType
+ int sourceStart = returnType.sourceStart();
+ int sourceEnd = returnType.sourceEnd();
+ returnType = TypeReference.baseTypeReference(-baseType, dims);
+ returnType.sourceStart = sourceStart;
+ returnType.sourceEnd = sourceEnd;
+ md.returnType = returnType;
+ } else {
+ md.returnType = md.returnType.copyDims(dims);
+ }
+ if (currentToken == TokenNameLBRACE) {
+ md.bodyStart = endPosition + 1;
+ }
+ }
+ }
+
+ protected void consumeMethodHeaderName() {
+ // MethodHeaderName ::= Modifiersopt Type 'Identifier' '('
+ int length;
+ MethodDeclaration md = new MethodDeclaration();
+
+ //name
+ md.selector = identifierStack[identifierPtr];
+ selectorSourcePositions = identifierPositionStack[identifierPtr--];
+ identifierLengthPtr--;
+ //type
+ md.returnType = getTypeReference(typeDims = intStack[intPtr--]);
+ //modifiers
+ md.declarationSourceStart = intStack[intPtr--];
+ md.modifiersSourceStart = intStack[intPtr--];
+ md.modifiers = intStack[intPtr--];
+
+ //highlight starts at selector start
+ md.sourceStart = (int) (selectorSourcePositions >>> 32);
+ pushOnAstStack(md);
+ md.bodyStart = scanner.currentPosition - 1;
+ }
+
+ protected void consumeModifiers() {
+ checkAnnotation(); // might update modifiers with AccDeprecated
+ pushOnIntStack(modifiers); // modifiers
+ pushOnIntStack(modifiersSourceStart);
+ pushOnIntStack(
+ declarationSourceStart >= 0 ? declarationSourceStart : modifiersSourceStart);
+ resetModifiers();
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumePackageDeclarationName() {
+ /* persisting javadoc positions */
+ pushOnIntArrayStack(this.getJavaDocPositions());
+
+ super.consumePackageDeclarationName();
+ ImportReference importReference = compilationUnit.currentPackage;
+
+ requestor.acceptPackage(
+ importReference.declarationSourceStart,
+ importReference.declarationSourceEnd,
+ intArrayStack[intArrayPtr--],
+ CharOperation.concatWith(importReference.getImportName(), '.'),
+ importReference.sourceStart());
+ }
+
+ protected void consumePushModifiers() {
+ checkAnnotation(); // might update modifiers with AccDeprecated
+ pushOnIntStack(modifiers); // modifiers
+ if (modifiersSourceStart < 0) {
+ pushOnIntStack(-1);
+ pushOnIntStack(
+ declarationSourceStart >= 0 ? declarationSourceStart : scanner.startPosition);
+ } else {
+ pushOnIntStack(modifiersSourceStart);
+ pushOnIntStack(
+ declarationSourceStart >= 0 ? declarationSourceStart : modifiersSourceStart);
+ }
+ resetModifiers();
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumeSingleTypeImportDeclarationName() {
+ // SingleTypeImportDeclarationName ::= 'import' Name
+
+ /* persisting javadoc positions */
+ pushOnIntArrayStack(this.getJavaDocPositions());
+
+ super.consumeSingleTypeImportDeclarationName();
+ ImportReference importReference = (ImportReference) astStack[astPtr];
+ requestor.acceptImport(
+ importReference.declarationSourceStart,
+ importReference.declarationSourceEnd,
+ intArrayStack[intArrayPtr--],
+ CharOperation.concatWith(importReference.getImportName(), '.'),
+ importReference.sourceStart(),
+ false);
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumeStaticInitializer() {
+ // StaticInitializer ::= StaticOnly Block
+ //push an Initializer
+ //optimize the push/pop
+ super.consumeStaticInitializer();
+ Initializer initializer = (Initializer) astStack[astPtr];
+ requestor.acceptInitializer(
+ initializer.declarationSourceStart,
+ initializer.declarationSourceEnd,
+ intArrayStack[intArrayPtr--],
+ AccStatic,
+ intStack[intPtr--],
+ initializer.block.sourceStart,
+ initializer.declarationSourceEnd);
+ }
+
+ protected void consumeStaticOnly() {
+ // StaticOnly ::= 'static'
+ checkAnnotation(); // might update declaration source start
+ pushOnIntStack(modifiersSourceStart);
+ pushOnIntStack(
+ declarationSourceStart >= 0 ? declarationSourceStart : modifiersSourceStart);
+ jumpOverMethodBody();
+ nestedMethod[nestedType]++;
+ resetModifiers();
+ }
+
+ protected void consumeToken(int type) {
+ super.consumeToken(type);
+
+ switch (type) {
+ case TokenNamevoid :
+ case TokenNameboolean :
+ case TokenNamebyte :
+ case TokenNamechar :
+ case TokenNamedouble :
+ case TokenNamefloat :
+ case TokenNameint :
+ case TokenNamelong :
+ case TokenNameshort :
+ // we need this position to know where the base type name ends.
+ pushOnIntStack(scanner.currentPosition - 1);
+ break;
+ }
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumeTypeImportOnDemandDeclarationName() {
+ // TypeImportOnDemandDeclarationName ::= 'import' Name '.' '*'
+
+ /* persisting javadoc positions */
+ pushOnIntArrayStack(this.getJavaDocPositions());
+
+ super.consumeTypeImportOnDemandDeclarationName();
+ ImportReference importReference = (ImportReference) astStack[astPtr];
+ requestor.acceptImport(
+ importReference.declarationSourceStart,
+ importReference.declarationSourceEnd,
+ intArrayStack[intArrayPtr--],
+ CharOperation.concatWith(importReference.getImportName(), '.'),
+ importReference.sourceStart(),
+ true);
+ }
+
+ public CompilationUnitDeclaration endParse(int act) {
+ if (scanner.recordLineSeparator) {
+ requestor.acceptLineSeparatorPositions(scanner.lineEnds());
+ }
+ return super.endParse(act);
+ }
+
+ /*
+ * Flush annotations defined prior to a given positions.
+ *
+ * Note: annotations are stacked in syntactical order
+ *
+ * Either answer given <position>, or the end position of a comment line
+ * immediately following the <position> (same line)
+ *
+ * e.g.
+ * void foo(){
+ * } // end of method foo
+ */
+
+ public int flushAnnotationsDefinedPriorTo(int position) {
+
+ return lastFieldEndPosition = super.flushAnnotationsDefinedPriorTo(position);
+ }
+
+ protected TypeReference getTypeReference(int dim) { /* build a Reference on a variable that may be qualified or not
+ This variable is a type reference and dim will be its dimensions*/
+
+ int length;
+ TypeReference ref;
+ if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) {
+ // single variable reference
+ if (dim == 0) {
+ ref =
+ new SingleTypeReference(
+ identifierStack[identifierPtr],
+ identifierPositionStack[identifierPtr--]);
+ } else {
+ ref =
+ new ArrayTypeReference(
+ identifierStack[identifierPtr],
+ dim,
+ identifierPositionStack[identifierPtr--]);
+ }
+ } else {
+ if (length < 0) { //flag for precompiled type reference on base types
+ ref = TypeReference.baseTypeReference(-length, dim);
+ ref.sourceEnd = intStack[intPtr--];
+ ref.sourceStart = intStack[intPtr--];
+ } else { //Qualified variable reference
+ char[][] tokens = new char[length][];
+ identifierPtr -= length;
+ long[] positions = new long[length];
+ System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length);
+ System.arraycopy(
+ identifierPositionStack,
+ identifierPtr + 1,
+ positions,
+ 0,
+ length);
+ if (dim == 0)
+ ref = new QualifiedTypeReference(tokens, positions);
+ else
+ ref = new ArrayQualifiedTypeReference(tokens, dim, positions);
+ }
+ };
+ return ref;
+ }
+
+ public void initialize() {
+ //positionning the parser for a new compilation unit
+ //avoiding stack reallocation and all that....
+ super.initialize();
+ intArrayPtr = -1;
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ private boolean isLocalDeclaration() {
+ int nestedDepth = nestedType;
+ while (nestedDepth >= 0) {
+ if (nestedMethod[nestedDepth] != 0) {
+ return true;
+ }
+ nestedDepth--;
+ }
+ return false;
+ }
+
+ /*
+ * Investigate one entire unit.
+ */
+ public void parseCompilationUnit(ICompilationUnit unit) {
+ char[] regionSource = unit.getContents();
+ try {
+ initialize();
+ goForCompilationUnit();
+ referenceContext =
+ compilationUnit =
+ compilationUnit =
+ new CompilationUnitDeclaration(
+ problemReporter(),
+ new CompilationResult(unit, 0, 0),
+ regionSource.length);
+ scanner.resetTo(0, regionSource.length);
+ scanner.setSourceBuffer(regionSource);
+ parse();
+ } catch (AbortCompilation ex) {
+ }
+ }
+
+ /*
+ * Investigate one constructor declaration.
+ */
+ public void parseConstructor(char[] regionSource) {
+ try {
+ initialize();
+ goForClassBodyDeclarations();
+ referenceContext =
+ compilationUnit =
+ compilationUnit =
+ new CompilationUnitDeclaration(
+ problemReporter(),
+ new CompilationResult(regionSource, 0, 0),
+ regionSource.length);
+ scanner.resetTo(0, regionSource.length);
+ scanner.setSourceBuffer(regionSource);
+ parse();
+ } catch (AbortCompilation ex) {
+ }
+ }
+
+ /*
+ * Investigate one field declaration statement (might have multiple declarations in it).
+ */
+ public void parseField(char[] regionSource) {
+ try {
+ initialize();
+ goForFieldDeclaration();
+ referenceContext =
+ compilationUnit =
+ compilationUnit =
+ new CompilationUnitDeclaration(
+ problemReporter(),
+ new CompilationResult(regionSource, 0, 0),
+ regionSource.length);
+ scanner.resetTo(0, regionSource.length);
+ scanner.setSourceBuffer(regionSource);
+ parse();
+ } catch (AbortCompilation ex) {
+ }
+
+ }
+
+ /*
+ * Investigate one import statement declaration.
+ */
+ public void parseImport(char[] regionSource) {
+ try {
+ initialize();
+ goForImportDeclaration();
+ referenceContext =
+ compilationUnit =
+ compilationUnit =
+ new CompilationUnitDeclaration(
+ problemReporter(),
+ new CompilationResult(regionSource, 0, 0),
+ regionSource.length);
+ scanner.resetTo(0, regionSource.length);
+ scanner.setSourceBuffer(regionSource);
+ parse();
+ } catch (AbortCompilation ex) {
+ }
+
+ }
+
+ /*
+ * Investigate one initializer declaration.
+ * regionSource need to content exactly an initializer declaration.
+ * e.g: static { i = 4; }
+ * { name = "test"; }
+ */
+ public void parseInitializer(char[] regionSource) {
+ try {
+ initialize();
+ goForInitializer();
+ referenceContext =
+ compilationUnit =
+ compilationUnit =
+ new CompilationUnitDeclaration(
+ problemReporter(),
+ new CompilationResult(regionSource, 0, 0),
+ regionSource.length);
+ scanner.resetTo(0, regionSource.length);
+ scanner.setSourceBuffer(regionSource);
+ parse();
+ } catch (AbortCompilation ex) {
+ }
+
+ }
+
+ /*
+ * Investigate one method declaration.
+ */
+ public void parseMethod(char[] regionSource) {
+ try {
+ initialize();
+ goForGenericMethodDeclaration();
+ referenceContext =
+ compilationUnit =
+ compilationUnit =
+ new CompilationUnitDeclaration(
+ problemReporter(),
+ new CompilationResult(regionSource, 0, 0),
+ regionSource.length);
+ scanner.resetTo(0, regionSource.length);
+ scanner.setSourceBuffer(regionSource);
+ parse();
+ } catch (AbortCompilation ex) {
+ }
+
+ }
+
+ /*
+ * Investigate one package statement declaration.
+ */
+ public void parsePackage(char[] regionSource) {
+ try {
+ initialize();
+ goForPackageDeclaration();
+ referenceContext =
+ compilationUnit =
+ compilationUnit =
+ new CompilationUnitDeclaration(
+ problemReporter(),
+ new CompilationResult(regionSource, 0, 0),
+ regionSource.length);
+ scanner.resetTo(0, regionSource.length);
+ scanner.setSourceBuffer(regionSource);
+ parse();
+ } catch (AbortCompilation ex) {
+ }
+
+ }
+
+ /*
+ * Investigate one type declaration, its fields, methods and member types.
+ */
+ public void parseType(char[] regionSource) {
+ try {
+ initialize();
+ goForTypeDeclaration();
+ referenceContext =
+ compilationUnit =
+ compilationUnit =
+ new CompilationUnitDeclaration(
+ problemReporter(),
+ new CompilationResult(regionSource, 0, 0),
+ regionSource.length);
+ scanner.resetTo(0, regionSource.length);
+ scanner.setSourceBuffer(regionSource);
+ parse();
+ } catch (AbortCompilation ex) {
+ }
+
+ }
+
+ /**
+ * Returns this parser's problem reporter initialized with its reference context.
+ * Also it is assumed that a problem is going to be reported, so initializes
+ * the compilation result's line positions.
+ */
+ public ProblemReporter problemReporter() {
+ problemReporter.referenceContext = referenceContext;
+ return problemReporter;
+ }
+
+ protected void pushOnIntArrayStack(int[] positions) {
+
+ try {
+ intArrayStack[++intArrayPtr] = positions;
+ } catch (IndexOutOfBoundsException e) {
+ //intPtr is correct
+ int oldStackLength = intArrayStack.length;
+ int oldStack[][] = intArrayStack;
+ intArrayStack = new int[oldStackLength + StackIncrement][];
+ System.arraycopy(oldStack, 0, intArrayStack, 0, oldStackLength);
+ intArrayStack[intArrayPtr] = positions;
+ }
+ }
+
+ protected void resetModifiers() {
+ super.resetModifiers();
+ declarationSourceStart = -1;
+ }
+
+ /*
+ * Syntax error was detected. Will attempt to perform some recovery action in order
+ * to resume to the regular parse loop.
+ */
+ protected boolean resumeOnSyntaxError() {
+ return false;
+ }
+
+ /*
+ * Answer a char array representation of the type name formatted like:
+ * - type name + dimensions
+ * Example:
+ * "A[][]".toCharArray()
+ * "java.lang.String".toCharArray()
+ */
+ private char[] returnTypeName(TypeReference type) {
+ int dimension = type.dimensions();
+ if (dimension != 0) {
+ char[] dimensionsArray = new char[dimension * 2];
+ for (int i = 0; i < dimension; i++) {
+ dimensionsArray[i * 2] = '[';
+ dimensionsArray[(i * 2) + 1] = ']';
+ }
+ return CharOperation.concat(
+ CharOperation.concatWith(type.getTypeName(), '.'),
+ dimensionsArray);
+ }
+ return CharOperation.concatWith(type.getTypeName(), '.');
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("intArrayPtr = " + intArrayPtr + "\n");
+ buffer.append(super.toString());
+ return buffer.toString();
+ }
+
+ /**
+ * INTERNAL USE ONLY
+ */
+ protected TypeReference typeReference(
+ int dim,
+ int localIdentifierPtr,
+ int localIdentifierLengthPtr) {
+ /* build a Reference on a variable that may be qualified or not
+ * This variable is a type reference and dim will be its dimensions.
+ * We don't have any side effect on the stacks' pointers.
+ */
+
+ int length;
+ TypeReference ref;
+ if ((length = identifierLengthStack[localIdentifierLengthPtr]) == 1) {
+ // single variable reference
+ if (dim == 0) {
+ ref =
+ new SingleTypeReference(
+ identifierStack[localIdentifierPtr],
+ identifierPositionStack[localIdentifierPtr--]);
+ } else {
+ ref =
+ new ArrayTypeReference(
+ identifierStack[localIdentifierPtr],
+ dim,
+ identifierPositionStack[localIdentifierPtr--]);
+ }
+ } else {
+ if (length < 0) { //flag for precompiled type reference on base types
+ ref = TypeReference.baseTypeReference(-length, dim);
+ ref.sourceEnd = intStack[localIntPtr--];
+ ref.sourceStart = intStack[localIntPtr--];
+ } else { //Qualified variable reference
+ char[][] tokens = new char[length][];
+ localIdentifierPtr -= length;
+ long[] positions = new long[length];
+ System.arraycopy(identifierStack, localIdentifierPtr + 1, tokens, 0, length);
+ System.arraycopy(
+ identifierPositionStack,
+ localIdentifierPtr + 1,
+ positions,
+ 0,
+ length);
+ if (dim == 0)
+ ref = new QualifiedTypeReference(tokens, positions);
+ else
+ ref = new ArrayQualifiedTypeReference(tokens, dim, positions);
+ }
+ };
+ return ref;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/HierarchyResolver.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/HierarchyResolver.java
new file mode 100644
index 0000000000..4fc3cdde00
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/HierarchyResolver.java
@@ -0,0 +1,398 @@
+package org.eclipse.jdt.internal.compiler;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/**
+ * This is the public entry point to resolve type hierarchies.
+ *
+ * When requesting additional types from the name environment, the resolver
+ * accepts all forms (binary, source & compilation unit) for additional types.
+ *
+ * Side notes: Binary types already know their resolved supertypes so this
+ * only makes sense for source types. Even though the compiler finds all binary
+ * types to complete the hierarchy of a given source type, is there any reason
+ * why the requestor should be informed that binary type X subclasses Y &
+ * implements I & J?
+ */
+
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.parser.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class HierarchyResolver implements ITypeRequestor {
+ IHierarchyRequestor requestor;
+ LookupEnvironment lookupEnvironment;
+
+ private int typeIndex;
+ private IGenericType[] typeModels;
+ private ReferenceBinding[] typeBindings;
+ public HierarchyResolver(
+ INameEnvironment nameEnvironment,
+ IErrorHandlingPolicy policy,
+ ConfigurableOption[] settings,
+ IHierarchyRequestor requestor,
+ IProblemFactory problemFactory) {
+
+ // create a problem handler given a handling policy
+ CompilerOptions options =
+ settings == null ? new CompilerOptions() : new CompilerOptions(settings);
+ ProblemReporter problemReporter =
+ new ProblemReporter(policy, options, problemFactory);
+ this.lookupEnvironment =
+ new LookupEnvironment(this, options, problemReporter, nameEnvironment);
+ this.requestor = requestor;
+
+ this.typeIndex = -1;
+ this.typeModels = new IGenericType[5];
+ this.typeBindings = new ReferenceBinding[5];
+ }
+
+ public HierarchyResolver(
+ INameEnvironment nameEnvironment,
+ IHierarchyRequestor requestor,
+ IProblemFactory problemFactory) {
+ this(
+ nameEnvironment,
+ DefaultErrorHandlingPolicies.exitAfterAllProblems(),
+ null,
+ requestor,
+ problemFactory);
+ }
+
+ /**
+ * Add an additional binary type
+ */
+
+ public void accept(IBinaryType binaryType, PackageBinding packageBinding) {
+ BinaryTypeBinding typeBinding =
+ lookupEnvironment.createBinaryTypeFrom(binaryType, packageBinding);
+ remember(binaryType, typeBinding);
+ }
+
+ /**
+ * Add an additional compilation unit.
+ */
+
+ public void accept(ICompilationUnit sourceUnit) {
+ System.out.println(
+ "Cannot accept compilation units inside the HierarchyResolver.");
+ lookupEnvironment.problemReporter.abortDueToInternalError(
+ new StringBuffer("Cannot accept the compilation unit: ")
+ .append(sourceUnit.getFileName())
+ .toString());
+ }
+
+ /**
+ * Add an additional source type
+ */
+
+ public void accept(ISourceType sourceType, PackageBinding packageBinding) {
+ CompilationResult result =
+ new CompilationResult(sourceType.getFileName(), 1, 1);
+ CompilationUnitDeclaration unit =
+ SourceTypeConverter.buildCompilationUnit(
+ sourceType,
+ false,
+ true,
+ lookupEnvironment.problemReporter,
+ result);
+
+ if (unit != null) {
+ lookupEnvironment.buildTypeBindings(unit);
+ rememberWithMemberTypes(sourceType, unit.types[0].binding);
+
+ lookupEnvironment.completeTypeBindings(unit, false);
+ }
+ }
+
+ private void remember(
+ IGenericType suppliedType,
+ ReferenceBinding typeBinding) {
+ if (typeBinding == null)
+ return;
+
+ if (++typeIndex == typeModels.length) {
+ System.arraycopy(
+ typeModels,
+ 0,
+ typeModels = new IGenericType[typeIndex * 2],
+ 0,
+ typeIndex);
+ System.arraycopy(
+ typeBindings,
+ 0,
+ typeBindings = new ReferenceBinding[typeIndex * 2],
+ 0,
+ typeIndex);
+ }
+ typeModels[typeIndex] = suppliedType;
+ typeBindings[typeIndex] = typeBinding;
+ }
+
+ private void rememberWithMemberTypes(
+ TypeDeclaration typeDeclaration,
+ HierarchyType enclosingType,
+ ICompilationUnit unit) {
+
+ if (typeDeclaration.binding == null)
+ return;
+
+ HierarchyType hierarchyType =
+ new HierarchyType(
+ enclosingType,
+ !typeDeclaration.isInterface(),
+ typeDeclaration.name,
+ typeDeclaration.binding.modifiers,
+ unit);
+ remember(hierarchyType, typeDeclaration.binding);
+
+ // propagate into member types
+ if (typeDeclaration.memberTypes == null)
+ return;
+ MemberTypeDeclaration[] memberTypes = typeDeclaration.memberTypes;
+ for (int i = 0, max = memberTypes.length; i < max; i++) {
+ rememberWithMemberTypes(memberTypes[i], hierarchyType, unit);
+ }
+ }
+
+ private void rememberWithMemberTypes(
+ ISourceType suppliedType,
+ ReferenceBinding typeBinding) {
+ if (typeBinding == null)
+ return;
+
+ remember(suppliedType, typeBinding);
+
+ ISourceType[] memberTypes = suppliedType.getMemberTypes();
+ if (memberTypes == null)
+ return;
+ for (int m = memberTypes.length; --m >= 0;) {
+ ISourceType memberType = memberTypes[m];
+ rememberWithMemberTypes(
+ memberType,
+ typeBinding.getMemberType(memberType.getName()));
+ }
+ }
+
+ private void reportHierarchy() {
+ // ensure each binary type knows its supertypes before reporting the hierarchy
+ int problemLength = typeIndex + 1;
+ boolean[] typesWithProblem = new boolean[problemLength];
+ for (int current = 0;
+ current <= typeIndex;
+ current++) { // typeIndex may continue to grow
+ ReferenceBinding typeBinding = typeBindings[current];
+ if (typeBinding.isBinaryBinding()) {
+ // fault in its hierarchy...
+ try {
+ typeBinding.superclass();
+ typeBinding.superInterfaces();
+ } catch (AbortCompilation e) {
+ if (current >= problemLength) {
+ System.arraycopy(
+ typesWithProblem,
+ 0,
+ typesWithProblem = new boolean[current + 1],
+ 0,
+ problemLength);
+ problemLength = current + 1;
+ }
+ typesWithProblem[current] = true;
+ }
+ }
+ }
+
+ for (int current = typeIndex; current >= 0; current--) {
+ IGenericType suppliedType = typeModels[current];
+ ReferenceBinding typeBinding = typeBindings[current];
+ if (current < problemLength && typesWithProblem[current])
+ continue;
+
+ ReferenceBinding superBinding = typeBinding.superclass();
+ IGenericType superclass = null;
+ if (superBinding != null) {
+ for (int t = typeIndex; t >= 0; t--) {
+ if (typeBindings[t] == superBinding) {
+ superclass = typeModels[t];
+ break;
+ }
+ }
+ }
+
+ ReferenceBinding[] interfaceBindings = typeBinding.superInterfaces();
+ int length = interfaceBindings.length;
+ IGenericType[] superinterfaces = new IGenericType[length];
+ next : for (int i = 0; i < length; i++) {
+ ReferenceBinding interfaceBinding = interfaceBindings[i];
+ for (int t = typeIndex; t >= 0; t--) {
+ if (typeBindings[t] == interfaceBinding) {
+ superinterfaces[i] = typeModels[t];
+ continue next;
+ }
+ }
+ }
+ if (typeBinding.isInterface()) { // do not connect interfaces to Object
+ superclass = null;
+ }
+ requestor.connect(suppliedType, superclass, superinterfaces);
+ }
+ }
+
+ private void reset() {
+ lookupEnvironment.reset();
+
+ this.typeIndex = -1;
+ this.typeModels = new IGenericType[5];
+ this.typeBindings = new ReferenceBinding[5];
+ }
+
+ /**
+ * Resolve the supertypes for the supplied source types.
+ * Inform the requestor of the resolved supertypes for each
+ * supplied source type using:
+ * connect(ISourceType suppliedType, IGenericType superclass, IGenericType[] superinterfaces)
+ *
+ * Also inform the requestor of the supertypes of each
+ * additional requested super type which is also a source type
+ * instead of a binary type.
+ */
+
+ public void resolve(IGenericType[] suppliedTypes) {
+ resolve(suppliedTypes, null);
+ }
+
+ /**
+ * Resolve the supertypes for the supplied source types.
+ * Inform the requestor of the resolved supertypes for each
+ * supplied source type using:
+ * connect(ISourceType suppliedType, IGenericType superclass, IGenericType[] superinterfaces)
+ *
+ * Also inform the requestor of the supertypes of each
+ * additional requested super type which is also a source type
+ * instead of a binary type.
+ */
+
+ public void resolve(
+ IGenericType[] suppliedTypes,
+ ICompilationUnit[] sourceUnits) {
+ try {
+ int suppliedLength = suppliedTypes == null ? 0 : suppliedTypes.length;
+ int sourceLength = sourceUnits == null ? 0 : sourceUnits.length;
+ CompilationUnitDeclaration[] units =
+ new CompilationUnitDeclaration[suppliedLength + sourceLength];
+ int count = -1;
+ for (int i = 0; i < suppliedLength; i++) {
+ if (suppliedTypes[i].isBinaryType()) {
+ IBinaryType binaryType = (IBinaryType) suppliedTypes[i];
+ suppliedTypes[i] = null; // no longer needed pass this point
+ try {
+ remember(binaryType, lookupEnvironment.cacheBinaryType(binaryType, false));
+ } catch (AbortCompilation e) {
+ // classpath problem for this type: ignore
+ }
+ } else {
+ // must start with the top level type
+ ISourceType topLevelType = (ISourceType) suppliedTypes[i];
+ suppliedTypes[i] = null; // no longer needed pass this point
+ while (topLevelType.getEnclosingType() != null)
+ topLevelType = topLevelType.getEnclosingType();
+ CompilationResult result =
+ new CompilationResult(topLevelType.getFileName(), i, suppliedLength);
+ units[++count] =
+ SourceTypeConverter.buildCompilationUnit(
+ topLevelType,
+ false,
+ true,
+ lookupEnvironment.problemReporter,
+ result);
+
+ if (units[count] == null) {
+ count--;
+ } else {
+ try {
+ lookupEnvironment.buildTypeBindings(units[count]);
+ rememberWithMemberTypes(topLevelType, units[count].types[0].binding);
+ } catch (AbortCompilation e) {
+ // classpath problem for this type: ignore
+ }
+ }
+ }
+ }
+ for (int i = 0; i < sourceLength; i++) {
+ ICompilationUnit sourceUnit = sourceUnits[i];
+ sourceUnits[i] = null; // no longer needed pass this point
+ CompilationResult unitResult =
+ new CompilationResult(
+ sourceUnit,
+ suppliedLength + i,
+ suppliedLength + sourceLength);
+ Parser parser = new Parser(lookupEnvironment.problemReporter);
+ CompilationUnitDeclaration parsedUnit =
+ parser.dietParse(sourceUnit, unitResult);
+ if (parsedUnit != null) {
+ units[++count] = parsedUnit;
+ lookupEnvironment.buildTypeBindings(units[count]);
+ int typeCount = parsedUnit.types == null ? 0 : parsedUnit.types.length;
+ for (int j = 0; j < typeCount; j++) {
+ rememberWithMemberTypes(parsedUnit.types[j], null, sourceUnit);
+ }
+ }
+ }
+ for (int i = 0; i <= count; i++)
+ lookupEnvironment.completeTypeBindings(units[i], false);
+
+ reportHierarchy();
+ } catch (AbortCompilation e) { // ignore this exception for now since it typically means we cannot find java.lang.Object
+ } finally {
+ reset();
+ }
+ }
+
+ /**
+ * Resolve the supertypes for the supplied source type.
+ * Inform the requestor of the resolved supertypes using:
+ * connect(ISourceType suppliedType, IGenericType superclass, IGenericType[] superinterfaces)
+ */
+
+ public void resolve(IGenericType suppliedType) {
+ try {
+ if (suppliedType.isBinaryType()) {
+ remember(
+ suppliedType,
+ lookupEnvironment.cacheBinaryType((IBinaryType) suppliedType));
+ } else {
+ // must start with the top level type
+ ISourceType topLevelType = (ISourceType) suppliedType;
+ while (topLevelType.getEnclosingType() != null)
+ topLevelType = topLevelType.getEnclosingType();
+ CompilationResult result =
+ new CompilationResult(topLevelType.getFileName(), 1, 1);
+ CompilationUnitDeclaration unit =
+ SourceTypeConverter.buildCompilationUnit(
+ topLevelType,
+ false,
+ true,
+ lookupEnvironment.problemReporter,
+ result);
+
+ if (unit != null) {
+ lookupEnvironment.buildTypeBindings(unit);
+ rememberWithMemberTypes(topLevelType, unit.types[0].binding);
+
+ lookupEnvironment.completeTypeBindings(unit, false);
+ }
+ }
+ reportHierarchy();
+ } catch (AbortCompilation e) { // ignore this exception for now since it typically means we cannot find java.lang.Object
+ } finally {
+ reset();
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/HierarchyType.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/HierarchyType.java
new file mode 100644
index 0000000000..9b2137994b
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/HierarchyType.java
@@ -0,0 +1,79 @@
+package org.eclipse.jdt.internal.compiler;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.jdt.internal.compiler.env.*;
+
+/**
+ *
+ * Partial implementation of an IGenericType used to
+ * answer hierarchies.
+ */
+public class HierarchyType implements IGenericType {
+
+ public HierarchyType enclosingType;
+ public boolean isClass;
+ public char[] name;
+ public int modifiers;
+ public ICompilationUnit originatingUnit;
+ public HierarchyType(
+ HierarchyType enclosingType,
+ boolean isClass,
+ char[] name,
+ int modifiers,
+ ICompilationUnit originatingUnit) {
+ this.enclosingType = enclosingType;
+ this.isClass = isClass;
+ this.name = name;
+ this.modifiers = modifiers;
+ this.originatingUnit = originatingUnit;
+ }
+
+ /**
+ * Answer the file name which defines the type.
+ *
+ * The path part (optional) must be separated from the actual
+ * file proper name by a java.io.File.separator.
+ *
+ * The proper file name includes the suffix extension (e.g. ".java")
+ *
+ * e.g. "c:/com/ibm/compiler/java/api/Compiler.java"
+ */
+ public char[] getFileName() {
+ return originatingUnit.getFileName();
+ }
+
+ /**
+ * Answer an int whose bits are set according the access constants
+ * defined by the VM spec.
+ */
+ public int getModifiers() {
+ return this.modifiers;
+ }
+
+ /**
+ * Answer whether the receiver contains the resolved binary form
+ * or the unresolved source form of the type.
+ */
+ public boolean isBinaryType() {
+ return false;
+ }
+
+ /**
+ * isClass method comment.
+ */
+ public boolean isClass() {
+ return this.isClass;
+ }
+
+ /**
+ * isInterface method comment.
+ */
+ public boolean isInterface() {
+ return !isClass;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IAbstractSyntaxTreeVisitor.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IAbstractSyntaxTreeVisitor.java
new file mode 100644
index 0000000000..2d5d6c07bf
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IAbstractSyntaxTreeVisitor.java
@@ -0,0 +1,193 @@
+package org.eclipse.jdt.internal.compiler;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+/**
+ * A visitor interface for interating through the parse tree.
+ */
+public interface IAbstractSyntaxTreeVisitor {
+ void acceptProblem(IProblem problem);
+ void endVisit(AllocationExpression allocationExpression, BlockScope scope);
+ void endVisit(AND_AND_Expression and_and_Expression, BlockScope scope);
+ void endVisit(
+ AnonymousLocalTypeDeclaration anonymousTypeDeclaration,
+ BlockScope scope);
+ void endVisit(Argument argument, BlockScope scope);
+ void endVisit(
+ ArrayAllocationExpression arrayAllocationExpression,
+ BlockScope scope);
+ void endVisit(ArrayInitializer arrayInitializer, BlockScope scope);
+ void endVisit(
+ ArrayQualifiedTypeReference arrayQualifiedTypeReference,
+ BlockScope scope);
+ void endVisit(
+ ArrayQualifiedTypeReference arrayQualifiedTypeReference,
+ ClassScope scope);
+ void endVisit(ArrayReference arrayReference, BlockScope scope);
+ void endVisit(ArrayTypeReference arrayTypeReference, BlockScope scope);
+ void endVisit(ArrayTypeReference arrayTypeReference, ClassScope scope);
+ void endVisit(Assignment assignment, BlockScope scope);
+ void endVisit(BinaryExpression binaryExpression, BlockScope scope);
+ void endVisit(Block block, BlockScope scope);
+ void endVisit(Break breakStatement, BlockScope scope);
+ void endVisit(Case caseStatement, BlockScope scope);
+ void endVisit(CastExpression castExpression, BlockScope scope);
+ void endVisit(CharLiteral charLiteral, BlockScope scope);
+ void endVisit(ClassLiteralAccess classLiteral, BlockScope scope);
+ void endVisit(Clinit clinit, ClassScope scope);
+ void endVisit(
+ CompilationUnitDeclaration compilationUnitDeclaration,
+ CompilationUnitScope scope);
+ void endVisit(CompoundAssignment compoundAssignment, BlockScope scope);
+ void endVisit(ConditionalExpression conditionalExpression, BlockScope scope);
+ void endVisit(ConstructorDeclaration constructorDeclaration, ClassScope scope);
+ void endVisit(Continue continueStatement, BlockScope scope);
+ void endVisit(DefaultCase defaultCaseStatement, BlockScope scope);
+ void endVisit(DoStatement doStatement, BlockScope scope);
+ void endVisit(DoubleLiteral doubleLiteral, BlockScope scope);
+ void endVisit(EqualExpression equalExpression, BlockScope scope);
+ void endVisit(ExplicitConstructorCall explicitConstructor, BlockScope scope);
+ void endVisit(ExtendedStringLiteral extendedStringLiteral, BlockScope scope);
+ void endVisit(FalseLiteral falseLiteral, BlockScope scope);
+ void endVisit(FieldDeclaration fieldDeclaration, MethodScope scope);
+ void endVisit(FieldReference fieldReference, BlockScope scope);
+ void endVisit(FloatLiteral floatLiteral, BlockScope scope);
+ void endVisit(ForStatement forStatement, BlockScope scope);
+ void endVisit(IfStatement ifStatement, BlockScope scope);
+ void endVisit(ImportReference importRef, CompilationUnitScope scope);
+ void endVisit(Initializer initializer, MethodScope scope);
+ void endVisit(InstanceOfExpression instanceOfExpression, BlockScope scope);
+ void endVisit(IntLiteral intLiteral, BlockScope scope);
+ void endVisit(LabeledStatement labeledStatement, BlockScope scope);
+ void endVisit(LocalDeclaration localDeclaration, BlockScope scope);
+ void endVisit(LocalTypeDeclaration localTypeDeclaration, MethodScope scope);
+ void endVisit(LongLiteral longLiteral, BlockScope scope);
+ void endVisit(MemberTypeDeclaration memberTypeDeclaration, ClassScope scope);
+ void endVisit(MessageSend messageSend, BlockScope scope);
+ void endVisit(MethodDeclaration methodDeclaration, ClassScope scope);
+ void endVisit(NullLiteral nullLiteral, BlockScope scope);
+ void endVisit(OR_OR_Expression or_or_Expression, BlockScope scope);
+ void endVisit(PostfixExpression postfixExpression, BlockScope scope);
+ void endVisit(PrefixExpression prefixExpression, BlockScope scope);
+ void endVisit(
+ QualifiedAllocationExpression qualifiedAllocationExpression,
+ BlockScope scope);
+ void endVisit(QualifiedNameReference qualifiedNameReference, BlockScope scope);
+ void endVisit(
+ QualifiedSuperReference qualifiedSuperReference,
+ BlockScope scope);
+ void endVisit(QualifiedThisReference qualifiedThisReference, BlockScope scope);
+ void endVisit(QualifiedTypeReference qualifiedTypeReference, BlockScope scope);
+ void endVisit(QualifiedTypeReference qualifiedTypeReference, ClassScope scope);
+ void endVisit(ReturnStatement returnStatement, BlockScope scope);
+ void endVisit(SingleNameReference singleNameReference, BlockScope scope);
+ void endVisit(SingleTypeReference singleTypeReference, BlockScope scope);
+ void endVisit(SingleTypeReference singleTypeReference, ClassScope scope);
+ void endVisit(StringLiteral stringLiteral, BlockScope scope);
+ void endVisit(SuperReference superReference, BlockScope scope);
+ void endVisit(SwitchStatement switchStatement, BlockScope scope);
+ void endVisit(SynchronizedStatement synchronizedStatement, BlockScope scope);
+ void endVisit(ThisReference thisReference, BlockScope scope);
+ void endVisit(ThrowStatement throwStatement, BlockScope scope);
+ void endVisit(TrueLiteral trueLiteral, BlockScope scope);
+ void endVisit(TryStatement tryStatement, BlockScope scope);
+ void endVisit(TypeDeclaration typeDeclaration, BlockScope scope);
+ void endVisit(TypeDeclaration typeDeclaration, ClassScope scope);
+ void endVisit(TypeDeclaration typeDeclaration, CompilationUnitScope scope);
+ void endVisit(UnaryExpression unaryExpression, BlockScope scope);
+ void endVisit(WhileStatement whileStatement, BlockScope scope);
+ boolean visit(AllocationExpression allocationExpression, BlockScope scope);
+ boolean visit(AND_AND_Expression and_and_Expression, BlockScope scope);
+ boolean visit(
+ AnonymousLocalTypeDeclaration anonymousTypeDeclaration,
+ BlockScope scope);
+ boolean visit(Argument argument, BlockScope scope);
+ boolean visit(
+ ArrayAllocationExpression arrayAllocationExpression,
+ BlockScope scope);
+ boolean visit(ArrayInitializer arrayInitializer, BlockScope scope);
+ boolean visit(
+ ArrayQualifiedTypeReference arrayQualifiedTypeReference,
+ BlockScope scope);
+ boolean visit(
+ ArrayQualifiedTypeReference arrayQualifiedTypeReference,
+ ClassScope scope);
+ boolean visit(ArrayReference arrayReference, BlockScope scope);
+ boolean visit(ArrayTypeReference arrayTypeReference, BlockScope scope);
+ boolean visit(ArrayTypeReference arrayTypeReference, ClassScope scope);
+ boolean visit(Assignment assignment, BlockScope scope);
+ boolean visit(BinaryExpression binaryExpression, BlockScope scope);
+ boolean visit(Block block, BlockScope scope);
+ boolean visit(Break breakStatement, BlockScope scope);
+ boolean visit(Case caseStatement, BlockScope scope);
+ boolean visit(CastExpression castExpression, BlockScope scope);
+ boolean visit(CharLiteral charLiteral, BlockScope scope);
+ boolean visit(ClassLiteralAccess classLiteral, BlockScope scope);
+ boolean visit(Clinit clinit, ClassScope scope);
+ boolean visit(
+ CompilationUnitDeclaration compilationUnitDeclaration,
+ CompilationUnitScope scope);
+ boolean visit(CompoundAssignment compoundAssignment, BlockScope scope);
+ boolean visit(ConditionalExpression conditionalExpression, BlockScope scope);
+ boolean visit(ConstructorDeclaration constructorDeclaration, ClassScope scope);
+ boolean visit(Continue continueStatement, BlockScope scope);
+ boolean visit(DefaultCase defaultCaseStatement, BlockScope scope);
+ boolean visit(DoStatement doStatement, BlockScope scope);
+ boolean visit(DoubleLiteral doubleLiteral, BlockScope scope);
+ boolean visit(EqualExpression equalExpression, BlockScope scope);
+ boolean visit(ExplicitConstructorCall explicitConstructor, BlockScope scope);
+ boolean visit(ExtendedStringLiteral extendedStringLiteral, BlockScope scope);
+ boolean visit(FalseLiteral falseLiteral, BlockScope scope);
+ boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope);
+ boolean visit(FieldReference fieldReference, BlockScope scope);
+ boolean visit(FloatLiteral floatLiteral, BlockScope scope);
+ boolean visit(ForStatement forStatement, BlockScope scope);
+ boolean visit(IfStatement ifStatement, BlockScope scope);
+ boolean visit(ImportReference importRef, CompilationUnitScope scope);
+ boolean visit(Initializer initializer, MethodScope scope);
+ boolean visit(InstanceOfExpression instanceOfExpression, BlockScope scope);
+ boolean visit(IntLiteral intLiteral, BlockScope scope);
+ boolean visit(LabeledStatement labeledStatement, BlockScope scope);
+ boolean visit(LocalDeclaration localDeclaration, BlockScope scope);
+ boolean visit(LocalTypeDeclaration localTypeDeclaration, MethodScope scope);
+ boolean visit(LongLiteral longLiteral, BlockScope scope);
+ boolean visit(MemberTypeDeclaration memberTypeDeclaration, ClassScope scope);
+ boolean visit(MessageSend messageSend, BlockScope scope);
+ boolean visit(MethodDeclaration methodDeclaration, ClassScope scope);
+ boolean visit(NullLiteral nullLiteral, BlockScope scope);
+ boolean visit(OR_OR_Expression or_or_Expression, BlockScope scope);
+ boolean visit(PostfixExpression postfixExpression, BlockScope scope);
+ boolean visit(PrefixExpression prefixExpression, BlockScope scope);
+ boolean visit(
+ QualifiedAllocationExpression qualifiedAllocationExpression,
+ BlockScope scope);
+ boolean visit(QualifiedNameReference qualifiedNameReference, BlockScope scope);
+ boolean visit(
+ QualifiedSuperReference qualifiedSuperReference,
+ BlockScope scope);
+ boolean visit(QualifiedThisReference qualifiedThisReference, BlockScope scope);
+ boolean visit(QualifiedTypeReference qualifiedTypeReference, BlockScope scope);
+ boolean visit(QualifiedTypeReference qualifiedTypeReference, ClassScope scope);
+ boolean visit(ReturnStatement returnStatement, BlockScope scope);
+ boolean visit(SingleNameReference singleNameReference, BlockScope scope);
+ boolean visit(SingleTypeReference singleTypeReference, BlockScope scope);
+ boolean visit(SingleTypeReference singleTypeReference, ClassScope scope);
+ boolean visit(StringLiteral stringLiteral, BlockScope scope);
+ boolean visit(SuperReference superReference, BlockScope scope);
+ boolean visit(SwitchStatement switchStatement, BlockScope scope);
+ boolean visit(SynchronizedStatement synchronizedStatement, BlockScope scope);
+ boolean visit(ThisReference thisReference, BlockScope scope);
+ boolean visit(ThrowStatement throwStatement, BlockScope scope);
+ boolean visit(TrueLiteral trueLiteral, BlockScope scope);
+ boolean visit(TryStatement tryStatement, BlockScope scope);
+ boolean visit(TypeDeclaration typeDeclaration, BlockScope scope);
+ boolean visit(TypeDeclaration typeDeclaration, ClassScope scope);
+ boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope scope);
+ boolean visit(UnaryExpression unaryExpression, BlockScope scope);
+ boolean visit(WhileStatement whileStatement, BlockScope scope);
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ICompilerRequestor.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ICompilerRequestor.java
new file mode 100644
index 0000000000..f5475b15d7
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ICompilerRequestor.java
@@ -0,0 +1,8 @@
+package org.eclipse.jdt.internal.compiler;
+
+public interface ICompilerRequestor {
+ /**
+ * Accept a compilation result.
+ */
+ public void acceptResult(CompilationResult result);
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IDocumentElementRequestor.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IDocumentElementRequestor.java
new file mode 100644
index 0000000000..37ac0fd276
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IDocumentElementRequestor.java
@@ -0,0 +1,394 @@
+package org.eclipse.jdt.internal.compiler;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Part of the source element parser responsible for building the output.
+ * It gets notified of structural information as they are detected, relying
+ * on the requestor to assemble them together, based on the notifications it got.
+ *
+ * The structural investigation includes:
+ * - package statement
+ * - import statements
+ * - top-level types: package member, member types (member types of member types...)
+ * - fields
+ * - methods
+ *
+ * If reference information is requested, then all source constructs are
+ * investigated and type, field & method references are provided as well.
+ *
+ * Any (parsing) problem encountered is also provided.
+ *
+ * All positions are relative to the exact source fed to the parser.
+ *
+ * Elements which are complex are notified in two steps:
+ * - enter<Element> : once the element header has been identified
+ * - exit<Element> : once the element has been fully consumed
+ *
+ * other simpler elements (package, import) are read all at once:
+ * - accept<Element>
+ */
+
+import org.eclipse.jdt.internal.compiler.IProblem;
+
+public interface IDocumentElementRequestor {
+ /**
+ * @param declarationStart - a source position corresponding to the start of the package
+ * declaration
+ * @param declarationEnd - a source position corresponding to the end of the package
+ * declaration
+ * @param javaDocPositions - answer back an array of sourceStart/sourceEnd
+ * positions of the available JavaDoc comments. The array is a flattened
+ * structure: 2*n entries with consecutives start and end positions.
+ * If no JavaDoc is available, then null is answered instead of an empty array.
+ * e.g. { 10, 20, 25, 45 } --> javadoc1 from 10 to 20, javadoc2 from 25 to 45
+ * The array is equals to null if there are no javadoc comments
+ * @param name - the name of the package
+ * @param nameStartPosition - a source position corresponding to the first character of the
+ * name
+ * @param onDemand - a boolean equals to true if the import is an import on demand
+ */
+ void acceptImport(
+ int declarationStart,
+ int declarationEnd,
+ int[] javaDocPositions,
+ char[] name,
+ int nameStartPosition,
+ boolean onDemand);
+ /**
+ * @param declarationStart - a source position corresponding to the start of the package
+ * declaration
+ * @param declarationEnd - a source position corresponding to the end of the package
+ * declaration
+ * @param javaDocPositions - answer back an array of sourceStart/sourceEnd
+ * positions of the available JavaDoc comments. The array is a flattened
+ * structure: 2*n entries with consecutives start and end positions.
+ * If no JavaDoc is available, then null is answered instead of an empty array.
+ * e.g. { 10, 20, 25, 45 } --> javadoc1 from 10 to 20, javadoc2 from 25 to 45
+ * The array is equals to null if there are no javadoc comments
+ * @param modifiers - the modifiers for this initializer
+ * @param modifiersStart - a source position corresponding to the start
+ * of the textual modifiers, is < 0 if there are no textual modifiers
+ * @param bodyStart - the position of the '{'
+ * @param bodyEnd - the position of the '}'
+ */
+ void acceptInitializer(
+ int declarationStart,
+ int declarationEnd,
+ int[] javaDocPositions,
+ int modifiers,
+ int modifiersStart,
+ int bodyStart,
+ int bodyEnd);
+ /*
+ * Table of line separator position. This table is passed once at the end
+ * of the parse action, so as to allow computation of normalized ranges.
+ *
+ * A line separator might corresponds to several characters in the source,
+ *
+ */
+ void acceptLineSeparatorPositions(int[] positions);
+ /**
+ * @param declarationStart - a source position corresponding to the start of the package
+ * declaration
+ * @param declarationEnd - a source position corresponding to the end of the package
+ * declaration
+ * @param javaDocPositions - answer back an array of sourceStart/sourceEnd
+ * positions of the available JavaDoc comments. The array is a flattened
+ * structure: 2*n entries with consecutives start and end positions.
+ * If no JavaDoc is available, then null is answered instead of an empty array.
+ * e.g. { 10, 20, 25, 45 } --> javadoc1 from 10 to 20, javadoc2 from 25 to 45
+ * The array is equals to null if there are no javadoc comments
+ * @param name - the name of the package
+ * @param nameStartPosition - a source position corresponding to the first character of the
+ * name
+ */
+ void acceptPackage(
+ int declarationStart,
+ int declarationEnd,
+ int[] javaDocPositions,
+ char[] name,
+ int nameStartPosition);
+ /**
+ * @param problem - Used to report a problem while running the JDOM
+ */
+ void acceptProblem(IProblem problem);
+ /**
+ * @param declarationStart - a source position corresponding to the start
+ * of this class.
+ * @param javaDocPositions - answer back an array of sourceStart/sourceEnd
+ * positions of the available JavaDoc comments. The array is a flattened
+ * structure: 2*n entries with consecutives start and end positions.
+ * If no JavaDoc is available, then null is answered instead of an empty array.
+ * e.g. { 10, 20, 25, 45 } --> javadoc1 from 10 to 20, javadoc2 from 25 to 45
+ * The array is equals to null if there are no javadoc comments
+ * @param modifiers - the modifiers for this class
+ * @param modifiersStart - a source position corresponding to the start
+ * of the textual modifiers, is < 0 if there are no textual modifiers
+ * @param classStart - a source position corresponding to the start
+ * of the keyword 'class'
+ * @param name - the name of the class
+ * @param nameStart - a source position corresponding to the start of the name
+ * @param nameEnd - a source position corresponding to the end of the name
+ * @param superclass - the name of the superclass
+ * @param superclassStart - a source position corresponding to the start
+ * of the superclass name
+ * @param superclassEnd - a source position corresponding to the end of the
+ * superclass name
+ * @param superinterfaces - the name of the superinterfaces
+ * @param superinterfaceStarts - an array of source positions corresponding
+ * to the start of their respective superinterface names
+ * @param superinterfaceEnds - an array of source positions corresponding
+ * to the end of their respective superinterface names
+ * @param bodyStart - a source position corresponding to the open bracket
+ * of the class body
+ */
+ void enterClass(
+ int declarationStart,
+ int[] javaDocPositions,
+ int modifiers,
+ int modifiersStart,
+ int classStart,
+ char[] name,
+ int nameStart,
+ int nameEnd,
+ char[] superclass,
+ int superclassStart,
+ int superclassEnd,
+ char[][] superinterfaces,
+ int[] superinterfaceStarts,
+ int[] superinterfaceEnds,
+ int bodyStart);
+ void enterCompilationUnit();
+ /**
+ * @param declarationStart - a source position corresponding to the first character
+ * of this constructor declaration
+ * @param javaDocPositions - answer back an array of sourceStart/sourceEnd
+ * positions of the available JavaDoc comments. The array is a flattened
+ * structure: 2*n entries with consecutives start and end positions.
+ * If no JavaDoc is available, then null is answered instead of an empty array.
+ * e.g. { 10, 20, 25, 45 } --> javadoc1 from 10 to 20, javadoc2 from 25 to 45
+ * The array is equals to null if there are no javadoc comments
+ * @param modifiers - the modifiers for this constructor converted to a flag
+ * @param modifiersStart - a source position corresponding to the first character of the
+ * textual modifiers
+ * @param name - the name of this constructor
+ * @param nameStart - a source position corresponding to the first character of the name
+ * @param nameEnd - a source position corresponding to the last character of the name
+ * @param parameterTypes - a list of parameter type names
+ * @param parameterTypeStarts - a list of source positions corresponding to the
+ * first character of each parameter type name
+ * @param parameterTypeEnds - a list of source positions corresponding to the
+ * last character of each parameter type name
+ * @param parameterNames - a list of the names of the parameters
+ * @param parametersEnd - a source position corresponding to the last character of the
+ * parameter list
+ * @param exceptionTypes - a list of the exception types
+ * @param exceptionTypeStarts - a list of source positions corresponding to the first
+ * character of the respective exception types
+ * @param exceptionTypeEnds - a list of source positions corresponding to the last
+ * character of the respective exception types
+ * @param bodyStart - a source position corresponding to the start of this
+ * constructor's body
+ */
+ void enterConstructor(
+ int declarationStart,
+ int[] javaDocPositions,
+ int modifiers,
+ int modifiersStart,
+ char[] name,
+ int nameStart,
+ int nameEnd,
+ char[][] parameterTypes,
+ int[] parameterTypeStarts,
+ int[] parameterTypeEnds,
+ char[][] parameterNames,
+ int[] parameterNameStarts,
+ int[] parameterNameEnds,
+ int parametersEnd,
+ char[][] exceptionTypes,
+ int[] exceptionTypeStarts,
+ int[] exceptionTypeEnds,
+ int bodyStart);
+ /**
+ * @param declarationStart - a source position corresponding to the first character
+ * of this field
+ * @param javaDocPositions - answer back an array of sourceStart/sourceEnd
+ * positions of the available JavaDoc comments. The array is a flattened
+ * structure: 2*n entries with consecutives start and end positions.
+ * If no JavaDoc is available, then null is answered instead of an empty array.
+ * e.g. { 10, 20, 25, 45 } --> javadoc1 from 10 to 20, javadoc2 from 25 to 45
+ * The array is equals to null if there are no javadoc comments
+ * @param modifiers - the modifiers for this field converted to a flag
+ * @param modifiersStart - a source position corresponding to the first character of the
+ * textual modifiers
+ * @param type - the name of the field type
+ * @param typeStart - a source position corresponding to the start of the fields type
+ * @param typeEnd - a source position corresponding to the end of the fields type
+ * @param typeDimensionCount - the array dimension indicated on the type, i.e. int[] v
+ * @param name - the name of this constructor
+ * @param nameStart - a source position corresponding to the first character of the name
+ * @param nameEnd - a source position corresponding to the last character of the name
+ * @param extendedTypeDimensionCount - the array dimension indicated on the variable,
+ * i.e. int v[]
+ * @param extendedTypeDimnesionEnd - a source position corresponding to the end of
+ * the extened type dimension. This position should be -1 in case there is no extended
+ * dimension for the type.
+ */
+ void enterField(
+ int declarationStart,
+ int[] javaDocPositions,
+ int modifiers,
+ int modifiersStart,
+ char[] type,
+ int typeStart,
+ int typeEnd,
+ int typeDimensionCount,
+ char[] name,
+ int nameStart,
+ int nameEnd,
+ int extendedTypeDimensionCount,
+ int extendedTypeDimensionEnd);
+ /**
+ * @param declarationStart - a source position corresponding to the start
+ * of this class.
+ * @param javaDocPositions - answer back an array of sourceStart/sourceEnd
+ * positions of the available JavaDoc comments. The array is a flattened
+ * structure: 2*n entries with consecutives start and end positions.
+ * If no JavaDoc is available, then null is answered instead of an empty array.
+ * e.g. { 10, 20, 25, 45 } --> javadoc1 from 10 to 20, javadoc2 from 25 to 45
+ * The array is equals to null if there are no javadoc comments
+ * @param modifiers - the modifiers for this class
+ * @param modifiersStart - a source position corresponding to the start
+ * of the textual modifiers, is < 0 if there are no textual modifiers
+ * @param interfaceStart - a source position corresponding to the start
+ * of the keyword 'interface'
+ * @param name - the name of the class
+ * @param nameStart - a source position corresponding to the start of the name
+ * @param nameEnd - a source position corresponding to the end of the name
+ * @param superinterfaces - the name of the superinterfaces
+ * @param superinterfaceStarts - an array of source positions corresponding
+ * to the start of their respective superinterface names
+ * @param superinterfaceEnds - an array of source positions corresponding
+ * to the end of their respective superinterface names
+ * @param bodyStart - a source position corresponding to the open bracket
+ * of the class body
+ */
+ void enterInterface(
+ int declarationStart,
+ int[] javaDocPositions,
+ int modifiers,
+ int modifiersStart,
+ int interfaceStart,
+ char[] name,
+ int nameStart,
+ int nameEnd,
+ char[][] superinterfaces,
+ int[] superinterfaceStarts,
+ int[] superinterfaceEnds,
+ int bodyStart);
+ /**
+ * @param declarationStart - a source position corresponding to the first character
+ * of this constructor declaration
+ * @param javaDocPositions - answer back an array of sourceStart/sourceEnd
+ * positions of the available JavaDoc comments. The array is a flattened
+ * structure: 2*n entries with consecutives start and end positions.
+ * If no JavaDoc is available, then null is answered instead of an empty array.
+ * e.g. { 10, 20, 25, 45 } --> javadoc1 from 10 to 20, javadoc2 from 25 to 45
+ * The array is equals to null if there are no javadoc comments
+ * @param modifiers - the modifiers for this constructor converted to a flag
+ * @param modifiersStart - a source position corresponding to the first character of the
+ * textual modifiers
+ * @param returnType - the name of the return type
+ * @param returnTypeStart - a source position corresponding to the first character
+ * of the return type
+ * @param returnTypeEnd - a source position corresponding to the last character
+ * of the return type
+ * @param returnTypeDimensionCount - the array dimension count as supplied on the
+ * return type, i.e. public int[] foo() {}
+ * @param name - the name of this constructor
+ * @param nameStart - a source position corresponding to the first character of the name
+ * @param nameEnd - a source position corresponding to the last character of the name
+ * @param parameterTypes - a list of parameter type names
+ * @param parameterTypeStarts - a list of source positions corresponding to the
+ * first character of each parameter type name
+ * @param parameterTypeEnds - a list of source positions corresponding to the
+ * last character of each parameter type name
+ * @param parameterNames - a list of the names of the parameters
+ * @param parametersEnd - a source position corresponding to the last character of the
+ * parameter list
+ * @extendedReturnTypeDimensionCount - the array dimension count as supplied on the
+ * end of the parameter list, i.e. public int foo()[] {}
+ * @extendedReturnTypeDimensionEnd - a source position corresponding to the last character
+ * of the extended return type dimension. This position should be -1 in case there is no extended
+ * dimension for the type.
+ * @param exceptionTypes - a list of the exception types
+ * @param exceptionTypeStarts - a list of source positions corresponding to the first
+ * character of the respective exception types
+ * @param exceptionTypeEnds - a list of source positions corresponding to the last
+ * character of the respective exception types
+ * @param bodyStart - a source position corresponding to the start of this
+ * method's body
+ */
+ void enterMethod(
+ int declarationStart,
+ int[] javaDocPositions,
+ int modifiers,
+ int modifiersStart,
+ char[] returnType,
+ int returnTypeStart,
+ int returnTypeEnd,
+ int returnTypeDimensionCount,
+ char[] name,
+ int nameStart,
+ int nameEnd,
+ char[][] parameterTypes,
+ int[] parameterTypeStarts,
+ int[] parameterTypeEnds,
+ char[][] parameterNames,
+ int[] parameterNameStarts,
+ int[] parameterNameEnds,
+ int parametersEnd,
+ int extendedReturnTypeDimensionCount,
+ int extendedReturnTypeDimensionEnd,
+ char[][] exceptionTypes,
+ int[] exceptionTypeStarts,
+ int[] exceptionTypeEnds,
+ int bodyStart);
+ /**
+ * @param bodyEnd - a source position corresponding to the closing bracket of the class
+ * @param declarationEnd - a source position corresponding to the end of the class
+ * declaration. This can include whitespace and comments following the closing bracket.
+ */
+ void exitClass(int bodyEnd, int declarationEnd);
+ /**
+ * @param declarationEnd - a source position corresponding to the end of the compilation unit
+ */
+ void exitCompilationUnit(int declarationEnd);
+ /**
+ * @param bodyEnd - a source position corresponding to the closing bracket of the method
+ * @param declarationEnd - a source position corresponding to the end of the method
+ * declaration. This can include whitespace and comments following the closing bracket.
+ */
+ void exitConstructor(int bodyEnd, int declarationEnd);
+ /**
+ * @param bodyEnd - a source position corresponding to the end of the field.
+ * @param declarationEnd - a source position corresponding to the end of the field.
+ * This can include whitespace and comments following the semi-colon.
+ */
+ void exitField(int bodyEnd, int declarationEnd);
+ /**
+ * @param bodyEnd - a source position corresponding to the closing bracket of the interface
+ * @param declarationEnd - a source position corresponding to the end of the interface
+ * declaration. This can include whitespace and comments following the closing bracket.
+ */
+ void exitInterface(int bodyEnd, int declarationEnd);
+ /**
+ * @param bodyEnd - a source position corresponding to the closing bracket of the method
+ * @param declarationEnd - a source position corresponding to the end of the method
+ * declaration. This can include whitespace and comments following the closing bracket.
+ */
+ void exitMethod(int bodyEnd, int declarationEnd);
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IErrorHandlingPolicy.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IErrorHandlingPolicy.java
new file mode 100644
index 0000000000..9cbd6e9c77
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IErrorHandlingPolicy.java
@@ -0,0 +1,6 @@
+package org.eclipse.jdt.internal.compiler;
+
+public interface IErrorHandlingPolicy {
+ boolean proceedOnErrors();
+ boolean stopOnFirstError();
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IHierarchyRequestor.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IHierarchyRequestor.java
new file mode 100644
index 0000000000..1716acebb7
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IHierarchyRequestor.java
@@ -0,0 +1,20 @@
+package org.eclipse.jdt.internal.compiler;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.*;
+
+public interface IHierarchyRequestor {
+ /**
+ * Connect the supplied type to its superclass & superinterfaces.
+ * The superclass & superinterfaces are the identical binary or source types as
+ * supplied by the name environment.
+ */
+
+ public void connect(
+ IGenericType suppliedType,
+ IGenericType superclass,
+ IGenericType[] superinterfaces);
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IProblem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IProblem.java
new file mode 100644
index 0000000000..d7195970f6
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IProblem.java
@@ -0,0 +1,63 @@
+package org.eclipse.jdt.internal.compiler;
+
+public interface IProblem {
+ final int Error = 1;
+ // when bit is set: problem is error, if not it is a warning
+ /**
+ * Answer back the original arguments recorded into the problem.
+ */
+ String[] getArguments();
+ /**
+ *
+ * @return int
+ */
+ int getID();
+ /**
+ * Answer a localized, human-readable message string which describes the problem.
+ */
+ String getMessage();
+ /**
+ * Answer the file name in which the problem was found.
+ */
+ char[] getOriginatingFileName();
+ /**
+ * Answer the severity of the problem.
+ */
+ int getSeverity();
+ /**
+ * Answer the end position of the problem (inclusive), or -1 if unknown.
+ */
+ int getSourceEnd();
+ /**
+ * Answer the line number in source where the problem begins.
+ */
+ int getSourceLineNumber();
+ /**
+ * Answer the start position of the problem (inclusive), or -1 if unknown.
+ */
+ int getSourceStart();
+ /*
+ * Helper method: checks the severity to see if the Error bit is set.
+ */
+ boolean isError();
+ /*
+ * Helper method: checks the severity to see if the Error bit is not set.
+ */
+ boolean isWarning();
+ /**
+ * Set the end position of the problem (inclusive), or -1 if unknown.
+ *
+ * Used for shifting problem positions.
+ */
+ void setSourceEnd(int sourceEnd);
+ /**
+ * Set the line number in source where the problem begins.
+ */
+ void setSourceLineNumber(int lineNumber);
+ /**
+ * Set the start position of the problem (inclusive), or -1 if unknown.
+ *
+ * Used for shifting problem positions.
+ */
+ void setSourceStart(int sourceStart);
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IProblemFactory.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IProblemFactory.java
new file mode 100644
index 0000000000..16c0320dea
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IProblemFactory.java
@@ -0,0 +1,28 @@
+package org.eclipse.jdt.internal.compiler;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Factory used from inside the compiler to build the actual problems
+ * which are handed back in the compilation result.
+ *
+ * This allows sharing the internal problem representation with the environment.
+ *
+ * Note: The factory is responsible for computing and storing a localized error message.
+ */
+import java.util.*;
+
+public interface IProblemFactory {
+ IProblem createProblem(
+ char[] originatingFileName,
+ int problemId,
+ String[] arguments,
+ int severity,
+ int startPosition,
+ int endPosition,
+ int lineNumber);
+ Locale getLocale();
+ String getLocalizedMessage(int problemId, String[] problemArguments);
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ISourceElementRequestor.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ISourceElementRequestor.java
new file mode 100644
index 0000000000..9afeef3682
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ISourceElementRequestor.java
@@ -0,0 +1,133 @@
+package org.eclipse.jdt.internal.compiler;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Part of the source element parser responsible for building the output.
+ * It gets notified of structural information as they are detected, relying
+ * on the requestor to assemble them together, based on the notifications it got.
+ *
+ * The structural investigation includes:
+ * - package statement
+ * - import statements
+ * - top-level types: package member, member types (member types of member types...)
+ * - fields
+ * - methods
+ *
+ * If reference information is requested, then all source constructs are
+ * investigated and type, field & method references are provided as well.
+ *
+ * Any (parsing) problem encountered is also provided.
+ *
+ * All positions are relative to the exact source fed to the parser.
+ *
+ * Elements which are complex are notified in two steps:
+ * - enter<Element> : once the element header has been identified
+ * - exit<Element> : once the element has been fully consumed
+ *
+ * other simpler elements (package, import) are read all at once:
+ * - accept<Element>
+ */
+
+import org.eclipse.jdt.internal.compiler.IProblem;
+
+public interface ISourceElementRequestor {
+ void acceptConstructorReference(
+ char[] typeName,
+ int argCount,
+ int sourcePosition);
+ void acceptFieldReference(char[] fieldName, int sourcePosition);
+ /**
+ * @param declarationStart This is the position of the first character of the
+ * import keyword.
+ * @param declarationEnd This is the position of the ';' ending the import statement
+ * or the end of the comment following the import.
+ * @param name This is the name of the import like specified in the source including the dots. The '.*'
+ * is never included in the name.
+ * @param onDemand set to true if the import is an import on demand (e.g. import java.io.*). False otherwise.
+ */
+ void acceptImport(
+ int declarationStart,
+ int declarationEnd,
+ char[] name,
+ boolean onDemand);
+ void acceptInitializer(
+ int modifiers,
+ int declarationSourceStart,
+ int declarationSourceEnd);
+ /*
+ * Table of line separator position. This table is passed once at the end
+ * of the parse action, so as to allow computation of normalized ranges.
+ *
+ * A line separator might corresponds to several characters in the source,
+ *
+ */
+ void acceptLineSeparatorPositions(int[] positions);
+ void acceptMethodReference(char[] methodName, int argCount, int sourcePosition);
+ void acceptPackage(int declarationStart, int declarationEnd, char[] name);
+ void acceptProblem(IProblem problem);
+ void acceptTypeReference(char[][] typeName, int sourceStart, int sourceEnd);
+ void acceptTypeReference(char[] typeName, int sourcePosition);
+ void acceptUnknownReference(char[][] name, int sourceStart, int sourceEnd);
+ void acceptUnknownReference(char[] name, int sourcePosition);
+ void enterClass(
+ int declarationStart,
+ int modifiers,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[] superclass,
+ char[][] superinterfaces);
+ void enterCompilationUnit();
+ void enterConstructor(
+ int declarationStart,
+ int modifiers,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[][] parameterTypes,
+ char[][] parameterNames,
+ char[][] exceptionTypes);
+ void enterField(
+ int declarationStart,
+ int modifiers,
+ char[] type,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd);
+ void enterInterface(
+ int declarationStart,
+ int modifiers,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[][] superinterfaces);
+ void enterMethod(
+ int declarationStart,
+ int modifiers,
+ char[] returnType,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[][] parameterTypes,
+ char[][] parameterNames,
+ char[][] exceptionTypes);
+ void exitClass(int declarationEnd);
+ void exitCompilationUnit(int declarationEnd);
+ void exitConstructor(int declarationEnd);
+ /*
+ * - No initialization source for now -
+ * initializationSource denotes the source of the expression used for initializing
+ * the field if any (if no source, then it is null).
+ *
+ * Note: the initializationSource will be used in case we do need to type check
+ * against source models, and thus the only interesting use for it is field
+ * constant propagation. Therefore, the initializationSource will only be non
+ * null for final fields (so as to minimize char[] allocations).
+ */
+ void exitField(/*char[] initializationSource, */ int declarationEnd);
+ void exitInterface(int declarationEnd);
+ void exitMethod(int declarationEnd);
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/SourceElementParser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/SourceElementParser.java
new file mode 100644
index 0000000000..28fc03a312
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/SourceElementParser.java
@@ -0,0 +1,1011 @@
+package org.eclipse.jdt.internal.compiler;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/**
+ * A source element parser extracts structural and reference information
+ * from a piece of source.
+ *
+ * also see @ISourceElementRequestor
+ *
+ * The structural investigation includes:
+ * - the package statement
+ * - import statements
+ * - top-level types: package member, member types (member types of member types...)
+ * - fields
+ * - methods
+ *
+ * If reference information is requested, then all source constructs are
+ * investigated and type, field & method references are provided as well.
+ *
+ * Any (parsing) problem encountered is also provided.
+ */
+import java.lang.reflect.Constructor;
+
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.parser.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class SourceElementParser extends Parser {
+ ISourceElementRequestor requestor;
+ private int fieldCount;
+ private int localIntPtr;
+ private int lastFieldEndPosition;
+ private ISourceType sourceType;
+ private boolean reportReferenceInfo;
+ private char[][] typeNames;
+ private char[][] superTypeNames;
+ private int nestedTypeIndex;
+ private static final char[] JAVA_LANG_OBJECT = "java.lang.Object".toCharArray();
+ public SourceElementParser(
+ final ISourceElementRequestor requestor,
+ IProblemFactory problemFactory) {
+ // we want to notify all syntax error with the acceptProblem API
+ // To do so, we define the record method of the ProblemReporter
+ super(new ProblemReporter(
+ DefaultErrorHandlingPolicies.exitAfterAllProblems(),
+ new CompilerOptions(),
+ problemFactory) {
+ public void record(IProblem problem, CompilationResult unitResult) {
+ unitResult.record(problem);
+ requestor.acceptProblem(problem);
+ }
+ }, false);
+ this.requestor = requestor;
+ typeNames = new char[4][];
+ superTypeNames = new char[4][];
+ nestedTypeIndex = 0;
+ }
+
+ protected void classInstanceCreation(boolean alwaysQualified) {
+
+ boolean previousFlag = reportReferenceInfo;
+ reportReferenceInfo = false;
+ // not to see the type reference reported in super call to getTypeReference(...)
+ super.classInstanceCreation(alwaysQualified);
+ reportReferenceInfo = previousFlag;
+ if (reportReferenceInfo) {
+ AllocationExpression alloc =
+ (AllocationExpression) expressionStack[expressionPtr];
+ TypeReference typeRef = alloc.type;
+ requestor.acceptConstructorReference(
+ typeRef instanceof SingleTypeReference
+ ? ((SingleTypeReference) typeRef).token
+ : CharOperation.concatWith(alloc.type.getTypeName(), '.'),
+ alloc.arguments == null ? 0 : alloc.arguments.length,
+ alloc.sourceStart);
+ }
+ }
+
+ protected void consumeConstructorHeaderName() {
+ // ConstructorHeaderName ::= Modifiersopt 'Identifier' '('
+
+ /* recovering - might be an empty message send */
+ if (currentElement != null) {
+ if (lastIgnoredToken == TokenNamenew) { // was an allocation expression
+ lastCheckPoint = scanner.startPosition;
+ // force to restart at this exact position
+ restartRecovery = true;
+ return;
+ }
+ }
+ SourceConstructorDeclaration cd = new SourceConstructorDeclaration();
+
+ //name -- this is not really revelant but we do .....
+ cd.selector = identifierStack[identifierPtr];
+ long selectorSourcePositions = identifierPositionStack[identifierPtr--];
+ identifierLengthPtr--;
+
+ //modifiers
+ cd.declarationSourceStart = intStack[intPtr--];
+ cd.modifiers = intStack[intPtr--];
+
+ //highlight starts at the selector starts
+ cd.sourceStart = (int) (selectorSourcePositions >>> 32);
+ cd.selectorSourceEnd = (int) selectorSourcePositions;
+ pushOnAstStack(cd);
+
+ cd.sourceEnd = lParenPos;
+ cd.bodyStart = lParenPos + 1;
+ listLength = 0; // initialize listLength before reading parameters/throws
+
+ // recovery
+ if (currentElement != null) {
+ lastCheckPoint = cd.bodyStart;
+ if ((currentElement instanceof RecoveredType
+ && lastIgnoredToken != TokenNameDOT)
+ || cd.modifiers != 0) {
+ currentElement = currentElement.add(cd, 0);
+ lastIgnoredToken = -1;
+ }
+ }
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumeExitVariableWithInitialization() {
+ // ExitVariableWithInitialization ::= $empty
+ // the scanner is located after the comma or the semi-colon.
+ // we want to include the comma or the semi-colon
+ super.consumeExitVariableWithInitialization();
+ if (isLocalDeclaration()
+ || ((currentToken != TokenNameCOMMA) && (currentToken != TokenNameSEMICOLON)))
+ return;
+ ((SourceFieldDeclaration) astStack[astPtr]).fieldEndPosition =
+ scanner.currentPosition - 1;
+ }
+
+ protected void consumeExitVariableWithoutInitialization() {
+ // ExitVariableWithoutInitialization ::= $empty
+ // do nothing by default
+ if (isLocalDeclaration()
+ || ((currentToken != TokenNameCOMMA) && (currentToken != TokenNameSEMICOLON)))
+ return;
+ ((SourceFieldDeclaration) astStack[astPtr]).fieldEndPosition =
+ scanner.currentPosition - 1;
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumeFieldAccess(boolean isSuperAccess) {
+ // FieldAccess ::= Primary '.' 'Identifier'
+ // FieldAccess ::= 'super' '.' 'Identifier'
+ super.consumeFieldAccess(isSuperAccess);
+ FieldReference fr = (FieldReference) expressionStack[expressionPtr];
+ if (reportReferenceInfo) {
+ requestor.acceptFieldReference(fr.token, fr.sourceStart);
+ }
+ }
+
+ protected void consumeMethodHeaderName() {
+ // MethodHeaderName ::= Modifiersopt Type 'Identifier' '('
+ int length;
+ SourceMethodDeclaration md = new SourceMethodDeclaration();
+
+ //name
+ md.selector = identifierStack[identifierPtr];
+ long selectorSourcePositions = identifierPositionStack[identifierPtr--];
+ identifierLengthPtr--;
+ //type
+ md.returnType = getTypeReference(intStack[intPtr--]);
+ //modifiers
+ md.declarationSourceStart = intStack[intPtr--];
+ md.modifiers = intStack[intPtr--];
+
+ //highlight starts at selector start
+ md.sourceStart = (int) (selectorSourcePositions >>> 32);
+ md.selectorSourceEnd = (int) selectorSourcePositions;
+ pushOnAstStack(md);
+ md.sourceEnd = lParenPos;
+ md.bodyStart = lParenPos + 1;
+ listLength = 0; // initialize listLength before reading parameters/throws
+
+ // recovery
+ if (currentElement != null) {
+ if (currentElement instanceof RecoveredType //|| md.modifiers != 0
+ || (scanner.searchLineNumber(md.returnType.sourceStart)
+ == scanner.searchLineNumber(md.sourceStart))) {
+ lastCheckPoint = md.bodyStart;
+ currentElement = currentElement.add(md, 0);
+ lastIgnoredToken = -1;
+ } else {
+ lastCheckPoint = md.sourceStart;
+ restartRecovery = true;
+ }
+ }
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumeMethodInvocationName() {
+ // MethodInvocation ::= Name '(' ArgumentListopt ')'
+
+ // when the name is only an identifier...we have a message send to "this" (implicit)
+ super.consumeMethodInvocationName();
+ MessageSend messageSend = (MessageSend) expressionStack[expressionPtr];
+ Expression[] args = messageSend.arguments;
+ if (reportReferenceInfo) {
+ requestor.acceptMethodReference(
+ messageSend.selector,
+ args == null ? 0 : args.length,
+ (int) (messageSend.nameSourcePosition >>> 32));
+ }
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumeMethodInvocationPrimary() {
+ super.consumeMethodInvocationPrimary();
+ MessageSend messageSend = (MessageSend) expressionStack[expressionPtr];
+ Expression[] args = messageSend.arguments;
+ if (reportReferenceInfo) {
+ requestor.acceptMethodReference(
+ messageSend.selector,
+ args == null ? 0 : args.length,
+ (int) (messageSend.nameSourcePosition >>> 32));
+ }
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void consumeMethodInvocationSuper() {
+ // MethodInvocation ::= 'super' '.' 'Identifier' '(' ArgumentListopt ')'
+ super.consumeMethodInvocationSuper();
+ MessageSend messageSend = (MessageSend) expressionStack[expressionPtr];
+ Expression[] args = messageSend.arguments;
+ if (reportReferenceInfo) {
+ requestor.acceptMethodReference(
+ messageSend.selector,
+ args == null ? 0 : args.length,
+ (int) (messageSend.nameSourcePosition >>> 32));
+ }
+ }
+
+ protected void consumeSingleTypeImportDeclarationName() {
+ // SingleTypeImportDeclarationName ::= 'import' Name
+ /* push an ImportRef build from the last name
+ stored in the identifier stack. */
+
+ super.consumeSingleTypeImportDeclarationName();
+ ImportReference impt = (ImportReference) astStack[astPtr];
+ if (reportReferenceInfo) {
+ requestor.acceptTypeReference(
+ impt.tokens,
+ impt.sourceStart(),
+ impt.sourceEnd());
+ }
+ }
+
+ protected void consumeTypeImportOnDemandDeclarationName() {
+ // TypeImportOnDemandDeclarationName ::= 'import' Name '.' '*'
+ /* push an ImportRef build from the last name
+ stored in the identifier stack. */
+
+ super.consumeTypeImportOnDemandDeclarationName();
+ ImportReference impt = (ImportReference) astStack[astPtr];
+ if (reportReferenceInfo) {
+ requestor.acceptUnknownReference(
+ impt.tokens,
+ impt.sourceStart(),
+ impt.sourceEnd());
+ }
+ }
+
+ protected FieldDeclaration createFieldDeclaration(
+ Expression initialization,
+ char[] name,
+ int sourceStart,
+ int sourceEnd) {
+ return new SourceFieldDeclaration(null, name, sourceStart, sourceEnd);
+ }
+
+ protected CompilationUnitDeclaration endParse(int act) {
+
+ if (sourceType != null) {
+ if (sourceType.isInterface()) {
+ consumeInterfaceDeclaration();
+ } else {
+ consumeClassDeclaration();
+ }
+ }
+ CompilationUnitDeclaration result = super.endParse(act);
+ notifySourceElementRequestor();
+ return result;
+ }
+
+ /*
+ * Flush annotations defined prior to a given positions.
+ *
+ * Note: annotations are stacked in syntactical order
+ *
+ * Either answer given <position>, or the end position of a comment line
+ * immediately following the <position> (same line)
+ *
+ * e.g.
+ * void foo(){
+ * } // end of method foo
+ */
+
+ public int flushAnnotationsDefinedPriorTo(int position) {
+
+ return lastFieldEndPosition = super.flushAnnotationsDefinedPriorTo(position);
+ }
+
+ public TypeReference getTypeReference(int dim) {
+ /* build a Reference on a variable that may be qualified or not
+ * This variable is a type reference and dim will be its dimensions
+ */
+ int length;
+ if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) {
+ // single variable reference
+ if (dim == 0) {
+ SingleTypeReference ref =
+ new SingleTypeReference(
+ identifierStack[identifierPtr],
+ identifierPositionStack[identifierPtr--]);
+ if (reportReferenceInfo) {
+ requestor.acceptTypeReference(ref.token, ref.sourceStart);
+ }
+ return ref;
+ } else {
+ ArrayTypeReference ref =
+ new ArrayTypeReference(
+ identifierStack[identifierPtr],
+ dim,
+ identifierPositionStack[identifierPtr--]);
+ if (reportReferenceInfo) {
+ requestor.acceptTypeReference(ref.token, ref.sourceStart);
+ }
+ return ref;
+ }
+ } else {
+ if (length < 0) { //flag for precompiled type reference on base types
+ TypeReference ref = TypeReference.baseTypeReference(-length, dim);
+ ref.sourceStart = intStack[intPtr--];
+ return ref;
+ } else { //Qualified variable reference
+ char[][] tokens = new char[length][];
+ identifierPtr -= length;
+ long[] positions = new long[length];
+ System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length);
+ System.arraycopy(
+ identifierPositionStack,
+ identifierPtr + 1,
+ positions,
+ 0,
+ length);
+ if (dim == 0) {
+ QualifiedTypeReference ref = new QualifiedTypeReference(tokens, positions);
+ if (reportReferenceInfo) {
+ requestor.acceptTypeReference(ref.tokens, ref.sourceStart(), ref.sourceEnd());
+ }
+ return ref;
+ } else {
+ ArrayQualifiedTypeReference ref =
+ new ArrayQualifiedTypeReference(tokens, dim, positions);
+ if (reportReferenceInfo) {
+ requestor.acceptTypeReference(ref.tokens, ref.sourceStart(), ref.sourceEnd());
+ }
+ return ref;
+ }
+ }
+ }
+ }
+
+ public NameReference getUnspecifiedReference() {
+ /* build a (unspecified) NameReference which may be qualified*/
+
+ int length;
+ if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) {
+ // single variable reference
+ SingleNameReference ref =
+ new SingleNameReference(
+ identifierStack[identifierPtr],
+ identifierPositionStack[identifierPtr--]);
+ if (reportReferenceInfo) {
+ requestor.acceptUnknownReference(ref.token, ref.sourceStart());
+ }
+ return ref;
+ } else {
+ //Qualified variable reference
+ char[][] tokens = new char[length][];
+ identifierPtr -= length;
+ System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length);
+ QualifiedNameReference ref =
+ new QualifiedNameReference(
+ tokens,
+ (int) (identifierPositionStack[identifierPtr + 1] >> 32),
+ // sourceStart
+ (int) identifierPositionStack[identifierPtr + length]); // sourceEnd
+ if (reportReferenceInfo) {
+ requestor.acceptUnknownReference(
+ ref.tokens,
+ ref.sourceStart(),
+ ref.sourceEnd());
+ }
+ return ref;
+ }
+ }
+
+ public NameReference getUnspecifiedReferenceOptimized() {
+ /* build a (unspecified) NameReference which may be qualified
+ The optimization occurs for qualified reference while we are
+ certain in this case the last item of the qualified name is
+ a field access. This optimization is IMPORTANT while it results
+ that when a NameReference is build, the type checker should always
+ look for that it is not a type reference */
+
+ int length;
+ if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) {
+ // single variable reference
+ SingleNameReference ref =
+ new SingleNameReference(
+ identifierStack[identifierPtr],
+ identifierPositionStack[identifierPtr--]);
+ ref.bits &= ~NameReference.RestrictiveFlagMASK;
+ ref.bits |= LOCAL | FIELD;
+ if (reportReferenceInfo) {
+ requestor.acceptUnknownReference(ref.token, ref.sourceStart());
+ }
+ return ref;
+ }
+
+ //Qualified-variable-reference
+ //In fact it is variable-reference DOT field-ref , but it would result in a type
+ //conflict tha can be only reduce by making a superclass (or inetrface ) between
+ //nameReference and FiledReference or putting FieldReference under NameReference
+ //or else..........This optimisation is not really relevant so just leave as it is
+
+ char[][] tokens = new char[length][];
+ identifierPtr -= length;
+ System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length);
+ QualifiedNameReference ref =
+ new QualifiedNameReference(
+ tokens,
+ (int) (identifierPositionStack[identifierPtr + 1] >> 32),
+ // sourceStart
+ (int) identifierPositionStack[identifierPtr + length]); // sourceEnd
+ ref.bits &= ~NameReference.RestrictiveFlagMASK;
+ ref.bits |= LOCAL | FIELD;
+ if (reportReferenceInfo) {
+ requestor.acceptUnknownReference(
+ ref.tokens,
+ ref.sourceStart(),
+ ref.sourceEnd());
+ }
+ return ref;
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ private boolean isLocalDeclaration() {
+ int nestedDepth = nestedType;
+ while (nestedDepth >= 0) {
+ if (nestedMethod[nestedDepth] != 0) {
+ return true;
+ }
+ nestedDepth--;
+ }
+ return false;
+ }
+
+ /*
+ * Update the bodyStart of the corresponding parse node
+ */
+ public void notifySourceElementRequestor() {
+
+ if (sourceType == null) {
+ if (scanner.initialPosition == 0) {
+ requestor.enterCompilationUnit();
+ }
+ // first we notify the package declaration
+ ImportReference currentPackage = compilationUnit.currentPackage;
+ if (currentPackage != null) {
+ notifySourceElementRequestor(currentPackage, true);
+ }
+ // then the imports
+ ImportReference[] imports = compilationUnit.imports;
+ if (imports != null) {
+ for (int i = 0, max = imports.length; i < max; i++) {
+ notifySourceElementRequestor(imports[i], false);
+ }
+ }
+ }
+ // then the types contained by this compilation unit
+ TypeDeclaration[] types = compilationUnit.types;
+ if (types != null) {
+ for (int i = 0, max = types.length; i < max; i++) {
+ notifySourceElementRequestor(types[i], sourceType == null);
+ }
+ }
+ if (sourceType == null) {
+ if (scanner.eofPosition >= compilationUnit.sourceEnd) {
+ requestor.exitCompilationUnit(compilationUnit.sourceEnd);
+ }
+ }
+ }
+
+ /*
+ * Update the bodyStart of the corresponding parse node
+ */
+ public void notifySourceElementRequestor(AbstractMethodDeclaration methodDeclaration) {
+ if (methodDeclaration.isClinit())
+ return;
+
+ if (methodDeclaration.isDefaultConstructor()) {
+ if (reportReferenceInfo) {
+ ConstructorDeclaration constructorDeclaration =
+ (ConstructorDeclaration) methodDeclaration;
+ ExplicitConstructorCall constructorCall =
+ constructorDeclaration.constructorCall;
+ if (constructorCall != null) {
+ switch (constructorCall.accessMode) {
+ case ExplicitConstructorCall.This :
+ requestor.acceptConstructorReference(
+ typeNames[nestedTypeIndex - 1],
+ constructorCall.arguments == null ? 0 : constructorCall.arguments.length,
+ constructorCall.sourceStart);
+ break;
+ case ExplicitConstructorCall.Super :
+ case ExplicitConstructorCall.ImplicitSuper :
+ requestor.acceptConstructorReference(
+ superTypeNames[nestedTypeIndex - 1],
+ constructorCall.arguments == null ? 0 : constructorCall.arguments.length,
+ constructorCall.sourceStart);
+ break;
+ }
+ }
+ }
+ return;
+ }
+ char[][] argumentTypes = null;
+ char[][] argumentNames = null;
+ Argument[] arguments = methodDeclaration.arguments;
+ if (arguments != null) {
+ int argumentLength = arguments.length;
+ argumentTypes = new char[argumentLength][];
+ argumentNames = new char[argumentLength][];
+ for (int i = 0; i < argumentLength; i++) {
+ argumentTypes[i] = returnTypeName(arguments[i].type);
+ argumentNames[i] = arguments[i].name;
+ }
+ }
+ char[][] thrownExceptionTypes = null;
+ TypeReference[] thrownExceptions = methodDeclaration.thrownExceptions;
+ if (thrownExceptions != null) {
+ int thrownExceptionLength = thrownExceptions.length;
+ thrownExceptionTypes = new char[thrownExceptionLength][];
+ for (int i = 0; i < thrownExceptionLength; i++) {
+ thrownExceptionTypes[i] =
+ CharOperation.concatWith(thrownExceptions[i].getTypeName(), '.');
+ }
+ }
+ // by default no selector end position
+ int selectorSourceEnd = -1;
+ if (methodDeclaration.isConstructor()) {
+ if (methodDeclaration instanceof SourceConstructorDeclaration) {
+ selectorSourceEnd =
+ ((SourceConstructorDeclaration) methodDeclaration).selectorSourceEnd;
+ }
+ if (scanner.initialPosition <= methodDeclaration.declarationSourceStart) {
+ requestor.enterConstructor(
+ methodDeclaration.declarationSourceStart,
+ methodDeclaration.modifiers,
+ methodDeclaration.selector,
+ methodDeclaration.sourceStart,
+ selectorSourceEnd,
+ argumentTypes,
+ argumentNames,
+ thrownExceptionTypes);
+ if (reportReferenceInfo) {
+ ConstructorDeclaration constructorDeclaration =
+ (ConstructorDeclaration) methodDeclaration;
+ ExplicitConstructorCall constructorCall =
+ constructorDeclaration.constructorCall;
+ if (constructorCall != null) {
+ switch (constructorCall.accessMode) {
+ case ExplicitConstructorCall.This :
+ requestor.acceptConstructorReference(
+ typeNames[nestedTypeIndex - 1],
+ constructorCall.arguments == null ? 0 : constructorCall.arguments.length,
+ constructorCall.sourceStart);
+ break;
+ case ExplicitConstructorCall.Super :
+ case ExplicitConstructorCall.ImplicitSuper :
+ requestor.acceptConstructorReference(
+ superTypeNames[nestedTypeIndex - 1],
+ constructorCall.arguments == null ? 0 : constructorCall.arguments.length,
+ constructorCall.sourceStart);
+ break;
+ }
+ }
+ }
+ }
+ if (scanner.eofPosition >= methodDeclaration.declarationSourceEnd) {
+ requestor.exitConstructor(methodDeclaration.declarationSourceEnd);
+ }
+ return;
+ }
+ if (methodDeclaration instanceof SourceMethodDeclaration) {
+ selectorSourceEnd =
+ ((SourceMethodDeclaration) methodDeclaration).selectorSourceEnd;
+ }
+ requestor.enterMethod(
+ methodDeclaration.declarationSourceStart,
+ methodDeclaration.modifiers,
+ returnTypeName(((MethodDeclaration) methodDeclaration).returnType),
+ methodDeclaration.selector,
+ methodDeclaration.sourceStart,
+ selectorSourceEnd,
+ argumentTypes,
+ argumentNames,
+ thrownExceptionTypes);
+ requestor.exitMethod(methodDeclaration.declarationSourceEnd);
+ }
+
+ /*
+ * Update the bodyStart of the corresponding parse node
+ */
+ public void notifySourceElementRequestor(FieldDeclaration fieldDeclaration) {
+ if (fieldDeclaration.isField()) {
+ int fieldEndPosition = fieldDeclaration.declarationSourceEnd;
+ if (fieldDeclaration instanceof SourceFieldDeclaration) {
+ fieldEndPosition = ((SourceFieldDeclaration) fieldDeclaration).fieldEndPosition;
+ if (fieldEndPosition == 0) {
+ // use the declaration source end by default
+ fieldEndPosition = fieldDeclaration.declarationSourceEnd;
+ }
+ }
+ requestor.enterField(
+ fieldDeclaration.declarationSourceStart,
+ fieldDeclaration.modifiers,
+ returnTypeName(fieldDeclaration.type),
+ fieldDeclaration.name,
+ fieldDeclaration.sourceStart,
+ fieldDeclaration.sourceEnd);
+ requestor.exitField(fieldEndPosition);
+
+ } else {
+ requestor.acceptInitializer(
+ fieldDeclaration.modifiers,
+ fieldDeclaration.declarationSourceStart,
+ fieldDeclaration.declarationSourceEnd);
+ }
+ }
+
+ public void notifySourceElementRequestor(
+ ImportReference importReference,
+ boolean isPackage) {
+ if (isPackage) {
+ requestor.acceptPackage(
+ importReference.declarationSourceStart,
+ importReference.declarationSourceEnd,
+ CharOperation.concatWith(importReference.getImportName(), '.'));
+ } else {
+ requestor.acceptImport(
+ importReference.declarationSourceStart,
+ importReference.declarationSourceEnd,
+ CharOperation.concatWith(importReference.getImportName(), '.'),
+ importReference.onDemand);
+ }
+ }
+
+ public void notifySourceElementRequestor(
+ TypeDeclaration typeDeclaration,
+ boolean notifyTypePresence) {
+ FieldDeclaration[] fields = typeDeclaration.fields;
+ AbstractMethodDeclaration[] methods = typeDeclaration.methods;
+ MemberTypeDeclaration[] memberTypes = typeDeclaration.memberTypes;
+ int fieldCount = fields == null ? 0 : fields.length;
+ int methodCount = methods == null ? 0 : methods.length;
+ int memberTypeCount = memberTypes == null ? 0 : memberTypes.length;
+ int fieldIndex = 0;
+ int methodIndex = 0;
+ int memberTypeIndex = 0;
+ boolean isInterface = typeDeclaration.isInterface();
+
+ if (notifyTypePresence) {
+ char[][] interfaceNames = null;
+ int superInterfacesLength = 0;
+ TypeReference[] superInterfaces = typeDeclaration.superInterfaces;
+ if (superInterfaces != null) {
+ superInterfacesLength = superInterfaces.length;
+ interfaceNames = new char[superInterfacesLength][];
+ }
+ if (superInterfaces != null) {
+ for (int i = 0; i < superInterfacesLength; i++) {
+ interfaceNames[i] =
+ CharOperation.concatWith(superInterfaces[i].getTypeName(), '.');
+ }
+ }
+ if (isInterface) {
+ requestor.enterInterface(
+ typeDeclaration.declarationSourceStart,
+ typeDeclaration.modifiers,
+ typeDeclaration.name,
+ typeDeclaration.sourceStart,
+ typeDeclaration.sourceEnd,
+ interfaceNames);
+ if (nestedTypeIndex == typeNames.length) {
+ // need a resize
+ System.arraycopy(
+ typeNames,
+ 0,
+ (typeNames = new char[nestedTypeIndex * 2][]),
+ 0,
+ nestedTypeIndex);
+ System.arraycopy(
+ superTypeNames,
+ 0,
+ (superTypeNames = new char[nestedTypeIndex * 2][]),
+ 0,
+ nestedTypeIndex);
+ }
+ typeNames[nestedTypeIndex] = typeDeclaration.name;
+ superTypeNames[nestedTypeIndex++] = JAVA_LANG_OBJECT;
+ } else {
+ TypeReference superclass = typeDeclaration.superclass;
+ if (superclass == null) {
+ requestor.enterClass(
+ typeDeclaration.declarationSourceStart,
+ typeDeclaration.modifiers,
+ typeDeclaration.name,
+ typeDeclaration.sourceStart,
+ typeDeclaration.sourceEnd,
+ null,
+ interfaceNames);
+ } else {
+ requestor.enterClass(
+ typeDeclaration.declarationSourceStart,
+ typeDeclaration.modifiers,
+ typeDeclaration.name,
+ typeDeclaration.sourceStart,
+ typeDeclaration.sourceEnd,
+ CharOperation.concatWith(superclass.getTypeName(), '.'),
+ interfaceNames);
+ }
+ if (nestedTypeIndex == typeNames.length) {
+ // need a resize
+ System.arraycopy(
+ typeNames,
+ 0,
+ (typeNames = new char[nestedTypeIndex * 2][]),
+ 0,
+ nestedTypeIndex);
+ System.arraycopy(
+ superTypeNames,
+ 0,
+ (superTypeNames = new char[nestedTypeIndex * 2][]),
+ 0,
+ nestedTypeIndex);
+ }
+ typeNames[nestedTypeIndex] = typeDeclaration.name;
+ superTypeNames[nestedTypeIndex++] =
+ superclass == null
+ ? JAVA_LANG_OBJECT
+ : CharOperation.concatWith(superclass.getTypeName(), '.');
+ }
+ }
+ while ((fieldIndex < fieldCount)
+ || (memberTypeIndex < memberTypeCount)
+ || (methodIndex < methodCount)) {
+ FieldDeclaration nextFieldDeclaration = null;
+ AbstractMethodDeclaration nextMethodDeclaration = null;
+ TypeDeclaration nextMemberDeclaration = null;
+
+ int position = Integer.MAX_VALUE;
+ int nextDeclarationType = -1;
+ if (fieldIndex < fieldCount) {
+ nextFieldDeclaration = fields[fieldIndex];
+ if (nextFieldDeclaration.declarationSourceStart < position) {
+ position = nextFieldDeclaration.declarationSourceStart;
+ nextDeclarationType = 0; // FIELD
+ }
+ }
+ if (methodIndex < methodCount) {
+ nextMethodDeclaration = methods[methodIndex];
+ if (nextMethodDeclaration.declarationSourceStart < position) {
+ position = nextMethodDeclaration.declarationSourceStart;
+ nextDeclarationType = 1; // METHOD
+ }
+ }
+ if (memberTypeIndex < memberTypeCount) {
+ nextMemberDeclaration = memberTypes[memberTypeIndex];
+ if (nextMemberDeclaration.declarationSourceStart < position) {
+ position = nextMemberDeclaration.declarationSourceStart;
+ nextDeclarationType = 2; // MEMBER
+ }
+ }
+ switch (nextDeclarationType) {
+ case 0 :
+ fieldIndex++;
+ notifySourceElementRequestor(nextFieldDeclaration);
+ break;
+ case 1 :
+ methodIndex++;
+ notifySourceElementRequestor(nextMethodDeclaration);
+ break;
+ case 2 :
+ memberTypeIndex++;
+ notifySourceElementRequestor(nextMemberDeclaration, true);
+ }
+ }
+ if (notifyTypePresence) {
+ if (isInterface) {
+ requestor.exitInterface(typeDeclaration.declarationSourceEnd);
+ } else {
+ requestor.exitClass(typeDeclaration.declarationSourceEnd);
+ }
+ nestedTypeIndex--;
+ }
+ }
+
+ public void parseCompilationUnit(
+ ICompilationUnit unit,
+ int start,
+ int end,
+ boolean needReferenceInfo) {
+
+ CompilationUnitDeclaration result;
+ reportReferenceInfo = needReferenceInfo;
+ boolean old = diet;
+ try {
+ diet = !needReferenceInfo;
+ CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0);
+ result = parse(unit, compilationUnitResult, start, end);
+ } catch (AbortCompilation e) {
+ } finally {
+ if (scanner.recordLineSeparator) {
+ requestor.acceptLineSeparatorPositions(scanner.lineEnds());
+ }
+ diet = old;
+ }
+ }
+
+ public void parseCompilationUnit(
+ ICompilationUnit unit,
+ boolean needReferenceInfo) {
+
+ CompilationUnitDeclaration result;
+ boolean old = diet;
+ try {
+ diet = !needReferenceInfo;
+ reportReferenceInfo = needReferenceInfo;
+ CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0);
+ result = parse(unit, compilationUnitResult);
+ } catch (AbortCompilation e) {
+ } finally {
+ if (scanner.recordLineSeparator) {
+ requestor.acceptLineSeparatorPositions(scanner.lineEnds());
+ }
+ diet = old;
+ }
+ }
+
+ public void parseTypeMemberDeclarations(
+ ISourceType sourceType,
+ ICompilationUnit sourceUnit,
+ int start,
+ int end,
+ boolean needReferenceInfo) {
+
+ boolean old = diet;
+ try {
+ diet = !needReferenceInfo;
+ reportReferenceInfo = needReferenceInfo;
+ CompilationResult compilationUnitResult =
+ new CompilationResult(sourceUnit, 0, 0);
+
+ CompilationUnitDeclaration unit =
+ SourceTypeConverter.buildCompilationUnit(
+ sourceType,
+ false,
+ false,
+ problemReporter(),
+ compilationUnitResult);
+ if ((unit == null) || (unit.types == null) || (unit.types.length != 1))
+ return;
+
+ this.sourceType = sourceType;
+
+ try {
+ /* automaton initialization */
+ initialize();
+ goForClassBodyDeclarations();
+ /* scanner initialization */
+ scanner.setSourceBuffer(sourceUnit.getContents());
+ int sourceLength = scanner.source.length;
+ scanner.resetTo(start, end);
+ /* unit creation */
+ referenceContext = compilationUnit = unit;
+
+ /* initialize the astStacl */
+ // the compilationUnitDeclaration should contain exactly one type
+ pushOnAstStack(unit.types[0]);
+ /* run automaton */
+ parse();
+ } finally {
+ unit = compilationUnit;
+ compilationUnit = null; // reset parser
+ }
+ } catch (AbortCompilation e) {
+ } finally {
+ if (scanner.recordLineSeparator) {
+ requestor.acceptLineSeparatorPositions(scanner.lineEnds());
+ }
+ diet = old;
+ }
+ }
+
+ /*
+ * Answer a char array representation of the type name formatted like:
+ * - type name + dimensions
+ * Example:
+ * "A[][]".toCharArray()
+ * "java.lang.String".toCharArray()
+ */
+ private char[] returnTypeName(TypeReference type) {
+ if (type == null)
+ return null;
+ int dimension = type.dimensions();
+ if (dimension != 0) {
+ char[] dimensionsArray = new char[dimension * 2];
+ for (int i = 0; i < dimension; i++) {
+ dimensionsArray[i * 2] = '[';
+ dimensionsArray[(i * 2) + 1] = ']';
+ }
+ return CharOperation.concat(
+ CharOperation.concatWith(type.getTypeName(), '.'),
+ dimensionsArray);
+ }
+ return CharOperation.concatWith(type.getTypeName(), '.');
+ }
+
+ private TypeReference typeReference(
+ int dim,
+ int localIdentifierPtr,
+ int localIdentifierLengthPtr) {
+ /* build a Reference on a variable that may be qualified or not
+ * This variable is a type reference and dim will be its dimensions.
+ * We don't have any side effect on the stacks' pointers.
+ */
+
+ int length;
+ TypeReference ref;
+ if ((length = identifierLengthStack[localIdentifierLengthPtr]) == 1) {
+ // single variable reference
+ if (dim == 0) {
+ ref =
+ new SingleTypeReference(
+ identifierStack[localIdentifierPtr],
+ identifierPositionStack[localIdentifierPtr--]);
+ } else {
+ ref =
+ new ArrayTypeReference(
+ identifierStack[localIdentifierPtr],
+ dim,
+ identifierPositionStack[localIdentifierPtr--]);
+ }
+ } else {
+ if (length < 0) { //flag for precompiled type reference on base types
+ ref = TypeReference.baseTypeReference(-length, dim);
+ ref.sourceStart = intStack[localIntPtr--];
+ } else { //Qualified variable reference
+ char[][] tokens = new char[length][];
+ localIdentifierPtr -= length;
+ long[] positions = new long[length];
+ System.arraycopy(identifierStack, localIdentifierPtr + 1, tokens, 0, length);
+ System.arraycopy(
+ identifierPositionStack,
+ localIdentifierPtr + 1,
+ positions,
+ 0,
+ length);
+ if (dim == 0)
+ ref = new QualifiedTypeReference(tokens, positions);
+ else
+ ref = new ArrayQualifiedTypeReference(tokens, dim, positions);
+ }
+ };
+ return ref;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java
new file mode 100644
index 0000000000..2aa1690f20
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java
@@ -0,0 +1,375 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class AND_AND_Expression extends BinaryExpression {
+ //dedicated treatment for the &&
+ int rightInitStateIndex = -1;
+ int mergedInitStateIndex = -1;
+
+ public AND_AND_Expression(Expression left, Expression right, int operator) {
+ super(left, right, operator);
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ if (left.constant != NotAConstant) {
+ if (left.constant.booleanValue()) { //true && anything
+ // in this case only, we are sure that local inits performed in
+ // the argument <anything> will be executed even though it was
+ // a conditional operation
+ FlowInfo mergedInfo = right.analyseCode(currentScope, flowContext, flowInfo);
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(mergedInfo);
+ return mergedInfo;
+ } else { //false && anything
+ // in this case only, we are sure that local inits performed in
+ // the argument <anything> will *not* be executed even though it
+ // was a conditional operation
+ return flowInfo;
+ }
+ }
+ if (right.constant != NotAConstant) {
+ if (right.constant.booleanValue()) { // anything && true
+ // in this case only, we are sure that local inits performed in
+ // the argument <anything> will be executed even though it was
+ // a conditional operation
+ FlowInfo mergedInfo = left.analyseCode(currentScope, flowContext, flowInfo);
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(mergedInfo);
+ return mergedInfo;
+ } else { // anything && false
+ // whatever is on the left, we will fail, so the result must merge the left inits when answering
+ // initsWhenFalse.
+ // the initsWhenTrue are undetermined, since this path will be fake reachable...
+ FlowInfo mergedInfo =
+ left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(mergedInfo);
+ return mergedInfo;
+ }
+ }
+
+ FlowInfo leftInfo, rightInfo;
+ leftInfo = left.analyseCode(currentScope, flowContext, flowInfo);
+ rightInfo = leftInfo.initsWhenTrue().copy();
+ rightInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(rightInfo);
+ rightInfo = right.analyseCode(currentScope, flowContext, rightInfo);
+ FlowInfo mergedInfo =
+ FlowInfo.conditional(
+ rightInfo.initsWhenTrue(),
+ leftInfo.initsWhenFalse().unconditionalInits().mergedWith(
+ rightInfo.initsWhenFalse().copy().unconditionalInits()));
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(mergedInfo);
+ return mergedInfo;
+ }
+
+ public void computeConstant(BlockScope scope, int leftId, int rightId) {
+ //the TC has been done so leftId and rightId are both equal to T_boolean
+
+ Constant cst;
+ if ((cst = left.constant) != NotAConstant) {
+ if (cst.booleanValue() == false) { // false && x --> false
+ constant = cst; // inlined to constant(false)
+ } else { // true && x --> x
+ if ((constant = right.constant) == NotAConstant) {
+ // compute conditionalConstant
+ optimizedBooleanConstant(
+ leftId,
+ (bits & OperatorMASK) >> OperatorSHIFT,
+ rightId);
+ }
+ }
+ } else {
+ constant = NotAConstant;
+ // compute conditionalConstant
+ optimizedBooleanConstant(
+ leftId,
+ (bits & OperatorMASK) >> OperatorSHIFT,
+ rightId);
+ }
+ }
+
+ /**
+ * Code generation for a binary operation
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ Label falseLabel, endLabel;
+ if (constant != Constant.NotAConstant) {
+ // inlined value
+ if (valueRequired)
+ codeStream.generateConstant(constant, implicitConversion);
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ bits |= OnlyValueRequiredMASK;
+ generateOptimizedConditionalAnd(
+ currentScope,
+ codeStream,
+ null,
+ (falseLabel = new Label(codeStream)),
+ valueRequired);
+ /* improving code gen for such a case: boolean b = i < 0 && false
+ * since the label has never been used, we have the inlined value on the stack. */
+ if (falseLabel.hasForwardReferences()) {
+ if (valueRequired) {
+ codeStream.iconst_1();
+ if ((bits & ValueForReturnMASK) != 0) {
+ codeStream.ireturn();
+ falseLabel.place();
+ codeStream.iconst_0();
+ } else {
+ codeStream.goto_(endLabel = new Label(codeStream));
+ codeStream.decrStackSize(1);
+ falseLabel.place();
+ codeStream.iconst_0();
+ endLabel.place();
+ }
+ } else {
+ falseLabel.place();
+ }
+ }
+ if (valueRequired) {
+ codeStream.generateImplicitConversion(implicitConversion);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ /**
+ * Boolean operator code generation
+ * Optimized operations are: &&
+ */
+ public void generateOptimizedBoolean(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Label trueLabel,
+ Label falseLabel,
+ boolean valueRequired) {
+ if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) {
+ int pc = codeStream.position;
+ if (constant.booleanValue() == true) {
+ // constant == true
+ if (valueRequired) {
+ if (falseLabel == null) {
+ // implicit falling through the FALSE case
+ if (trueLabel != null) {
+ codeStream.goto_(trueLabel);
+ }
+ }
+ }
+ } else {
+ if (valueRequired) {
+ if (falseLabel != null) {
+ // implicit falling through the TRUE case
+ if (trueLabel == null) {
+ codeStream.goto_(falseLabel);
+ }
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ generateOptimizedConditionalAnd(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ valueRequired);
+ }
+
+ /**
+ * Boolean generation for &&
+ */
+ public void generateOptimizedConditionalAnd(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Label trueLabel,
+ Label falseLabel,
+ boolean valueRequired) {
+
+ int pc = codeStream.position;
+ Constant condConst;
+ if ((condConst = left.conditionalConstant()) != NotAConstant) {
+ if (condConst.booleanValue() == true) {
+ // <something equivalent to true> && x
+ left.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ if (rightInitStateIndex != -1) {
+ codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex);
+ }
+ if ((bits & OnlyValueRequiredMASK) != 0) {
+ right.generateCode(currentScope, codeStream, valueRequired);
+ } else {
+ right.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ valueRequired);
+ }
+ } else {
+ // <something equivalent to false> && x
+ left.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ if (valueRequired) {
+ if ((bits & OnlyValueRequiredMASK) != 0) {
+ codeStream.iconst_0();
+ } else {
+ if (falseLabel != null) {
+ // implicit falling through the TRUE case
+ codeStream.goto_(falseLabel);
+ }
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ if (mergedInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ mergedInitStateIndex);
+ }
+ return;
+ }
+ if ((condConst = right.conditionalConstant()) != NotAConstant) {
+ if (condConst.booleanValue() == true) {
+ // x && <something equivalent to true>
+ if ((bits & OnlyValueRequiredMASK) != 0) {
+ left.generateCode(currentScope, codeStream, valueRequired);
+ } else {
+ left.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ valueRequired);
+ }
+ if (rightInitStateIndex != -1) {
+ codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex);
+ }
+ right.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ } else {
+ // x && <something equivalent to false>
+ left.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ if (rightInitStateIndex != -1) {
+ codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex);
+ }
+ right.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ if (valueRequired) {
+ if ((bits & OnlyValueRequiredMASK) != 0) {
+ codeStream.iconst_0();
+ } else {
+ if (falseLabel != null) {
+ // implicit falling through the TRUE case
+ codeStream.goto_(falseLabel);
+ }
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ if (mergedInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ mergedInitStateIndex);
+ }
+ return;
+ }
+ // default case
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // implicit falling through the FALSE case
+ Label internalFalseLabel = new Label(codeStream);
+ left.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ null,
+ internalFalseLabel,
+ true);
+ if (rightInitStateIndex != -1) {
+ codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex);
+ }
+ right.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ null,
+ valueRequired);
+ internalFalseLabel.place();
+ }
+ } else {
+ // implicit falling through the TRUE case
+ if (trueLabel == null) {
+ left.generateOptimizedBoolean(currentScope, codeStream, null, falseLabel, true);
+ if (rightInitStateIndex != -1) {
+ codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex);
+ }
+ right.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ null,
+ falseLabel,
+ valueRequired);
+ } else {
+ // no implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ if (mergedInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ mergedInitStateIndex);
+ }
+ }
+
+ public boolean isCompactableOperation() {
+ return false;
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ if (visitor.visit(this, scope)) {
+ left.traverse(visitor, scope);
+ right.traverse(visitor, scope);
+ }
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java
new file mode 100644
index 0000000000..56f1eedef8
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java
@@ -0,0 +1,371 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.parser.*;
+
+public abstract class AbstractMethodDeclaration
+ extends AstNode
+ implements ProblemSeverities, ReferenceContext {
+ public MethodScope scope;
+ //it is not relevent for constructor but it helps to have the name of the constructor here
+ //which is always the name of the class.....parsing do extra work to fill it up while it do not have to....
+ public char[] selector;
+ public int declarationSourceStart;
+ public int declarationSourceEnd;
+ public int modifiers;
+ public int modifiersSourceStart;
+ public Argument[] arguments;
+ public TypeReference[] thrownExceptions;
+ public Statement[] statements;
+ public int explicitDeclarations;
+ public MethodBinding binding;
+ public boolean ignoreFurtherInvestigation = false;
+ public boolean needFreeReturn = false;
+ public LocalVariableBinding secretReturnValue;
+ static final char[] SecretLocalDeclarationName = " returnValue".toCharArray();
+
+ public int bodyStart;
+ public int bodyEnd = -1;
+ /**
+ * AbstractMethodDeclaration constructor comment.
+ */
+ public AbstractMethodDeclaration() {
+ super();
+ }
+
+ /*
+ * We cause the compilation task to abort to a given extent.
+ */
+ public void abort(int abortLevel) {
+
+ if (scope == null) {
+ throw new AbortCompilation(); // cannot do better
+ }
+
+ CompilationResult compilationResult =
+ scope.referenceCompilationUnit().compilationResult;
+
+ switch (abortLevel) {
+ case AbortCompilation :
+ throw new AbortCompilation(compilationResult);
+ case AbortCompilationUnit :
+ throw new AbortCompilationUnit(compilationResult);
+ case AbortType :
+ throw new AbortType(compilationResult);
+ default :
+ throw new AbortMethod(compilationResult);
+ }
+ }
+
+ public void analyseCode(
+ ClassScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+
+ // starting of the code analysis for methods
+ if (ignoreFurtherInvestigation)
+ return;
+ try {
+ if (binding == null)
+ return;
+ // may be in a non necessary <clinit> for innerclass with static final constant fields
+ if (binding.isAbstract() || binding.isNative())
+ return;
+
+ ExceptionHandlingFlowContext methodContext =
+ new ExceptionHandlingFlowContext(
+ flowContext,
+ this,
+ binding.thrownExceptions,
+ scope,
+ FlowInfo.DeadEnd);
+
+ // propagate to statements
+ if (statements != null) {
+ for (int i = 0, count = statements.length; i < count; i++) {
+ Statement stat;
+ if (!flowInfo.complainIfUnreachable((stat = statements[i]), scope)) {
+ flowInfo = stat.analyseCode(scope, methodContext, flowInfo);
+ }
+ }
+ }
+ // check for missing returning path
+ TypeBinding returnType = binding.returnType;
+ if ((returnType == VoidBinding) || isAbstract()) {
+ needFreeReturn =
+ !((flowInfo == FlowInfo.DeadEnd) || flowInfo.isFakeReachable());
+ } else {
+ if (flowInfo != FlowInfo.DeadEnd) {
+ // special test for empty methods that should return something
+ if ((statements == null) && (returnType != VoidBinding)) {
+ scope.problemReporter().shouldReturn(returnType, this);
+ } else {
+ scope.problemReporter().shouldReturn(
+ returnType,
+ statements[statements.length - 1]);
+ }
+ }
+ }
+ } catch (AbortMethod e) {
+ this.ignoreFurtherInvestigation = true;
+ }
+ }
+
+ public void bindArguments() {
+ //bind and add argument's binding into the scope of the method
+
+ if (arguments != null) {
+ int length = arguments.length;
+ for (int i = 0; i < length; i++) {
+ Argument argument = arguments[i];
+ if (argument.type != null)
+ argument.type.binding = binding.parameters[i];
+ // record the resolved type into the type reference
+ int modifierFlag = argument.modifiers;
+ if ((argument.binding = scope.duplicateName(argument.name)) != null) {
+ //the name already exist....may carry on with the first binding ....
+ scope.problemReporter().redefineArgument(argument);
+ } else {
+ scope.addLocalVariable(
+ argument.binding =
+ new LocalVariableBinding(
+ argument.name,
+ binding.parameters[i],
+ modifierFlag,
+ true));
+ //true stand for argument instead of just local
+ if (isTypeUseDeprecated(binding.parameters[i], scope))
+ scope.problemReporter().deprecatedType(binding.parameters[i], argument.type);
+ argument.binding.declaration = argument;
+ argument.binding.used = binding.isAbstract() | binding.isNative();
+ // by default arguments in abstract/native methods are considered to be used (no complaint is expected)
+ }
+ }
+ }
+ }
+
+ public void checkName() {
+ //look if the name of the method is correct
+ }
+
+ public CompilationResult compilationResult() {
+ return scope.referenceCompilationUnit().compilationResult;
+ }
+
+ /**
+ * Bytecode generation for a method
+ */
+ public void generateCode(ClassScope classScope, ClassFile classFile) {
+ int problemResetPC = 0;
+ if (ignoreFurtherInvestigation) {
+ if (this.binding == null)
+ return; // Handle methods with invalid signature or duplicates
+ int problemsLength;
+ IProblem[] problems =
+ scope.referenceCompilationUnit().compilationResult.getProblems();
+ IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
+ System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
+ classFile.addProblemMethod(this, binding, problemsCopy);
+ return;
+ }
+ try {
+ problemResetPC = classFile.contentsOffset;
+ classFile.generateMethodInfoHeader(binding);
+ int methodAttributeOffset = classFile.contentsOffset;
+ int attributeNumber = classFile.generateMethodInfoAttribute(binding);
+ if ((!binding.isNative()) && (!binding.isAbstract())) {
+ int codeAttributeOffset = classFile.contentsOffset;
+ classFile.generateCodeAttributeHeader();
+ CodeStream codeStream = classFile.codeStream;
+ codeStream.reset(this, classFile);
+ // initialize local positions
+ scope.computeLocalVariablePositions(binding.isStatic() ? 0 : 1, codeStream);
+
+ // arguments initialization for local variable debug attributes
+ if (arguments != null) {
+ for (int i = 0, max = arguments.length; i < max; i++) {
+ LocalVariableBinding argBinding;
+ codeStream.addVisibleLocalVariable(argBinding = arguments[i].binding);
+ argBinding.recordInitializationStartPC(0);
+ }
+ }
+ if (statements != null) {
+ for (int i = 0, max = statements.length; i < max; i++)
+ statements[i].generateCode(scope, codeStream);
+ }
+ if (needFreeReturn) {
+ codeStream.return_();
+ }
+ // local variable attributes
+ codeStream.exitUserScope(scope);
+ codeStream.recordPositionsFrom(0, this);
+ classFile.completeCodeAttribute(codeAttributeOffset);
+ attributeNumber++;
+ }
+ classFile.completeMethodInfo(methodAttributeOffset, attributeNumber);
+
+ // if a problem got reported during code gen, then trigger problem method creation
+ if (ignoreFurtherInvestigation) {
+ throw new AbortMethod(scope.referenceCompilationUnit().compilationResult);
+ }
+ } catch (AbortMethod e) {
+ int problemsLength;
+ IProblem[] problems =
+ scope.referenceCompilationUnit().compilationResult.getProblems();
+ IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
+ System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
+ classFile.addProblemMethod(this, binding, problemsCopy, problemResetPC);
+ }
+ }
+
+ public boolean isAbstract() {
+
+ if (binding != null)
+ return binding.isAbstract();
+ return (modifiers & AccAbstract) != 0;
+ }
+
+ public boolean isClinit() {
+ return false;
+ }
+
+ /**
+ * @return boolean
+ */
+ public boolean isConstructor() {
+ return false;
+ }
+
+ public boolean isDefaultConstructor() {
+ return false;
+ }
+
+ public boolean isInitializationMethod() {
+ return false;
+ }
+
+ public boolean isNative() {
+
+ if (binding != null)
+ return binding.isNative();
+ return (modifiers & AccNative) != 0;
+ }
+
+ public boolean isStatic() {
+ if (binding != null)
+ return binding.isStatic();
+ return (modifiers & AccStatic) != 0;
+ }
+
+ public abstract void parseStatements(
+ Parser parser,
+ CompilationUnitDeclaration unit);
+ //fill up the method body with statement
+ public void resolve(ClassScope upperScope) {
+ if (binding == null) {
+ ignoreFurtherInvestigation = true;
+ return;
+ }
+
+ // ========= abort on fatal error =============
+ try {
+ bindArguments(); //<-- shoud be done at binding/scope creation time
+ checkName();
+
+ // create secret value location
+ scope.addLocalVariable(
+ secretReturnValue =
+ new LocalVariableBinding(
+ SecretLocalDeclarationName,
+ binding.returnType,
+ AccDefault));
+ secretReturnValue.constant = NotAConstant; // not inlinable
+
+ // and then ....deep jump into statements.....
+ if (statements != null) {
+ int i = 0, length = statements.length;
+ while (i < length)
+ statements[i++].resolve(scope);
+ }
+ } catch (AbortMethod e) {
+ this.ignoreFurtherInvestigation = true;
+ }
+ }
+
+ public String returnTypeToString(int tab) {
+ /*slow code */
+
+ return "";
+ }
+
+ public void tagAsHavingErrors() {
+ ignoreFurtherInvestigation = true;
+ }
+
+ public String toString(int tab) {
+ /* slow code */
+
+ String s = tabString(tab);
+ if (modifiers != AccDefault) {
+ s += modifiersString(modifiers);
+ }
+
+ s += returnTypeToString(0);
+
+ s += new String(selector) + "(";
+ if (arguments != null) {
+ for (int i = 0; i < arguments.length; i++) {
+ s += arguments[i].toString(0);
+ if (i != (arguments.length - 1))
+ s = s + ", ";
+ };
+ };
+ s += ")";
+ if (thrownExceptions != null) {
+ s += " throws ";
+ for (int i = 0; i < thrownExceptions.length; i++) {
+ s += thrownExceptions[i].toString(0);
+ if (i != (thrownExceptions.length - 1))
+ s = s + ", ";
+ };
+ };
+
+ s += toStringStatements(tab + 1);
+
+ return s;
+ }
+
+ public String toStringStatements(int tab) {
+ /* slow code */
+
+ if (isAbstract() || (this.modifiers & AccSemicolonBody) != 0)
+ return ";";
+
+ String s = " {";
+ if (statements != null) {
+ for (int i = 0; i < statements.length; i++) {
+ s = s + "\n" + statements[i].toString(tab);
+ if (!(statements[i] instanceof Block)) {
+ s += ";";
+ }
+ }
+ }
+ s += "\n" + tabString(tab == 0 ? 0 : tab - 1) + "}";
+ return s;
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ ClassScope classScope) {
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractVariableDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractVariableDeclaration.java
new file mode 100644
index 0000000000..c34b215865
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractVariableDeclaration.java
@@ -0,0 +1,42 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public abstract class AbstractVariableDeclaration extends Statement {
+ public int modifiers;
+
+ public TypeReference type;
+ public Expression initialization;
+
+ public char[] name;
+
+ public int declarationSourceStart;
+ public int declarationSourceEnd;
+ public int modifiersSourceStart;
+ public AbstractVariableDeclaration() {
+ }
+
+ public String name() {
+
+ return "anonymous storage box";
+ }
+
+ public String toString(int tab) {
+ /*slow code*/
+
+ String s = tabString(tab);
+ if (modifiers != AccDefault) {
+ s += modifiersString(modifiers);
+ }
+ s += type.toString(0) + " " + new String(name());
+ if (initialization != null)
+ s += " = " + initialization.toStringExpression(tab);
+ return s;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
new file mode 100644
index 0000000000..f1f7890fed
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
@@ -0,0 +1,243 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class AllocationExpression
+ extends Expression
+ implements InvocationSite {
+ public TypeReference type;
+ public Expression[] arguments;
+ public MethodBinding binding;
+
+ MethodBinding syntheticAccessor;
+
+ public AllocationExpression() {
+ super();
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+
+ // must verify that exceptions potentially thrown by this expression are caught in the method
+
+ // process arguments
+ if (arguments != null) {
+ for (int i = 0, count = arguments.length; i < count; i++) {
+ flowInfo =
+ arguments[i]
+ .analyseCode(currentScope, flowContext, flowInfo)
+ .unconditionalInits();
+ }
+ }
+ // record some dependency information for exception types
+ int count;
+ ReferenceBinding[] thrownExceptions;
+ if ((count = (thrownExceptions = binding.thrownExceptions).length) != 0) {
+ // check exception handling
+ flowContext.checkExceptionHandlers(
+ thrownExceptions,
+ this,
+ flowInfo,
+ currentScope);
+ }
+ manageEnclosingInstanceAccessIfNecessary(currentScope);
+ manageSyntheticAccessIfNecessary(currentScope);
+ return flowInfo;
+ }
+
+ public Expression enclosingInstance() {
+ return null;
+ }
+
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+
+ int pc = codeStream.position;
+ ReferenceBinding allocatedType = binding.declaringClass;
+
+ codeStream.new_(allocatedType);
+ if (valueRequired) {
+ codeStream.dup();
+ }
+ // better highlight for allocation: display the type individually
+ codeStream.recordPositionsFrom(pc, type);
+
+ // handling innerclass instance allocation
+ if (allocatedType.isNestedType()) {
+ codeStream.generateSyntheticArgumentValues(
+ currentScope,
+ allocatedType,
+ enclosingInstance(),
+ this);
+ }
+ // generate the arguments for constructor
+ if (arguments != null) {
+ for (int i = 0, count = arguments.length; i < count; i++) {
+ arguments[i].generateCode(currentScope, codeStream, true);
+ }
+ }
+ // invoke constructor
+ if (syntheticAccessor == null) {
+ codeStream.invokespecial(binding);
+ } else {
+ // synthetic accessor got some extra arguments appended to its signature, which need values
+ for (int i = 0,
+ max = syntheticAccessor.parameters.length - binding.parameters.length;
+ i < max;
+ i++) {
+ codeStream.aconst_null();
+ }
+ codeStream.invokespecial(syntheticAccessor);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public boolean isSuperAccess() {
+ return false;
+ }
+
+ public boolean isTypeAccess() {
+ return true;
+ }
+
+ /* Inner emulation consists in either recording a dependency
+ * link only, or performing one level of propagation.
+ *
+ * Dependency mechanism is used whenever dealing with source target
+ * types, since by the time we reach them, we might not yet know their
+ * exact need.
+ */
+ public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
+ ReferenceBinding invocationType, allocatedType;
+
+ // perform some emulation work in case there is some and we are inside a local type only
+ if ((allocatedType = binding.declaringClass).isNestedType()
+ && currentScope.enclosingSourceType().isLocalType()) {
+
+ if (allocatedType.isLocalType()) {
+ ((LocalTypeBinding) allocatedType).addInnerEmulationDependent(
+ currentScope,
+ false,
+ false);
+ // request cascade of accesses
+ } else {
+ // locally propagate, since we already now the desired shape for sure
+ currentScope.propagateInnerEmulation(allocatedType, false, false);
+ // request cascade of accesses
+ }
+ }
+ }
+
+ public void manageSyntheticAccessIfNecessary(BlockScope currentScope) {
+ if (binding.isPrivate()
+ && (currentScope.enclosingSourceType() != binding.declaringClass)) {
+
+ if (currentScope
+ .environment()
+ .options
+ .isPrivateConstructorAccessChangingVisibility) {
+ binding.tagForClearingPrivateModifier();
+ // constructor will not be dumped as private, no emulation required thus
+ } else {
+ syntheticAccessor =
+ ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding);
+ currentScope.problemReporter().needToEmulateMethodAccess(binding, this);
+ }
+ }
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ // Propagate the type checking to the arguments, and check if the constructor is defined.
+ constant = NotAConstant;
+ TypeBinding typeBinding = type.resolveType(scope);
+ // will check for null after args are resolved
+
+ // buffering the arguments' types
+ TypeBinding[] argumentTypes = NoParameters;
+ if (arguments != null) {
+ boolean argHasError = false;
+ int length = arguments.length;
+ argumentTypes = new TypeBinding[length];
+ for (int i = 0; i < length; i++)
+ if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null)
+ argHasError = true;
+ if (argHasError)
+ return null;
+ }
+ if (typeBinding == null)
+ return null;
+
+ if (!typeBinding.canBeInstantiated()) {
+ scope.problemReporter().cannotInstantiate(type, typeBinding);
+ return null;
+ }
+ ReferenceBinding allocatedType = (ReferenceBinding) typeBinding;
+ if (!(binding = scope.getConstructor(allocatedType, argumentTypes, this))
+ .isValidBinding()) {
+ if (binding.declaringClass == null)
+ binding.declaringClass = allocatedType;
+ scope.problemReporter().invalidConstructor(this, binding);
+ return null;
+ }
+ if (isMethodUseDeprecated(binding, scope))
+ scope.problemReporter().deprecatedMethod(binding, this);
+
+ if (arguments != null)
+ for (int i = 0; i < arguments.length; i++)
+ arguments[i].implicitWidening(binding.parameters[i], argumentTypes[i]);
+ return allocatedType;
+ }
+
+ public void setDepth(int i) {
+ // ignored
+ }
+
+ public void setFieldIndex(int i) {
+ // ignored
+ }
+
+ public String toStringExpression() {
+ /* slow code */
+
+ String s = "new " + type.toString(0);
+ if (arguments == null)
+ s = s + "()";
+ else {
+ s = s + "(";
+ for (int i = 0; i < arguments.length; i++) {
+ s = s + arguments[i].toStringExpression();
+ if (i == (arguments.length - 1))
+ s = s + ")";
+ else
+ s = s + ", ";
+ };
+ };
+ return s;
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ if (visitor.visit(this, scope)) {
+ int argumentsLength;
+ type.traverse(visitor, scope);
+ if (arguments != null) {
+ argumentsLength = arguments.length;
+ for (int i = 0; i < argumentsLength; i++)
+ arguments[i].traverse(visitor, scope);
+ }
+ }
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AnonymousLocalTypeDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AnonymousLocalTypeDeclaration.java
new file mode 100644
index 0000000000..a4c180cd2d
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AnonymousLocalTypeDeclaration.java
@@ -0,0 +1,165 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+public class AnonymousLocalTypeDeclaration extends LocalTypeDeclaration {
+ //a temporal default name
+ public static final char[] ANONYMOUS_EMPTY_NAME = new char[] {
+ };
+
+ public QualifiedAllocationExpression allocation;
+ public AnonymousLocalTypeDeclaration() {
+ super();
+ modifiers = AccDefault;
+ name = ANONYMOUS_EMPTY_NAME;
+ } // use a default name in order to th name lookup
+
+ // to operate juat like a regular type (which has a name)
+ //without checking systematically if the naem is null ....
+ public MethodBinding createsInternalConstructorWithBinding(MethodBinding inheritedConstructorBinding) {
+ //Add to method'set, the default constuctor that just recall the
+ //super constructor with the same arguments
+
+ String baseName = "$anonymous";
+ TypeBinding[] argumentTypes = inheritedConstructorBinding.parameters;
+ int argumentsLength = argumentTypes.length;
+ //the constructor
+ ConstructorDeclaration cd = new ConstructorDeclaration();
+ cd.selector = new char[] { 'x' }; //no maining
+ cd.sourceStart = sourceStart;
+ cd.sourceEnd = sourceEnd;
+ cd.modifiers = modifiers & AccVisibilityMASK;
+
+ if (argumentsLength > 0) {
+ Argument[] arguments = (cd.arguments = new Argument[argumentsLength]);
+ for (int i = argumentsLength; --i >= 0;) {
+ arguments[i] = new Argument((baseName + i).toCharArray(), 0L,
+ //toCharArray() could be optimized ....
+ null, //no meaning (a TypeReference)
+ AccDefault);
+ }
+ }
+
+ //the super call inside the constructor
+ cd.constructorCall =
+ new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper);
+ cd.constructorCall.sourceStart = sourceStart;
+ cd.constructorCall.sourceEnd = sourceEnd;
+
+ if (argumentsLength > 0) {
+ Expression[] args;
+ args = cd.constructorCall.arguments = new Expression[argumentsLength];
+ for (int i = argumentsLength; --i >= 0;) {
+ args[i] = new SingleNameReference((baseName + i).toCharArray(), 0L);
+ }
+ }
+
+ //adding the constructor in the methods list
+ if (methods == null) {
+ methods = new AbstractMethodDeclaration[] { cd };
+ } else {
+ AbstractMethodDeclaration[] newMethods;
+ System.arraycopy(
+ methods,
+ 0,
+ newMethods = new AbstractMethodDeclaration[methods.length + 1],
+ 1,
+ methods.length);
+ newMethods[0] = cd;
+ methods = newMethods;
+ }
+
+ //============BINDING UPDATE==========================
+ cd.binding = new MethodBinding(cd.modifiers, //methodDeclaration
+ argumentsLength == 0 ? NoParameters : argumentTypes, //arguments bindings
+ inheritedConstructorBinding.thrownExceptions, //exceptions
+ binding); //declaringClass
+ cd.scope = new MethodScope(scope, this, true);
+ cd.bindArguments();
+ cd.constructorCall.resolve(cd.scope);
+ if (binding.methods == null) {
+ binding.methods = new MethodBinding[] { cd.binding };
+ } else {
+ MethodBinding[] newMethods;
+ System.arraycopy(
+ binding.methods,
+ 0,
+ newMethods = new MethodBinding[binding.methods.length + 1],
+ 1,
+ binding.methods.length);
+ newMethods[0] = cd.binding;
+ binding.methods = newMethods;
+ }
+ //===================================================
+
+ return cd.binding;
+
+ }
+
+ public void resolve(BlockScope scope) {
+ // scope and binding are provided in updateBindingSuperclass
+
+ resolve();
+ updateMaxFieldCount();
+ }
+
+ public String toString(int tab) {
+ /*slow code */
+
+ return toStringBody(tab);
+ }
+
+ /**
+ * Iteration for a local anonymous innertype
+ *
+ */
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ if (ignoreFurtherInvestigation)
+ return;
+ try {
+ if (visitor.visit(this, blockScope)) {
+
+ int fieldsLength;
+ int methodsLength;
+ int memberTypesLength;
+
+ // <superclass> is bound to the actual type from the allocation expression
+ // therefore it has already been iterated at this point.
+
+ if (memberTypes != null) {
+ memberTypesLength = memberTypes.length;
+ for (int i = 0; i < memberTypesLength; i++)
+ memberTypes[i].traverse(visitor, scope);
+ }
+ if (fields != null) {
+ fieldsLength = fields.length;
+ for (int i = 0; i < fieldsLength; i++) {
+ FieldDeclaration field;
+ if ((field = fields[i]).isStatic()) {
+ // local type cannot have static fields
+ } else {
+ field.traverse(visitor, initializerScope);
+ }
+ }
+ }
+ if (methods != null) {
+ methodsLength = methods.length;
+ for (int i = 0; i < methodsLength; i++)
+ methods[i].traverse(visitor, scope);
+ }
+ }
+ visitor.endVisit(this, blockScope);
+ } catch (AbortType e) {
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java
new file mode 100644
index 0000000000..f86f419035
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java
@@ -0,0 +1,71 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class Argument extends LocalDeclaration {
+ public Argument(char[] name, long posNom, TypeReference tr, int modifiers) {
+ super(null, name, (int) (posNom >>> 32), (int) (posNom & 0xFFFFFFFFL));
+ this.modifiers = modifiers;
+ type = tr;
+ }
+
+ public void resolve(BlockScope scope) {
+ // an argument may be final ==> cannot be assigned
+
+ super.resolve(scope);
+ binding.isArgument = true;
+ binding.used = true;
+ }
+
+ public TypeBinding resolveForCatch(BlockScope scope) {
+ // resolution on an argument of a catch clause
+ // provide the scope with a side effect : insertion of a LOCAL
+ // that represents the argument. The type must be from JavaThrowable
+
+ TypeBinding tb = type.resolveTypeExpecting(scope, scope.getJavaLangThrowable());
+ if (tb == null)
+ return null;
+ if ((binding = scope.duplicateName(name)) != null) {
+ // the name already exists....may carry on with the first binding ....
+ scope.problemReporter().redefineArgument(this);
+ return null;
+ }
+ binding = new LocalVariableBinding(this, tb, modifiers);
+ scope.addLocalVariable(binding);
+ binding.constant = NotAConstant;
+ return tb;
+ }
+
+ public String toString(int tab) {
+ /* slow code */
+
+ String s = "";
+ if (modifiers != AccDefault) {
+ s += modifiersString(modifiers);
+ }
+ if (type == null) {
+ s += "<no type> ";
+ } else {
+ s += type.toString(tab) + " ";
+ }
+ s += new String(name);
+ return s;
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ if (visitor.visit(this, scope)) {
+ if (type != null)
+ type.traverse(visitor, scope);
+ if (initialization != null)
+ initialization.traverse(visitor, scope);
+ }
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java
new file mode 100644
index 0000000000..ff0601c82c
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java
@@ -0,0 +1,178 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class ArrayAllocationExpression extends Expression {
+ public TypeReference type;
+
+ //dimensions.length gives the number of dimensions, but the
+ // last ones may be nulled as in new int[4][5][][]
+ public Expression[] dimensions;
+ public ArrayInitializer initializer;
+
+ public ArrayBinding arrayTb;
+ /**
+ * ArrayAllocationExpression constructor comment.
+ */
+ public ArrayAllocationExpression() {
+ super();
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ for (int i = 0, max = dimensions.length; i < max; i++) {
+ Expression dim;
+ if ((dim = dimensions[i]) != null) {
+ flowInfo = dim.analyseCode(currentScope, flowContext, flowInfo);
+ }
+ }
+ if (initializer != null) {
+ return initializer.analyseCode(currentScope, flowContext, flowInfo);
+ } else {
+ return flowInfo;
+ }
+ }
+
+ /**
+ * Code generation for a array allocation expression
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+
+ int pc = codeStream.position;
+ ArrayBinding arrayBinding;
+
+ if (initializer != null) {
+ initializer.generateCode(currentScope, codeStream, valueRequired);
+ return;
+ }
+
+ int nonNullDimensionsLength = 0;
+ for (int i = 0, max = dimensions.length; i < max; i++)
+ if (dimensions[i] != null) {
+ dimensions[i].generateCode(currentScope, codeStream, true);
+ nonNullDimensionsLength++;
+ }
+
+ // Generate a sequence of bytecodes corresponding to an array allocation
+ if ((arrayTb.isArrayType())
+ && ((arrayBinding = (ArrayBinding) arrayTb).dimensions == 1)) {
+ // Mono-dimensional array
+ codeStream.newArray(currentScope, arrayBinding);
+ } else {
+ // Multi-dimensional array
+ codeStream.multianewarray(arrayTb, nonNullDimensionsLength);
+ }
+
+ if (valueRequired) {
+ codeStream.generateImplicitConversion(implicitConversion);
+ } else {
+ codeStream.pop();
+ }
+
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ // Build an array type reference using the current dimensions
+ // The parser does not check for the fact that dimension may be null
+ // only at the -end- like new int [4][][]. The parser allows new int[][4][]
+ // so this must be checked here......(this comes from a reduction to LL1 grammar)
+
+ TypeBinding referenceTb = type.resolveType(scope);
+ // will check for null after dimensions are checked
+ constant = Constant.NotAConstant;
+ if (referenceTb == VoidBinding) {
+ scope.problemReporter().cannotAllocateVoidArray(this);
+ referenceTb = null; // will return below
+ }
+
+ // check the validity of the dimension syntax (and test for all null dimensions)
+ int lengthDim = -1;
+ for (int i = dimensions.length; --i >= 0;) {
+ if (dimensions[i] != null) {
+ if (lengthDim == -1)
+ lengthDim = i;
+ } else
+ if (lengthDim != -1) {
+ // should not have an empty dimension before an non-empty one
+ scope.problemReporter().incorrectLocationForEmptyDimension(this, i);
+ return null;
+ }
+ }
+ if (referenceTb == null)
+ return null;
+
+ // lengthDim == -1 says if all dimensions are nulled
+ // when an initializer is given, no dimension must be specified
+ if (initializer == null) {
+ if (lengthDim == -1) {
+ scope.problemReporter().mustDefineDimensionsOrInitializer(this);
+ return null;
+ }
+ } else
+ if (lengthDim != -1) {
+ scope.problemReporter().cannotDefineDimensionsAndInitializer(this);
+ return null;
+ }
+
+ // dimensions resolution
+ for (int i = 0; i <= lengthDim; i++) {
+ TypeBinding dimTb = dimensions[i].resolveTypeExpecting(scope, IntBinding);
+ if (dimTb == null)
+ return null;
+ dimensions[i].implicitWidening(IntBinding, dimTb);
+ }
+
+ // building the array binding
+ arrayTb = scope.createArray(referenceTb, dimensions.length);
+
+ // check the initializer
+ if (initializer != null)
+ if ((initializer.resolveTypeExpecting(scope, arrayTb)) != null)
+ initializer.binding = arrayTb;
+ return arrayTb;
+ }
+
+ public String toStringExpression() {
+ /* slow code */
+
+ String s = "new " + type.toString(0);
+ for (int i = 0; i < dimensions.length; i++) {
+ if (dimensions[i] == null)
+ s = s + "[]";
+ else
+ s = s + "[" + dimensions[i].toStringExpression() + "]";
+ }
+ if (initializer != null)
+ s = s + initializer.toStringExpression();
+ return s;
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ if (visitor.visit(this, scope)) {
+ int dimensionsLength = dimensions.length;
+ type.traverse(visitor, scope);
+ for (int i = 0; i < dimensionsLength; i++) {
+ if (dimensions[i] != null)
+ dimensions[i].traverse(visitor, scope);
+ }
+ if (initializer != null)
+ initializer.traverse(visitor, scope);
+ }
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java
new file mode 100644
index 0000000000..32ac5b5077
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java
@@ -0,0 +1,195 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class ArrayInitializer extends Expression {
+ public Expression[] expressions;
+ public ArrayBinding binding; //the type of the { , , , }
+
+ /**
+ * ArrayInitializer constructor comment.
+ */
+ public ArrayInitializer() {
+ super();
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ if (expressions != null) {
+ for (int i = 0, max = expressions.length; i < max; i++) {
+ flowInfo =
+ expressions[i]
+ .analyseCode(currentScope, flowContext, flowInfo)
+ .unconditionalInits();
+ }
+ }
+ return flowInfo;
+ }
+
+ /**
+ * Code generation for a array initializer
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ // Flatten the values and compute the dimensions, by iterating in depth into nested array initializers
+
+ int pc = codeStream.position;
+ int expressionLength = (expressions == null) ? 0 : expressions.length;
+ codeStream.generateInlinedValue(expressionLength);
+ codeStream.newArray(currentScope, binding);
+ if (expressions != null) {
+ // binding is an ArrayType, so I can just deal with the dimension
+ int elementsTypeID = binding.dimensions > 1 ? -1 : binding.leafComponentType.id;
+ for (int i = 0; i < expressionLength; i++) {
+ Expression expr;
+ if ((expr = expressions[i]).constant != NotAConstant) {
+ switch (elementsTypeID) { // filter out initializations to default values
+ case T_int :
+ case T_short :
+ case T_byte :
+ case T_char :
+ case T_float :
+ case T_long :
+ case T_double :
+ if (expr.constant.doubleValue() != 0) {
+ codeStream.dup();
+ codeStream.generateInlinedValue(i);
+ expr.generateCode(currentScope, codeStream, true);
+ codeStream.arrayAtPut(elementsTypeID, false);
+ }
+ break;
+ case T_boolean :
+ if (expr.constant.booleanValue() != false) {
+ codeStream.dup();
+ codeStream.generateInlinedValue(i);
+ expr.generateCode(currentScope, codeStream, true);
+ codeStream.arrayAtPut(elementsTypeID, false);
+ }
+ break;
+ default :
+ if (expr.constant != NullConstant.Default) {
+ codeStream.dup();
+ codeStream.generateInlinedValue(i);
+ expr.generateCode(currentScope, codeStream, true);
+ codeStream.arrayAtPut(elementsTypeID, false);
+ }
+ }
+ } else {
+ codeStream.dup();
+ codeStream.generateInlinedValue(i);
+ expr.generateCode(currentScope, codeStream, true);
+ codeStream.arrayAtPut(elementsTypeID, false);
+ }
+ }
+ }
+ if (!valueRequired) {
+ codeStream.pop();
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public TypeBinding resolveTypeExpecting(
+ BlockScope scope,
+ TypeBinding expectedTb) {
+ // Array initializers can only occur on the right hand side of an assignment
+ // expression, therefore the expected type contains the valid information
+ // concerning the type that must be enforced by the elements of the array initializer.
+
+ // this method is recursive... (the test on isArrayType is the stop case)
+
+ constant = NotAConstant;
+ if (expectedTb.isArrayType()) {
+ binding = (ArrayBinding) expectedTb;
+ if (expressions == null)
+ return binding;
+ TypeBinding expectedElementsTb = binding.elementsType(scope);
+ if (expectedElementsTb.isBaseType()) {
+ for (int i = 0, length = expressions.length; i < length; i++) {
+ Expression expression = expressions[i];
+ TypeBinding expressionTb =
+ (expression instanceof ArrayInitializer)
+ ? expression.resolveTypeExpecting(scope, expectedElementsTb)
+ : expression.resolveType(scope);
+ if (expressionTb == null)
+ return null;
+
+ // Compile-time conversion required?
+ if (expression
+ .isConstantValueOfTypeAssignableToType(expressionTb, expectedElementsTb)) {
+ expression.implicitWidening(expectedElementsTb, expressionTb);
+ } else
+ if (BaseTypeBinding.isWidening(expectedElementsTb.id, expressionTb.id)) {
+ expression.implicitWidening(expectedElementsTb, expressionTb);
+ } else {
+ scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
+ expression,
+ expressionTb,
+ expectedElementsTb);
+ return null;
+ }
+ }
+ } else {
+ for (int i = 0, length = expressions.length; i < length; i++)
+ if (expressions[i].resolveTypeExpecting(scope, expectedElementsTb) == null)
+ return null;
+ }
+ return binding;
+ }
+
+ TypeBinding elementTb =
+ (expressions == null)
+ ? scope.getJavaLangObject()
+ : expressions[0].resolveType(scope);
+ if (elementTb != null) {
+ TypeBinding probableTb = scope.createArray(elementTb, 1);
+ scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
+ this,
+ probableTb,
+ expectedTb);
+ }
+ return null;
+ }
+
+ public String toStringExpression() {
+ /* slow code */
+
+ String s = "{";
+ if (expressions != null) {
+ int j = 20;
+ for (int i = 0; i < expressions.length; i++) {
+ s = s + expressions[i].toStringExpression() + ",";
+ j--;
+ if (j == 0) {
+ s = s + "\n ";
+ j = 20;
+ }
+ }
+ };
+ s = s + "}";
+ return s;
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ if (visitor.visit(this, scope)) {
+ if (expressions != null) {
+ int expressionsLength = expressions.length;
+ for (int i = 0; i < expressionsLength; i++)
+ expressions[i].traverse(visitor, scope);
+ }
+ }
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayQualifiedTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayQualifiedTypeReference.java
new file mode 100644
index 0000000000..09926086bf
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayQualifiedTypeReference.java
@@ -0,0 +1,58 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class ArrayQualifiedTypeReference extends QualifiedTypeReference {
+ int dimensions;
+ public ArrayQualifiedTypeReference(char[][] sources, int dim, long[] poss) {
+ super(sources, poss);
+ dimensions = dim;
+ }
+
+ public ArrayQualifiedTypeReference(
+ char[][] sources,
+ TypeBinding tb,
+ int dim,
+ long[] poss) {
+ super(sources, tb, poss);
+ dimensions = dim;
+ }
+
+ public int dimensions() {
+ return dimensions;
+ }
+
+ public TypeBinding getTypeBinding(Scope scope) {
+ if (binding != null)
+ return binding;
+ return scope.createArray(scope.getType(tokens), dimensions);
+ }
+
+ public String toStringExpression(int tab) {
+ /* slow speed */
+
+ String s = super.toStringExpression(tab);
+ if (dimensions == 1)
+ return s + "[]";
+ for (int i = 1; i <= dimensions; i++)
+ s = s + "[]";
+ return s;
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ visitor.visit(this, scope);
+ visitor.endVisit(this, scope);
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, ClassScope scope) {
+ visitor.visit(this, scope);
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java
new file mode 100644
index 0000000000..74bb3a4e21
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java
@@ -0,0 +1,182 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class ArrayReference extends Reference {
+ public Expression receiver;
+ public Expression position;
+
+ public TypeBinding arrayElementBinding;
+ public ArrayReference(Expression rec, Expression pos) {
+ this.receiver = rec;
+ this.position = pos;
+ sourceStart = rec.sourceStart;
+ }
+
+ public FlowInfo analyseAssignment(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo,
+ Assignment assignment,
+ boolean compoundAssignment) {
+ if (assignment.expression == null) {
+ return analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
+ } else {
+ return assignment
+ .expression
+ .analyseCode(
+ currentScope,
+ flowContext,
+ analyseCode(currentScope, flowContext, flowInfo).unconditionalInits())
+ .unconditionalInits();
+ }
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ return position.analyseCode(
+ currentScope,
+ flowContext,
+ receiver.analyseCode(currentScope, flowContext, flowInfo));
+ }
+
+ public void generateAssignment(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Assignment assignment,
+ boolean valueRequired) {
+ receiver.generateCode(currentScope, codeStream, true);
+ position.generateCode(currentScope, codeStream, true);
+ assignment.expression.generateCode(currentScope, codeStream, true);
+ codeStream.arrayAtPut(arrayElementBinding.id, valueRequired);
+ if (valueRequired) {
+ codeStream.generateImplicitConversion(assignment.implicitConversion);
+ }
+ }
+
+ /**
+ * Code generation for a array reference
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ receiver.generateCode(currentScope, codeStream, true);
+ position.generateCode(currentScope, codeStream, true);
+ codeStream.arrayAt(arrayElementBinding.id);
+ // Generating code for the potential runtime type checking
+ if (valueRequired) {
+ codeStream.generateImplicitConversion(implicitConversion);
+ } else {
+ if (arrayElementBinding == LongBinding
+ || arrayElementBinding == DoubleBinding) {
+ codeStream.pop2();
+ } else {
+ codeStream.pop();
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public void generateCompoundAssignment(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Expression expression,
+ int operator,
+ int assignmentImplicitConversion,
+ boolean valueRequired) {
+ receiver.generateCode(currentScope, codeStream, true);
+ position.generateCode(currentScope, codeStream, true);
+ codeStream.dup2();
+ codeStream.arrayAt(arrayElementBinding.id);
+ int operationTypeID;
+ if ((operationTypeID = implicitConversion >> 4) == T_String) {
+ codeStream.generateStringAppend(currentScope, null, expression);
+ } else {
+ // promote the array reference to the suitable operation type
+ codeStream.generateImplicitConversion(implicitConversion);
+ // generate the increment value (will by itself be promoted to the operation value)
+ if (expression == IntLiteral.One) { // prefix operation
+ codeStream.generateConstant(expression.constant, implicitConversion);
+ } else {
+ expression.generateCode(currentScope, codeStream, true);
+ }
+ // perform the operation
+ codeStream.sendOperator(operator, operationTypeID);
+ // cast the value back to the array reference type
+ codeStream.generateImplicitConversion(assignmentImplicitConversion);
+ }
+ codeStream.arrayAtPut(arrayElementBinding.id, valueRequired);
+ }
+
+ public void generatePostIncrement(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ CompoundAssignment postIncrement,
+ boolean valueRequired) {
+ receiver.generateCode(currentScope, codeStream, true);
+ position.generateCode(currentScope, codeStream, true);
+ codeStream.dup2();
+ codeStream.arrayAt(arrayElementBinding.id);
+ if (valueRequired) {
+ if ((arrayElementBinding == LongBinding)
+ || (arrayElementBinding == DoubleBinding)) {
+ codeStream.dup2_x2();
+ } else {
+ codeStream.dup_x2();
+ }
+ }
+ codeStream.generateConstant(
+ postIncrement.expression.constant,
+ implicitConversion);
+ codeStream.sendOperator(postIncrement.operator, arrayElementBinding.id);
+ codeStream.generateImplicitConversion(
+ postIncrement.assignmentImplicitConversion);
+ codeStream.arrayAtPut(arrayElementBinding.id, false);
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ constant = Constant.NotAConstant;
+ TypeBinding arrayTb = receiver.resolveType(scope);
+ if (arrayTb == null)
+ return null;
+ if (!arrayTb.isArrayType()) {
+ scope.problemReporter().referenceMustBeArrayTypeAt(arrayTb, this);
+ return null;
+ }
+ TypeBinding positionTb = position.resolveTypeExpecting(scope, IntBinding);
+ if (positionTb == null)
+ return null;
+ position.implicitWidening(IntBinding, positionTb);
+ return arrayElementBinding = ((ArrayBinding) arrayTb).elementsType(scope);
+ }
+
+ public String toStringExpression() {
+ /* slow code */
+
+ return receiver.toStringExpression()
+ + "["
+ + position.toStringExpression()
+ + "]";
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ if (visitor.visit(this, scope)) {
+ receiver.traverse(visitor, scope);
+ position.traverse(visitor, scope);
+ }
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayTypeReference.java
new file mode 100644
index 0000000000..3a870a5c13
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayTypeReference.java
@@ -0,0 +1,55 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class ArrayTypeReference extends SingleTypeReference {
+ public int dimensions;
+ /**
+ * ArrayTypeReference constructor comment.
+ * @param source char[]
+ * @param dim int
+ * @param pos int
+ */
+ public ArrayTypeReference(char[] source, int dim, long pos) {
+ super(source, pos);
+ dimensions = dim;
+ }
+
+ public ArrayTypeReference(char[] source, TypeBinding tb, int dim, long pos) {
+ super(source, tb, pos);
+ dimensions = dim;
+ }
+
+ public int dimensions() {
+ return dimensions;
+ }
+
+ public TypeBinding getTypeBinding(Scope scope) {
+ if (binding != null)
+ return binding;
+ return scope.createArray(scope.getType(token), dimensions);
+ }
+
+ public String toStringExpression(int tab) {
+ /* slow speed */
+
+ String s = super.toStringExpression(tab);
+ if (dimensions == 1)
+ return s + "[]";
+ for (int i = 1; i <= dimensions; i++)
+ s = s + "[]";
+ return s;
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ visitor.visit(this, scope);
+ visitor.endVisit(this, scope);
+ }
+
+}
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
new file mode 100644
index 0000000000..9b1041b931
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java
@@ -0,0 +1,144 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class Assignment extends Expression {
+ public Reference lhs;
+ public Expression expression;
+ public Assignment(Expression lhs, Expression expression) {
+ //lhs is always a reference by construction ,
+ //but is build as an expression ==> the checkcast cannot fail
+
+ this.lhs = (Reference) lhs;
+ this.expression = expression;
+
+ sourceStart = lhs.sourceStart;
+ sourceEnd = expression.sourceEnd;
+
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ // record setting a variable: various scenarii are possible, setting an array reference,
+ // a field reference, a blank final field reference, a field of an enclosing instance or
+ // just a local variable.
+
+ return lhs
+ .analyseAssignment(currentScope, flowContext, flowInfo, this, false)
+ .unconditionalInits();
+ }
+
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+
+ // various scenarii are possible, setting an array reference,
+ // a field reference, a blank final field reference, a field of an enclosing instance or
+ // just a local variable.
+
+ int pc = codeStream.position;
+ lhs.generateAssignment(currentScope, codeStream, this, valueRequired);
+ // variable may have been optimized out
+ // the lhs is responsible to perform the implicitConversion generation for the assignment since optimized for unused local assignment.
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ // due to syntax lhs may be only a NameReference, a FieldReference or an ArrayReference
+
+ constant = NotAConstant;
+ TypeBinding lhsTb = lhs.resolveType(scope);
+ TypeBinding expressionTb = expression.resolveType(scope);
+ if (lhsTb == null || expressionTb == null)
+ return null;
+
+ // Compile-time conversion of base-types : implicit narrowing integer into byte/short/character
+ // may require to widen the rhs expression at runtime
+ if ((expression.isConstantValueOfTypeAssignableToType(expressionTb, lhsTb)
+ || (lhsTb.isBaseType() && BaseTypeBinding.isWidening(lhsTb.id, expressionTb.id)))
+ || (scope.areTypesCompatible(expressionTb, lhsTb))) {
+ expression.implicitWidening(lhsTb, expressionTb);
+ return lhsTb;
+ }
+ scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
+ expression,
+ expressionTb,
+ lhsTb);
+ return null;
+
+ /*------------code deported to the flow analysis-------------------
+ if (lhs.isFieldReference()) {
+ // cover also the case of a nameReference that refers to a field...(of course !...)
+ if (lhsTb.isFinal()) {
+ // if the field is final, then the assignment may be done only in constructors/initializers
+ // (this does not insure that the assignment is valid....the flow analysis will tell so)
+ if (scope.enclosingType() == lhs.fieldBinding().declaringClass) {
+ scope.problemReporter().cannotAssignToFinalField(this, lhs.fieldBinding());
+ return null;
+ }
+ if (!scope.enclosingMethod().isConstructorOrInintilizer()) {
+ scope.problemReporter().cannotAssignToFinalField(this, lhs.fieldBinding());
+ return null;
+ }
+ }
+ }
+ -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- * /
+
+ /*----------------------------------------------------------------
+ the code that test if the local is an outer local (it is by definition final)
+ and thus cannot be assigned , has been moved to flow analysis
+ ------------------------------------------------------------------*/
+
+ /*-----------------------------------------------------------------
+ The code that detect the a.b = a.b + 1 ; is done by the flow analysis too
+ -------------------------------------------------------------------*/
+ }
+
+ public String toString(int tab) {
+ /* slow code*/
+
+ //no () when used as a statement
+
+ return tabString(tab) + toStringExpressionNoParenthesis();
+ }
+
+ public String toStringExpression() {
+ /* slow code*/
+
+ //subclass redefine toStringExpressionNoParenthesis()
+
+ return "(" + toStringExpressionNoParenthesis() + ")";
+ }
+
+ public String toStringExpressionNoParenthesis() {
+
+ return lhs.toStringExpression()
+ + " "
+ + "="
+ + ((expression.constant != null)
+ && (expression.constant != NotAConstant)
+ ? " /*cst:" + expression.constant.toString() + "*/ "
+ : " ")
+ + expression.toStringExpression();
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ if (visitor.visit(this, scope)) {
+ lhs.traverse(visitor, scope);
+ expression.traverse(visitor, scope);
+ }
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AstNode.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AstNode.java
new file mode 100644
index 0000000000..b57fb728df
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AstNode.java
@@ -0,0 +1,139 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+
+public abstract class AstNode
+ implements BaseTypes, CompilerModifiers, TypeConstants, TypeIds {
+ public int sourceStart, sourceEnd;
+
+ //some global provision for the hierarchy
+ public final static Constant NotAConstant = Constant.NotAConstant;
+
+ /**
+ * AstNode constructor comment.
+ */
+ public AstNode() {
+ super();
+ }
+
+ public boolean cannotReturn() {
+ return false;
+ }
+
+ public AstNode concreteStatement() {
+ return this;
+ }
+
+ /* Answer true if the field use is considered deprecated.
+ * An access in the same compilation unit is allowed.
+ */
+
+ public final boolean isFieldUseDeprecated(FieldBinding field, Scope scope) {
+ return field.isViewedAsDeprecated()
+ && !scope.isDefinedInSameUnit(field.declaringClass);
+ }
+
+ /* Answer true if the method use is considered deprecated.
+ * An access in the same compilation unit is allowed.
+ */
+
+ public final boolean isMethodUseDeprecated(MethodBinding method, Scope scope) {
+ return method.isViewedAsDeprecated()
+ && !scope.isDefinedInSameUnit(method.declaringClass);
+ }
+
+ public boolean isSuper() {
+
+ return false;
+ }
+
+ public boolean isThis() {
+ return false;
+ }
+
+ /* Answer true if the type use is considered deprecated.
+ * An access in the same compilation unit is allowed.
+ */
+
+ public final boolean isTypeUseDeprecated(TypeBinding type, Scope scope) {
+ if (type.isArrayType())
+ type = ((ArrayBinding) type).leafComponentType;
+ if (type.isBaseType())
+ return false;
+
+ ReferenceBinding refType = (ReferenceBinding) type;
+ return refType.isViewedAsDeprecated() && !scope.isDefinedInSameUnit(refType);
+ }
+
+ public static String modifiersString(int modifiers) {
+
+ String s = "";
+ if ((modifiers & AccPublic) != 0)
+ s = s + "public ";
+ if ((modifiers & AccPrivate) != 0)
+ s = s + "private ";
+ if ((modifiers & AccProtected) != 0)
+ s = s + "protected ";
+ if ((modifiers & AccStatic) != 0)
+ s = s + "static ";
+ if ((modifiers & AccFinal) != 0)
+ s = s + "final ";
+ if ((modifiers & AccSynchronized) != 0)
+ s = s + "synchronized ";
+ if ((modifiers & AccVolatile) != 0)
+ s = s + "volatile ";
+ if ((modifiers & AccTransient) != 0)
+ s = s + "transient ";
+ if ((modifiers & AccNative) != 0)
+ s = s + "native ";
+ if ((modifiers & AccAbstract) != 0)
+ s = s + "abstract ";
+ return s;
+ }
+
+ /** @Deprecated
+ */
+ public int sourceEnd() {
+ return sourceEnd;
+ }
+
+ /** @Deprecated
+ */
+ public int sourceStart() {
+ return sourceStart;
+ }
+
+ public static String tabString(int tab) {
+ /*slow code*/
+
+ String s = "";
+ for (int i = tab; i > 0; i--)
+ s = s + " ";
+ return s;
+ }
+
+ public String toString() {
+ /* low speed */
+
+ return toString(0);
+ }
+
+ public String toString(int tab) {
+ /* low speed */
+
+ /*If reach here fetchs the default display*/
+ return "****" + super.toString() + "****";
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java
new file mode 100644
index 0000000000..392e0421f4
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java
@@ -0,0 +1,1743 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class BinaryExpression extends OperatorExpression {
+ public Expression left, right;
+ public Constant optimizedBooleanConstant;
+
+ public BinaryExpression(Expression left, Expression right, int operator) {
+ this.left = left;
+ this.right = right;
+ this.bits |= operator << OperatorSHIFT; // encode operator
+ this.sourceStart = left.sourceStart;
+ this.sourceEnd = right.sourceEnd;
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ return right
+ .analyseCode(
+ currentScope,
+ flowContext,
+ left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits())
+ .unconditionalInits();
+ }
+
+ public void computeConstant(BlockScope scope, int leftId, int rightId) {
+
+ //compute the constant when valid
+ if ((left.constant != Constant.NotAConstant)
+ && (right.constant != Constant.NotAConstant)) {
+ try {
+ constant =
+ Constant.computeConstantOperation(
+ left.constant,
+ leftId,
+ (bits & OperatorMASK) >> OperatorSHIFT,
+ right.constant,
+ rightId);
+ } catch (ArithmeticException e) {
+ constant = Constant.NotAConstant;
+ // 1.2 no longer throws an exception at compile-time
+ //scope.problemReporter().compileTimeConstantThrowsArithmeticException(this);
+ }
+ } else {
+ constant = Constant.NotAConstant;
+ //add some work for the boolean operators & |
+ optimizedBooleanConstant(
+ leftId,
+ (bits & OperatorMASK) >> OperatorSHIFT,
+ rightId);
+ }
+ }
+
+ public Constant conditionalConstant() {
+ return optimizedBooleanConstant == null ? constant : optimizedBooleanConstant;
+ }
+
+ /**
+ * Code generation for a binary operation
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ Label falseLabel, endLabel;
+ if (constant != Constant.NotAConstant) {
+ if (valueRequired)
+ codeStream.generateConstant(constant, implicitConversion);
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ bits |= OnlyValueRequiredMASK;
+ switch ((bits & OperatorMASK) >> OperatorSHIFT) {
+ case PLUS :
+ switch (bits & ReturnTypeIDMASK) {
+ case T_String :
+ codeStream.generateStringAppend(currentScope, left, right);
+ if (!valueRequired)
+ codeStream.pop();
+ break;
+ case T_int :
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.iadd();
+ break;
+ case T_long :
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.ladd();
+ break;
+ case T_double :
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.dadd();
+ break;
+ case T_float :
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.fadd();
+ break;
+ }
+ break;
+ case MINUS :
+ switch (bits & ReturnTypeIDMASK) {
+ case T_int :
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.isub();
+ break;
+ case T_long :
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.lsub();
+ break;
+ case T_double :
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.dsub();
+ break;
+ case T_float :
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.fsub();
+ break;
+ }
+ break;
+ case MULTIPLY :
+ switch (bits & ReturnTypeIDMASK) {
+ case T_int :
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.imul();
+ break;
+ case T_long :
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.lmul();
+ break;
+ case T_double :
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.dmul();
+ break;
+ case T_float :
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.fmul();
+ break;
+ }
+ break;
+ case DIVIDE :
+ switch (bits & ReturnTypeIDMASK) {
+ case T_int :
+ left.generateCode(currentScope, codeStream, true);
+ right.generateCode(currentScope, codeStream, true);
+ codeStream.idiv();
+ if (!valueRequired)
+ codeStream.pop();
+ break;
+ case T_long :
+ left.generateCode(currentScope, codeStream, true);
+ right.generateCode(currentScope, codeStream, true);
+ codeStream.ldiv();
+ if (!valueRequired)
+ codeStream.pop2();
+ break;
+ case T_double :
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.ddiv();
+ break;
+ case T_float :
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.fdiv();
+ break;
+ }
+ break;
+ case REMAINDER :
+ switch (bits & ReturnTypeIDMASK) {
+ case T_int :
+ left.generateCode(currentScope, codeStream, true);
+ right.generateCode(currentScope, codeStream, true);
+ codeStream.irem();
+ if (!valueRequired)
+ codeStream.pop();
+ break;
+ case T_long :
+ left.generateCode(currentScope, codeStream, true);
+ right.generateCode(currentScope, codeStream, true);
+ codeStream.lrem();
+ if (!valueRequired)
+ codeStream.pop2();
+ break;
+ case T_double :
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.drem();
+ break;
+ case T_float :
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.frem();
+ break;
+ }
+ break;
+ case AND :
+ switch (bits & ReturnTypeIDMASK) {
+ case T_int :
+ // 0 & x
+ if ((left.constant != Constant.NotAConstant)
+ && (left.constant.typeID() == T_int)
+ && (left.constant.intValue() == 0)) {
+ right.generateCode(currentScope, codeStream, false);
+ if (valueRequired)
+ codeStream.iconst_0();
+ } else {
+ // x & 0
+ if ((right.constant != Constant.NotAConstant)
+ && (right.constant.typeID() == T_int)
+ && (right.constant.intValue() == 0)) {
+ left.generateCode(currentScope, codeStream, false);
+ if (valueRequired)
+ codeStream.iconst_0();
+ } else {
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.iand();
+ }
+ }
+ break;
+ case T_long :
+ // 0 & x
+ if ((left.constant != Constant.NotAConstant)
+ && (left.constant.typeID() == T_long)
+ && (left.constant.longValue() == 0L)) {
+ right.generateCode(currentScope, codeStream, false);
+ if (valueRequired)
+ codeStream.lconst_0();
+ } else {
+ // x & 0
+ if ((right.constant != Constant.NotAConstant)
+ && (right.constant.typeID() == T_long)
+ && (right.constant.longValue() == 0L)) {
+ left.generateCode(currentScope, codeStream, false);
+ if (valueRequired)
+ codeStream.lconst_0();
+ } else {
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.land();
+ }
+ }
+ break;
+ case T_boolean : // logical and
+ generateOptimizedLogicalAnd(
+ currentScope,
+ codeStream,
+ null,
+ (falseLabel = new Label(codeStream)),
+ valueRequired);
+ /* improving code gen for such a case: boolean b = i < 0 && false;
+ * since the label has never been used, we have the inlined value on the stack. */
+ if (falseLabel.hasForwardReferences()) {
+ if (valueRequired) {
+ codeStream.iconst_1();
+ if ((bits & ValueForReturnMASK) != 0) {
+ codeStream.ireturn();
+ falseLabel.place();
+ codeStream.iconst_0();
+ } else {
+ codeStream.goto_(endLabel = new Label(codeStream));
+ codeStream.decrStackSize(1);
+ falseLabel.place();
+ codeStream.iconst_0();
+ endLabel.place();
+ }
+ } else {
+ falseLabel.place();
+ }
+ }
+ }
+ break;
+ case OR :
+ switch (bits & ReturnTypeIDMASK) {
+ case T_int :
+ // 0 | x
+ if ((left.constant != Constant.NotAConstant)
+ && (left.constant.typeID() == T_int)
+ && (left.constant.intValue() == 0)) {
+ right.generateCode(currentScope, codeStream, valueRequired);
+ } else {
+ // x | 0
+ if ((right.constant != Constant.NotAConstant)
+ && (right.constant.typeID() == T_int)
+ && (right.constant.intValue() == 0)) {
+ left.generateCode(currentScope, codeStream, valueRequired);
+ } else {
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.ior();
+ }
+ }
+ break;
+ case T_long :
+ // 0 | x
+ if ((left.constant != Constant.NotAConstant)
+ && (left.constant.typeID() == T_long)
+ && (left.constant.longValue() == 0L)) {
+ right.generateCode(currentScope, codeStream, valueRequired);
+ } else {
+ // x | 0
+ if ((right.constant != Constant.NotAConstant)
+ && (right.constant.typeID() == T_long)
+ && (right.constant.longValue() == 0L)) {
+ left.generateCode(currentScope, codeStream, valueRequired);
+ } else {
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.lor();
+ }
+ }
+ break;
+ case T_boolean : // logical or
+ generateOptimizedLogicalOr(
+ currentScope,
+ codeStream,
+ null,
+ (falseLabel = new Label(codeStream)),
+ valueRequired);
+ /* improving code gen for such a case: boolean b = i < 0 || true;
+ * since the label has never been used, we have the inlined value on the stack. */
+ if (falseLabel.hasForwardReferences()) {
+ if (valueRequired) {
+ codeStream.iconst_1();
+ if ((bits & ValueForReturnMASK) != 0) {
+ codeStream.ireturn();
+ falseLabel.place();
+ codeStream.iconst_0();
+ } else {
+ codeStream.goto_(endLabel = new Label(codeStream));
+ codeStream.decrStackSize(1);
+ falseLabel.place();
+ codeStream.iconst_0();
+ endLabel.place();
+ }
+ } else {
+ falseLabel.place();
+ }
+ }
+ }
+ break;
+ case XOR :
+ switch (bits & ReturnTypeIDMASK) {
+ case T_int :
+ // 0 ^ x
+ if ((left.constant != Constant.NotAConstant)
+ && (left.constant.typeID() == T_int)
+ && (left.constant.intValue() == 0)) {
+ right.generateCode(currentScope, codeStream, valueRequired);
+ } else {
+ // x ^ 0
+ if ((right.constant != Constant.NotAConstant)
+ && (right.constant.typeID() == T_int)
+ && (right.constant.intValue() == 0)) {
+ left.generateCode(currentScope, codeStream, valueRequired);
+ } else {
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.ixor();
+ }
+ }
+ break;
+ case T_long :
+ // 0 ^ x
+ if ((left.constant != Constant.NotAConstant)
+ && (left.constant.typeID() == T_long)
+ && (left.constant.longValue() == 0L)) {
+ right.generateCode(currentScope, codeStream, valueRequired);
+ } else {
+ // x ^ 0
+ if ((right.constant != Constant.NotAConstant)
+ && (right.constant.typeID() == T_long)
+ && (right.constant.longValue() == 0L)) {
+ left.generateCode(currentScope, codeStream, valueRequired);
+ } else {
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.lxor();
+ }
+ }
+ break;
+ case T_boolean :
+ generateOptimizedLogicalXor(
+ currentScope,
+ codeStream,
+ null,
+ (falseLabel = new Label(codeStream)),
+ valueRequired);
+ /* improving code gen for such a case: boolean b = i < 0 ^ bool;
+ * since the label has never been used, we have the inlined value on the stack. */
+ if (falseLabel.hasForwardReferences()) {
+ if (valueRequired) {
+ codeStream.iconst_1();
+ if ((bits & ValueForReturnMASK) != 0) {
+ codeStream.ireturn();
+ falseLabel.place();
+ codeStream.iconst_0();
+ } else {
+ codeStream.goto_(endLabel = new Label(codeStream));
+ codeStream.decrStackSize(1);
+ falseLabel.place();
+ codeStream.iconst_0();
+ endLabel.place();
+ }
+ } else {
+ falseLabel.place();
+ }
+ }
+ }
+ break;
+ case LEFT_SHIFT :
+ switch (bits & ReturnTypeIDMASK) {
+ case T_int :
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.ishl();
+ break;
+ case T_long :
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.lshl();
+ }
+ break;
+ case RIGHT_SHIFT :
+ switch (bits & ReturnTypeIDMASK) {
+ case T_int :
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.ishr();
+ break;
+ case T_long :
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.lshr();
+ }
+ break;
+ case UNSIGNED_RIGHT_SHIFT :
+ switch (bits & ReturnTypeIDMASK) {
+ case T_int :
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.iushr();
+ break;
+ case T_long :
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired)
+ codeStream.lushr();
+ }
+ break;
+ case GREATER :
+ generateOptimizedGreaterThan(
+ currentScope,
+ codeStream,
+ null,
+ (falseLabel = new Label(codeStream)),
+ valueRequired);
+ if (valueRequired) {
+ codeStream.iconst_1();
+ if ((bits & ValueForReturnMASK) != 0) {
+ codeStream.ireturn();
+ falseLabel.place();
+ codeStream.iconst_0();
+ } else {
+ codeStream.goto_(endLabel = new Label(codeStream));
+ codeStream.decrStackSize(1);
+ falseLabel.place();
+ codeStream.iconst_0();
+ endLabel.place();
+ }
+ }
+ break;
+ case GREATER_EQUAL :
+ generateOptimizedGreaterThanOrEqual(
+ currentScope,
+ codeStream,
+ null,
+ (falseLabel = new Label(codeStream)),
+ valueRequired);
+ if (valueRequired) {
+ codeStream.iconst_1();
+ if ((bits & ValueForReturnMASK) != 0) {
+ codeStream.ireturn();
+ falseLabel.place();
+ codeStream.iconst_0();
+ } else {
+ codeStream.goto_(endLabel = new Label(codeStream));
+ codeStream.decrStackSize(1);
+ falseLabel.place();
+ codeStream.iconst_0();
+ endLabel.place();
+ }
+ }
+ break;
+ case LESS :
+ generateOptimizedLessThan(
+ currentScope,
+ codeStream,
+ null,
+ (falseLabel = new Label(codeStream)),
+ valueRequired);
+ if (valueRequired) {
+ codeStream.iconst_1();
+ if ((bits & ValueForReturnMASK) != 0) {
+ codeStream.ireturn();
+ falseLabel.place();
+ codeStream.iconst_0();
+ } else {
+ codeStream.goto_(endLabel = new Label(codeStream));
+ codeStream.decrStackSize(1);
+ falseLabel.place();
+ codeStream.iconst_0();
+ endLabel.place();
+ }
+ }
+ break;
+ case LESS_EQUAL :
+ generateOptimizedLessThanOrEqual(
+ currentScope,
+ codeStream,
+ null,
+ (falseLabel = new Label(codeStream)),
+ valueRequired);
+ if (valueRequired) {
+ codeStream.iconst_1();
+ if ((bits & ValueForReturnMASK) != 0) {
+ codeStream.ireturn();
+ falseLabel.place();
+ codeStream.iconst_0();
+ } else {
+ codeStream.goto_(endLabel = new Label(codeStream));
+ codeStream.decrStackSize(1);
+ falseLabel.place();
+ codeStream.iconst_0();
+ endLabel.place();
+ }
+ }
+ }
+ if (valueRequired) {
+ codeStream.generateImplicitConversion(implicitConversion);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ /**
+ * Boolean operator code generation
+ * Optimized operations are: <, <=, >, >=, &, |, ^
+ */
+ public void generateOptimizedBoolean(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Label trueLabel,
+ Label falseLabel,
+ boolean valueRequired) {
+
+ if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) {
+ int pc = codeStream.position;
+ if (constant.booleanValue() == true) {
+ // constant == true
+ if (valueRequired) {
+ if (falseLabel == null) {
+ // implicit falling through the FALSE case
+ if (trueLabel != null) {
+ codeStream.goto_(trueLabel);
+ }
+ }
+ }
+ } else {
+ if (valueRequired) {
+ if (falseLabel != null) {
+ // implicit falling through the TRUE case
+ if (trueLabel == null) {
+ codeStream.goto_(falseLabel);
+ }
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ switch ((bits & OperatorMASK) >> OperatorSHIFT) {
+ case LESS :
+ generateOptimizedLessThan(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ valueRequired);
+ return;
+ case LESS_EQUAL :
+ generateOptimizedLessThanOrEqual(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ valueRequired);
+ return;
+ case GREATER :
+ generateOptimizedGreaterThan(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ valueRequired);
+ return;
+ case GREATER_EQUAL :
+ generateOptimizedGreaterThanOrEqual(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ valueRequired);
+ return;
+ case AND :
+ generateOptimizedLogicalAnd(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ valueRequired);
+ return;
+ case OR :
+ generateOptimizedLogicalOr(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ valueRequired);
+ return;
+ case XOR :
+ generateOptimizedLogicalXor(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ valueRequired);
+ return;
+ }
+ super.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ valueRequired);
+ }
+
+ /**
+ * Boolean generation for >
+ */
+ public void generateOptimizedGreaterThan(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Label trueLabel,
+ Label falseLabel,
+ boolean valueRequired) {
+
+ int pc = codeStream.position;
+ int promotedTypeID = left.implicitConversion >> 4;
+ // both sides got promoted in the same way
+ if (promotedTypeID == T_int) {
+ // 0 > x
+ if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) {
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // implicitly falling through the FALSE case
+ codeStream.iflt(trueLabel);
+ }
+ } else {
+ if (trueLabel == null) {
+ // implicitly falling through the TRUE case
+ codeStream.ifge(falseLabel);
+ } else {
+ // no implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ // x > 0
+ if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) {
+ left.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // implicitly falling through the FALSE case
+ codeStream.ifgt(trueLabel);
+ }
+ } else {
+ if (trueLabel == null) {
+ // implicitly falling through the TRUE case
+ codeStream.ifle(falseLabel);
+ } else {
+ // no implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ }
+ // default comparison
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // implicit falling through the FALSE case
+ switch (promotedTypeID) {
+ case T_int :
+ codeStream.if_icmpgt(trueLabel);
+ break;
+ case T_float :
+ codeStream.fcmpl();
+ codeStream.ifgt(trueLabel);
+ break;
+ case T_long :
+ codeStream.lcmp();
+ codeStream.ifgt(trueLabel);
+ break;
+ case T_double :
+ codeStream.dcmpl();
+ codeStream.ifgt(trueLabel);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ } else {
+ if (trueLabel == null) {
+ // implicit falling through the TRUE case
+ switch (promotedTypeID) {
+ case T_int :
+ codeStream.if_icmple(falseLabel);
+ break;
+ case T_float :
+ codeStream.fcmpl();
+ codeStream.ifle(falseLabel);
+ break;
+ case T_long :
+ codeStream.lcmp();
+ codeStream.ifle(falseLabel);
+ break;
+ case T_double :
+ codeStream.dcmpl();
+ codeStream.ifle(falseLabel);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ } else {
+ // no implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ }
+ }
+
+ /**
+ * Boolean generation for >=
+ */
+ public void generateOptimizedGreaterThanOrEqual(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Label trueLabel,
+ Label falseLabel,
+ boolean valueRequired) {
+
+ int pc = codeStream.position;
+ int promotedTypeID = left.implicitConversion >> 4;
+ // both sides got promoted in the same way
+ if (promotedTypeID == T_int) {
+ // 0 >= x
+ if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) {
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // implicitly falling through the FALSE case
+ codeStream.ifle(trueLabel);
+ }
+ } else {
+ if (trueLabel == null) {
+ // implicitly falling through the TRUE case
+ codeStream.ifgt(falseLabel);
+ } else {
+ // no implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ // x >= 0
+ if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) {
+ left.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // implicitly falling through the FALSE case
+ codeStream.ifge(trueLabel);
+ }
+ } else {
+ if (trueLabel == null) {
+ // implicitly falling through the TRUE case
+ codeStream.iflt(falseLabel);
+ } else {
+ // no implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ }
+ // default comparison
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // implicit falling through the FALSE case
+ switch (promotedTypeID) {
+ case T_int :
+ codeStream.if_icmpge(trueLabel);
+ break;
+ case T_float :
+ codeStream.fcmpl();
+ codeStream.ifge(trueLabel);
+ break;
+ case T_long :
+ codeStream.lcmp();
+ codeStream.ifge(trueLabel);
+ break;
+ case T_double :
+ codeStream.dcmpl();
+ codeStream.ifge(trueLabel);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ } else {
+ if (trueLabel == null) {
+ // implicit falling through the TRUE case
+ switch (promotedTypeID) {
+ case T_int :
+ codeStream.if_icmplt(falseLabel);
+ break;
+ case T_float :
+ codeStream.fcmpl();
+ codeStream.iflt(falseLabel);
+ break;
+ case T_long :
+ codeStream.lcmp();
+ codeStream.iflt(falseLabel);
+ break;
+ case T_double :
+ codeStream.dcmpl();
+ codeStream.iflt(falseLabel);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ } else {
+ // no implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ }
+ }
+
+ /**
+ * Boolean generation for <
+ */
+ public void generateOptimizedLessThan(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Label trueLabel,
+ Label falseLabel,
+ boolean valueRequired) {
+
+ int pc = codeStream.position;
+ int promotedTypeID = left.implicitConversion >> 4;
+ // both sides got promoted in the same way
+ if (promotedTypeID == T_int) {
+ // 0 < x
+ if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) {
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // implicitly falling through the FALSE case
+ codeStream.ifgt(trueLabel);
+ }
+ } else {
+ if (trueLabel == null) {
+ // implicitly falling through the TRUE case
+ codeStream.ifle(falseLabel);
+ } else {
+ // no implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ // x < 0
+ if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) {
+ left.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // implicitly falling through the FALSE case
+ codeStream.iflt(trueLabel);
+ }
+ } else {
+ if (trueLabel == null) {
+ // implicitly falling through the TRUE case
+ codeStream.ifge(falseLabel);
+ } else {
+ // no implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ }
+ // default comparison
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // implicit falling through the FALSE case
+ switch (promotedTypeID) {
+ case T_int :
+ codeStream.if_icmplt(trueLabel);
+ break;
+ case T_float :
+ codeStream.fcmpg();
+ codeStream.iflt(trueLabel);
+ break;
+ case T_long :
+ codeStream.lcmp();
+ codeStream.iflt(trueLabel);
+ break;
+ case T_double :
+ codeStream.dcmpg();
+ codeStream.iflt(trueLabel);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ } else {
+ if (trueLabel == null) {
+ // implicit falling through the TRUE case
+ switch (promotedTypeID) {
+ case T_int :
+ codeStream.if_icmpge(falseLabel);
+ break;
+ case T_float :
+ codeStream.fcmpg();
+ codeStream.ifge(falseLabel);
+ break;
+ case T_long :
+ codeStream.lcmp();
+ codeStream.ifge(falseLabel);
+ break;
+ case T_double :
+ codeStream.dcmpg();
+ codeStream.ifge(falseLabel);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ } else {
+ // no implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ }
+ }
+
+ /**
+ * Boolean generation for <=
+ */
+ public void generateOptimizedLessThanOrEqual(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Label trueLabel,
+ Label falseLabel,
+ boolean valueRequired) {
+
+ int pc = codeStream.position;
+ int promotedTypeID = left.implicitConversion >> 4;
+ // both sides got promoted in the same way
+ if (promotedTypeID == T_int) {
+ // 0 <= x
+ if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) {
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // implicitly falling through the FALSE case
+ codeStream.ifge(trueLabel);
+ }
+ } else {
+ if (trueLabel == null) {
+ // implicitly falling through the TRUE case
+ codeStream.iflt(falseLabel);
+ } else {
+ // no implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ // x <= 0
+ if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) {
+ left.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // implicitly falling through the FALSE case
+ codeStream.ifle(trueLabel);
+ }
+ } else {
+ if (trueLabel == null) {
+ // implicitly falling through the TRUE case
+ codeStream.ifgt(falseLabel);
+ } else {
+ // no implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ }
+ // default comparison
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // implicit falling through the FALSE case
+ switch (promotedTypeID) {
+ case T_int :
+ codeStream.if_icmple(trueLabel);
+ break;
+ case T_float :
+ codeStream.fcmpg();
+ codeStream.ifle(trueLabel);
+ break;
+ case T_long :
+ codeStream.lcmp();
+ codeStream.ifle(trueLabel);
+ break;
+ case T_double :
+ codeStream.dcmpg();
+ codeStream.ifle(trueLabel);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ } else {
+ if (trueLabel == null) {
+ // implicit falling through the TRUE case
+ switch (promotedTypeID) {
+ case T_int :
+ codeStream.if_icmpgt(falseLabel);
+ break;
+ case T_float :
+ codeStream.fcmpg();
+ codeStream.ifgt(falseLabel);
+ break;
+ case T_long :
+ codeStream.lcmp();
+ codeStream.ifgt(falseLabel);
+ break;
+ case T_double :
+ codeStream.dcmpg();
+ codeStream.ifgt(falseLabel);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ } else {
+ // no implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ }
+ }
+
+ /**
+ * Boolean generation for &
+ */
+ public void generateOptimizedLogicalAnd(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Label trueLabel,
+ Label falseLabel,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ Constant condConst;
+ if ((left.implicitConversion & 0xF) == T_boolean) {
+ if ((condConst = left.conditionalConstant()) != NotAConstant) {
+ if (condConst.booleanValue() == true) {
+ // <something equivalent to true> & x
+ left.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ if ((bits & OnlyValueRequiredMASK) != 0) {
+ right.generateCode(currentScope, codeStream, valueRequired);
+ } else {
+ right.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ valueRequired);
+ }
+ } else {
+ // <something equivalent to false> & x
+ left.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ right.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ if (valueRequired) {
+ if ((bits & OnlyValueRequiredMASK) != 0) {
+ codeStream.iconst_0();
+ } else {
+ if (falseLabel != null) {
+ // implicit falling through the TRUE case
+ codeStream.goto_(falseLabel);
+ }
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ if ((condConst = right.conditionalConstant()) != NotAConstant) {
+ if (condConst.booleanValue() == true) {
+ // x & <something equivalent to true>
+ if ((bits & OnlyValueRequiredMASK) != 0) {
+ left.generateCode(currentScope, codeStream, valueRequired);
+ } else {
+ left.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ valueRequired);
+ }
+ right.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ } else {
+ // x & <something equivalent to false>
+ left.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ right.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ if (valueRequired) {
+ if ((bits & OnlyValueRequiredMASK) != 0) {
+ codeStream.iconst_0();
+ } else {
+ if (falseLabel != null) {
+ // implicit falling through the TRUE case
+ codeStream.goto_(falseLabel);
+ }
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ }
+ // default case
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ codeStream.iand();
+ if ((bits & OnlyValueRequiredMASK) == 0) {
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // implicit falling through the FALSE case
+ codeStream.ifne(trueLabel);
+ }
+ } else {
+ // implicit falling through the TRUE case
+ if (trueLabel == null) {
+ codeStream.ifeq(falseLabel);
+ } else {
+ // no implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ /**
+ * Boolean generation for |
+ */
+ public void generateOptimizedLogicalOr(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Label trueLabel,
+ Label falseLabel,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ Constant condConst;
+ if ((left.implicitConversion & 0xF) == T_boolean) {
+ if ((condConst = left.conditionalConstant()) != NotAConstant) {
+ if (condConst.booleanValue() == true) {
+ // <something equivalent to true> | x
+ left.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ right.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ if (valueRequired) {
+ if ((bits & OnlyValueRequiredMASK) != 0) {
+ codeStream.iconst_1();
+ } else {
+ if (trueLabel != null) {
+ codeStream.goto_(trueLabel);
+ }
+ }
+ }
+ } else {
+ // <something equivalent to false> | x
+ left.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ if ((bits & OnlyValueRequiredMASK) != 0) {
+ right.generateCode(currentScope, codeStream, valueRequired);
+ } else {
+ right.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ valueRequired);
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ if ((condConst = right.conditionalConstant()) != NotAConstant) {
+ if (condConst.booleanValue() == true) {
+ // x | <something equivalent to true>
+ left.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ right.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ if (valueRequired) {
+ if ((bits & OnlyValueRequiredMASK) != 0) {
+ codeStream.iconst_1();
+ } else {
+ if (trueLabel != null) {
+ codeStream.goto_(trueLabel);
+ }
+ }
+ }
+ } else {
+ // x | <something equivalent to false>
+ if ((bits & OnlyValueRequiredMASK) != 0) {
+ left.generateCode(currentScope, codeStream, valueRequired);
+ } else {
+ left.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ valueRequired);
+ }
+ right.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ }
+ // default case
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ codeStream.ior();
+ if ((bits & OnlyValueRequiredMASK) == 0) {
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // implicit falling through the FALSE case
+ codeStream.ifne(trueLabel);
+ }
+ } else {
+ // implicit falling through the TRUE case
+ if (trueLabel == null) {
+ codeStream.ifeq(falseLabel);
+ } else {
+ // no implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ /**
+ * Boolean generation for ^
+ */
+ public void generateOptimizedLogicalXor(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Label trueLabel,
+ Label falseLabel,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ Constant condConst;
+ if ((left.implicitConversion & 0xF) == T_boolean) {
+ if ((condConst = left.conditionalConstant()) != NotAConstant) {
+ if (condConst.booleanValue() == true) {
+ // <something equivalent to true> ^ x
+ left.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ right.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ falseLabel,
+ trueLabel,
+ valueRequired);
+ } else {
+ // <something equivalent to false> ^ x
+ left.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ if ((bits & OnlyValueRequiredMASK) != 0) {
+ right.generateCode(currentScope, codeStream, valueRequired);
+ } else {
+ right.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ valueRequired);
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ if ((condConst = right.conditionalConstant()) != NotAConstant) {
+ if (condConst.booleanValue() == true) {
+ // x ^ <something equivalent to true>
+ left.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ falseLabel,
+ trueLabel,
+ valueRequired);
+ right.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ } else {
+ // x ^ <something equivalent to false>
+ if ((bits & OnlyValueRequiredMASK) != 0) {
+ left.generateCode(currentScope, codeStream, valueRequired);
+ } else {
+ left.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ valueRequired);
+ }
+ right.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ }
+ // default case
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ codeStream.ixor();
+ if ((bits & OnlyValueRequiredMASK) == 0) {
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // implicit falling through the FALSE case
+ codeStream.ifne(trueLabel);
+ }
+ } else {
+ // implicit falling through the TRUE case
+ if (trueLabel == null) {
+ codeStream.ifeq(falseLabel);
+ } else {
+ // no implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public void generateOptimizedStringBuffer(
+ BlockScope blockScope,
+ CodeStream codeStream,
+ int typeID) {
+ /* In the case trying to make a string concatenation, there is no need to create a new
+ * string buffer, thus use a lower-level API for code generation involving only the
+ * appending of arguments to the existing StringBuffer
+ */
+
+ if ((((bits & OperatorMASK) >> OperatorSHIFT) == PLUS)
+ && ((bits & ReturnTypeIDMASK) == T_String)) {
+ if (constant != NotAConstant) {
+ codeStream.generateConstant(constant, implicitConversion);
+ codeStream.invokeStringBufferAppendForType(implicitConversion & 0xF);
+ } else {
+ int pc = codeStream.position;
+ left.generateOptimizedStringBuffer(
+ blockScope,
+ codeStream,
+ left.implicitConversion & 0xF);
+ codeStream.recordPositionsFrom(pc, left);
+ pc = codeStream.position;
+ right.generateOptimizedStringBuffer(
+ blockScope,
+ codeStream,
+ right.implicitConversion & 0xF);
+ codeStream.recordPositionsFrom(pc, right);
+ }
+ } else {
+ super.generateOptimizedStringBuffer(blockScope, codeStream, typeID);
+ }
+ }
+
+ public void generateOptimizedStringBufferCreation(
+ BlockScope blockScope,
+ CodeStream codeStream,
+ int typeID) {
+ /* In the case trying to make a string concatenation, there is no need to create a new
+ * string buffer, thus use a lower-level API for code generation involving only the
+ * appending of arguments to the existing StringBuffer
+ */
+
+ if ((((bits & OperatorMASK) >> OperatorSHIFT) == PLUS)
+ && ((bits & ReturnTypeIDMASK) == T_String)) {
+ if (constant != NotAConstant) {
+ codeStream.newStringBuffer(); // new: java.lang.StringBuffer
+ codeStream.dup();
+ codeStream.ldc(constant.stringValue());
+ codeStream.invokeStringBufferStringConstructor();
+ // invokespecial: java.lang.StringBuffer.<init>(Ljava.lang.String;)V
+ } else {
+ int pc = codeStream.position;
+ left.generateOptimizedStringBufferCreation(
+ blockScope,
+ codeStream,
+ left.implicitConversion & 0xF);
+ codeStream.recordPositionsFrom(pc, left);
+ pc = codeStream.position;
+ right.generateOptimizedStringBuffer(
+ blockScope,
+ codeStream,
+ right.implicitConversion & 0xF);
+ codeStream.recordPositionsFrom(pc, right);
+ }
+ } else {
+ super.generateOptimizedStringBufferCreation(blockScope, codeStream, typeID);
+ }
+ }
+
+ public boolean isCompactableOperation() {
+ return true;
+ }
+
+ public void optimizedBooleanConstant(int leftId, int operator, int rightId) {
+ //watch for optimizedBooleanConstant
+
+ switch (operator) {
+ case AND :
+ if ((leftId != T_boolean) || (rightId != T_boolean))
+ return;
+ case AND_AND :
+ Constant cst;
+ if ((cst = left.conditionalConstant()) != NotAConstant) {
+ if (cst.booleanValue() == false) { // left is equivalent to false
+ optimizedBooleanConstant = cst; // constant(false)
+ return;
+ } else { //left is equivalent to true
+ if ((cst = right.conditionalConstant()) != NotAConstant) {
+ optimizedBooleanConstant = cst;
+ // the conditional result is equivalent to the right conditional value
+ }
+ return;
+ }
+ }
+ if ((cst = right.conditionalConstant()) != NotAConstant) {
+ if (cst.booleanValue() == false) { // right is equivalent to false
+ optimizedBooleanConstant = cst; // constant(false)
+ }
+ }
+ return;
+ case OR :
+ if ((leftId != T_boolean) || (rightId != T_boolean))
+ return;
+ case OR_OR :
+ if ((cst = left.conditionalConstant()) != NotAConstant) {
+ if (cst.booleanValue() == true) { // left is equivalent to true
+ optimizedBooleanConstant = cst; // constant(true)
+ return;
+ } else { //left is equivalent to false
+ if ((cst = right.conditionalConstant()) != NotAConstant) {
+ optimizedBooleanConstant = Constant.fromValue(!cst.booleanValue());
+ // the conditional result is equivalent to the opposite of the right conditional value
+ }
+ return;
+ }
+ }
+ if ((cst = right.conditionalConstant()) != NotAConstant) {
+ if (cst.booleanValue() == true) { // right is equivalent to true
+ optimizedBooleanConstant = cst; // constant(true)
+ }
+ }
+ }
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+
+ // use the id of the type to navigate into the table
+ TypeBinding leftTb = left.resolveType(scope);
+ TypeBinding rightTb = right.resolveType(scope);
+ if (leftTb == null || rightTb == null) {
+ constant = Constant.NotAConstant;
+ return null;
+ }
+ int leftId = leftTb.id;
+ int rightId = rightTb.id;
+ if (leftId > 15
+ || rightId > 15) { // must convert String + Object || Object + String
+ if (leftId == T_String) {
+ rightId = T_Object;
+ } else
+ if (rightId == T_String) {
+ leftId = T_Object;
+ } else {
+ constant = Constant.NotAConstant;
+ scope.problemReporter().invalidOperator(this, leftTb, rightTb);
+ return null;
+ }
+ }
+ if (((bits & OperatorMASK) >> OperatorSHIFT) == PLUS) {
+ if (leftId == T_String
+ && rightTb.isArrayType()
+ && ((ArrayBinding) rightTb).elementsType(scope) == CharBinding)
+ scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(
+ right);
+ else
+ if (rightId == T_String
+ && leftTb.isArrayType()
+ && ((ArrayBinding) leftTb).elementsType(scope) == CharBinding)
+ scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(
+ left);
+ }
+
+ // the code is an int
+ // (cast) left Op (cast) rigth --> result
+ // 0000 0000 0000 0000 0000
+ // <<16 <<12 <<8 <<4 <<0
+
+ // Don't test for result = 0. If it is zero, some more work is done.
+ // On the one hand when it is not zero (correct code) we avoid doing the test
+ int result =
+ ResolveTypeTables[(bits & OperatorMASK) >> OperatorSHIFT][(leftId << 4)
+ + rightId];
+ left.implicitConversion = result >>> 12;
+ right.implicitConversion = (result >>> 4) & 0x000FF;
+ TypeBinding type;
+ bits |= result & 0xF;
+ switch (result & 0xF) { // record the current ReturnTypeID
+ // only switch on possible result type.....
+ case T_boolean :
+ type = BooleanBinding;
+ break;
+ case T_byte :
+ type = ByteBinding;
+ break;
+ case T_char :
+ type = CharBinding;
+ break;
+ case T_double :
+ type = DoubleBinding;
+ break;
+ case T_float :
+ type = FloatBinding;
+ break;
+ case T_int :
+ type = IntBinding;
+ break;
+ case T_long :
+ type = LongBinding;
+ break;
+ case T_String :
+ type = scope.getJavaLangString();
+ break;
+ default : //error........
+ constant = Constant.NotAConstant;
+ scope.problemReporter().invalidOperator(this, leftTb, rightTb);
+ return null;
+ }
+
+ // compute the constant when valid
+ computeConstant(scope, leftId, rightId);
+ return type;
+ }
+
+ public String toStringExpressionNoParenthesis() {
+ /* slow code*/
+
+ return left.toStringExpression()
+ + " "
+ + operatorToString()
+ + " "
+ + right.toStringExpression();
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ if (visitor.visit(this, scope)) {
+ left.traverse(visitor, scope);
+ right.traverse(visitor, scope);
+ }
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java
new file mode 100644
index 0000000000..add6cb8715
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java
@@ -0,0 +1,149 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class Block extends Statement {
+ public Statement[] statements;
+ public int explicitDeclarations;
+ // the number of explicit declaration , used to create scope
+ public BlockScope scope;
+ public static final Block None = new Block(0);
+ public Block(int explicitDeclarations) {
+ this.explicitDeclarations = explicitDeclarations;
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+
+ // iterate on statements
+
+ // empty block
+ if (statements == null)
+ return flowInfo;
+ for (int i = 0, max = statements.length; i < max; i++) {
+ Statement stat;
+ if (!flowInfo.complainIfUnreachable((stat = statements[i]), scope)) {
+ flowInfo = stat.analyseCode(scope, flowContext, flowInfo);
+ }
+ }
+ return flowInfo;
+ }
+
+ public static final Block EmptyWith(int sourceStart, int sourceEnd) {
+ //return an empty block which position is s and e
+
+ Block bk = new Block(0);
+ bk.sourceStart = sourceStart;
+ bk.sourceEnd = sourceEnd;
+ return bk;
+ }
+
+ /**
+ * Code generation for a block
+ * i.e. propagate to statements
+ */
+ public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+ if ((bits & IsReachableMASK) == 0) {
+ return;
+ }
+ int pc = codeStream.position;
+ if (statements != null) {
+ for (int i = 0, max = statements.length; i < max; i++) {
+ statements[i].generateCode(scope, codeStream);
+ }
+ } // for local variable debug attributes
+ if (scope != currentScope) { // was really associated with its own scope
+ codeStream.exitUserScope(scope);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public boolean isEmptyBlock() {
+ return statements == null;
+ }
+
+ public void resolve(BlockScope upperScope) {
+ if (statements != null) {
+ scope =
+ explicitDeclarations == 0
+ ? upperScope
+ : new BlockScope(upperScope, explicitDeclarations);
+ int i = 0, length = statements.length;
+ while (i < length)
+ statements[i++].resolve(scope);
+ }
+ }
+
+ public void resolveUsing(BlockScope givenScope) {
+ // this optimized resolve(...) is sent only on none empty blocks
+
+ scope = givenScope;
+ if (statements != null) {
+ int i = 0, length = statements.length;
+ while (i < length)
+ statements[i++].resolve(scope);
+ }
+ }
+
+ public String toString(int tab) {
+ /* slow code */
+
+ String s = tabString(tab);
+ if (this.statements == null) {
+ s += "{\n";
+ s += tabString(tab);
+ s += "}";
+ return s;
+ }
+
+ // s = s + (explicitDeclarations != 0
+ // ? " { // ---scope needed for "+String.valueOf(explicitDeclarations) +" locals------------ \n"
+ // : "{// ---NO scope needed------ \n") ;
+
+ s += "{\n";
+ s += this.toStringStatements(tab);
+ s += tabString(tab);
+ s += "}";
+ return s;
+ }
+
+ public String toStringStatements(int tab) {
+ /* slow code */
+ if (this.statements == null)
+ return "";
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < statements.length; i++) {
+ buffer.append(statements[i].toString(tab + 1));
+ if (statements[i] instanceof Block) {
+ buffer.append("\n");
+ } else {
+ buffer.append(";\n");
+ }
+ };
+ return buffer.toString();
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ if (visitor.visit(this, blockScope)) {
+ if (statements != null) {
+ int statementLength = statements.length;
+ for (int i = 0; i < statementLength; i++)
+ statements[i].traverse(visitor, scope);
+ }
+ }
+ visitor.endVisit(this, blockScope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java
new file mode 100644
index 0000000000..b093db24fa
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java
@@ -0,0 +1,60 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public abstract class BranchStatement extends Statement {
+ public char[] label;
+ public Label targetLabel;
+ public AstNode[] subroutines;
+ /**
+ * BranchStatement constructor comment.
+ */
+ public BranchStatement(char[] l, int s, int e) {
+ label = l;
+ sourceStart = s;
+ sourceEnd = e;
+ }
+
+ /**
+ * Branch code generation
+ *
+ * generate the finallyInvocationSequence.
+ */
+ public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+
+ if ((bits & IsReachableMASK) == 0) {
+ return;
+ }
+ int pc = codeStream.position;
+
+ // generation of code responsible for invoking the finally
+ // blocks in sequence
+ if (subroutines != null) {
+ for (int i = 0, max = subroutines.length; i < max; i++) {
+ AstNode sub;
+ if ((sub = subroutines[i]) instanceof SynchronizedStatement) {
+ codeStream.load(((SynchronizedStatement) sub).synchroVariable);
+ codeStream.monitorexit();
+ } else {
+ TryStatement trySub = (TryStatement) sub;
+ if (trySub.subRoutineCannotReturn) {
+ codeStream.goto_(trySub.subRoutineStartLabel);
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ } else {
+ codeStream.jsr(trySub.subRoutineStartLabel);
+ }
+ }
+ }
+ }
+ codeStream.goto_(targetLabel);
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Break.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Break.java
new file mode 100644
index 0000000000..f87c1c22f5
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Break.java
@@ -0,0 +1,97 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class Break extends BranchStatement {
+ public Break(char[] label, int sourceStart, int e) {
+ super(label, sourceStart, e);
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+
+ // here requires to generate a sequence of finally blocks invocations depending corresponding
+ // to each of the traversed try statements, so that execution will terminate properly.
+
+ // lookup the label, this should answer the returnContext
+ FlowContext targetContext;
+ if (label == null) {
+ targetContext = flowContext.getTargetContextForDefaultBreak();
+ } else {
+ targetContext = flowContext.getTargetContextForBreakLabel(label);
+ }
+ if (targetContext == null) {
+ if (label == null) {
+ currentScope.problemReporter().invalidBreak(this);
+ } else {
+ currentScope.problemReporter().undefinedLabel(this); // need to improve
+ }
+ } else {
+ targetLabel = targetContext.breakLabel();
+ targetContext.recordBreakFrom(flowInfo);
+ FlowContext traversedContext = flowContext;
+ int subIndex = 0, maxSub = 5;
+ subroutines = new AstNode[maxSub];
+ while (true) {
+ AstNode sub;
+ if ((sub = traversedContext.subRoutine()) != null) {
+ if (subIndex == maxSub) {
+ System.arraycopy(
+ subroutines,
+ 0,
+ (subroutines = new AstNode[maxSub *= 2]),
+ 0,
+ subIndex);
+ // grow
+ }
+ subroutines[subIndex++] = sub;
+ if (sub.cannotReturn()) {
+ break;
+ }
+ }
+ if (traversedContext == targetContext) {
+ break;
+ } else {
+ traversedContext = traversedContext.parent;
+ }
+ }
+ // resize subroutines
+ if (subIndex != maxSub) {
+ System.arraycopy(
+ subroutines,
+ 0,
+ (subroutines = new AstNode[subIndex]),
+ 0,
+ subIndex);
+ }
+ }
+ return FlowInfo.DeadEnd;
+ }
+
+ public String toString(int tab) {
+ /* slow code */
+
+ String s = tabString(tab);
+ s = s + "break ";
+ if (label != null)
+ s = s + new String(label);
+ return s;
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockscope) {
+ visitor.visit(this, blockscope);
+ visitor.endVisit(this, blockscope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Case.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Case.java
new file mode 100644
index 0000000000..e73a7f8780
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Case.java
@@ -0,0 +1,98 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class Case extends Statement {
+ public Expression constantExpression;
+ public CaseLabel targetLabel;
+ public Case(Expression constantExpression) {
+ this.constantExpression = constantExpression;
+ sourceEnd = constantExpression.sourceEnd;
+ sourceStart = constantExpression.sourceStart;
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+
+ /* EXTRA REFERENCE RECORDING
+ // need to record field references sitting in case constants
+ FieldBinding binding;
+ if ((binding = constant.fieldBinding()) != null) {
+ currentScope.referenceType().recordReferenceTo(binding);
+ }
+ */
+
+ return flowInfo;
+ }
+
+ /**
+ * Case code generation
+ *
+ */
+ public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+
+ if ((bits & IsReachableMASK) == 0) {
+ return;
+ }
+ int pc = codeStream.position;
+ targetLabel.place();
+ codeStream.recordPositionsFrom(pc, this);
+
+ }
+
+ public void resolve(BlockScope scope) {
+ // error....use resolveCase....
+
+ throw new NullPointerException();
+ }
+
+ public Constant resolveCase(
+ BlockScope scope,
+ TypeBinding testTb,
+ SwitchStatement switchStatement) {
+ // add into the collection of cases of the associated switch statement
+ switchStatement.cases[switchStatement.caseCount++] = this;
+ TypeBinding caseTb = constantExpression.resolveType(scope);
+ if (constantExpression.constant == NotAConstant)
+ scope.problemReporter().caseExpressionMustBeConstant(constantExpression);
+ if (caseTb == null || testTb == null)
+ return null;
+ if (constantExpression.isConstantValueOfTypeAssignableToType(caseTb, testTb))
+ return constantExpression.constant;
+ if (scope.areTypesCompatible(caseTb, testTb))
+ return constantExpression.constant;
+ scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
+ constantExpression,
+ caseTb,
+ testTb);
+ return null;
+ }
+
+ public String toString(int tab) {
+ /* slow code */
+
+ String s = tabString(tab);
+ s = s + "case " + constantExpression.toStringExpression() + " : ";
+ return s;
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ if (visitor.visit(this, blockScope)) {
+ constantExpression.traverse(visitor, blockScope);
+ }
+ visitor.endVisit(this, blockScope);
+ }
+
+}
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
new file mode 100644
index 0000000000..5b16357d4d
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java
@@ -0,0 +1,287 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class CastExpression extends Expression {
+ public Expression expression;
+ public Expression type;
+ public boolean needRuntimeCheckcast;
+ public TypeBinding castTb;
+
+ //expression.implicitConversion holds the cast for baseType casting
+
+ public CastExpression(Expression e, Expression t) {
+ expression = e;
+ type = t;
+
+ //due to the fact an expression may start with ( and that a cast also start with (
+ //the field is an expression....it can be a TypeReference OR a NameReference Or
+ //an expression <--this last one is invalid.......
+
+ // :-( .............
+
+ //if (type instanceof TypeReference )
+ // flag = IsTypeReference ;
+ //else
+ // if (type instanceof NameReference)
+ // flag = IsNameReference ;
+ // else
+ // flag = IsExpression ;
+
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+
+ /* EXTRA REFERENCE RECORDING
+ if (!needsRuntimeCheck && (implicitConversion == NoConversion)) {
+ // need to manually remember the castType as part of the reference information"
+ currentScope.currentMethodDeclaration().recordReferenceTo(type.getTypeBinding());
+ }
+ */
+
+ return expression
+ .analyseCode(currentScope, flowContext, flowInfo)
+ .unconditionalInits();
+ }
+
+ public final void areTypesCastCompatible(
+ BlockScope scope,
+ TypeBinding castTb,
+ TypeBinding expressionTb) {
+ // see specifications p.68
+ // handle errors and process constant when needed
+
+ // if either one of the type is null ==>
+ // some error has been already reported some where ==>
+ // we then do not report an obvious-cascade-error.
+
+ needRuntimeCheckcast = false;
+ if (castTb == null || expressionTb == null)
+ return;
+ if (castTb.isBaseType()) {
+ if (expressionTb.isBaseType()) {
+ if (expressionTb == castTb) {
+ constant = expression.constant; //use the same constant
+ return;
+ }
+ if (scope.areTypesCompatible(expressionTb, castTb)
+ || BaseTypeBinding.isNarrowing(castTb.id, expressionTb.id)) {
+ expression.implicitConversion = (castTb.id << 4) + expressionTb.id;
+ if (expression.constant != Constant.NotAConstant)
+ constant = expression.constant.castTo(expression.implicitConversion);
+ return;
+ }
+ }
+ scope.problemReporter().typeCastError(this, castTb, expressionTb);
+ return;
+ }
+
+ //-----------cast to something which is NOT a base type--------------------------
+ if (expressionTb == NullBinding)
+ return; //null is compatible with every thing
+
+ if (expressionTb.isBaseType()) {
+ scope.problemReporter().typeCastError(this, castTb, expressionTb);
+ return;
+ }
+
+ if (expressionTb.isArrayType()) {
+ if (castTb.isArrayType()) {
+ //------- (castTb.isArray) expressionTb.isArray -----------
+ TypeBinding expressionEltTb = ((ArrayBinding) expressionTb).elementsType(scope);
+ if (expressionEltTb.isBaseType()) {
+ // <---stop the recursion-------
+ if (((ArrayBinding) castTb).elementsType(scope) == expressionEltTb)
+ needRuntimeCheckcast = true;
+ else
+ scope.problemReporter().typeCastError(this, castTb, expressionTb);
+ return;
+ }
+ // recursively on the elements...
+ areTypesCastCompatible(
+ scope,
+ ((ArrayBinding) castTb).elementsType(scope),
+ expressionEltTb);
+ return;
+ } else
+ if (castTb.isClass()) {
+ //------(castTb.isClass) expressionTb.isArray ---------------
+ if (scope.isJavaLangObject(castTb))
+ return;
+ } else { //------- (castTb.isInterface) expressionTb.isArray -----------
+ if (scope.isJavaLangCloneable(castTb) || scope.isJavaIoSerializable(castTb)) {
+ needRuntimeCheckcast = true;
+ return;
+ }
+ }
+ scope.problemReporter().typeCastError(this, castTb, expressionTb);
+ return;
+ }
+
+ if (expressionTb.isClass()) {
+ if (castTb.isArrayType()) {
+ // ---- (castTb.isArray) expressionTb.isClass -------
+ if (scope.isJavaLangObject(expressionTb)) { // potential runtime error
+ needRuntimeCheckcast = true;
+ return;
+ }
+ } else
+ if (castTb.isClass()) { // ----- (castTb.isClass) expressionTb.isClass ------
+ if (scope.areTypesCompatible(expressionTb, castTb)) // no runtime error
+ return;
+ if (scope.areTypesCompatible(castTb, expressionTb)) {
+ // potential runtime error
+ needRuntimeCheckcast = true;
+ return;
+ }
+ } else { // ----- (castTb.isInterface) expressionTb.isClass -------
+ if (((ReferenceBinding) expressionTb).isFinal()) {
+ // no subclass for expressionTb, thus compile-time check is valid
+ if (scope.areTypesCompatible(expressionTb, castTb))
+ return;
+ } else { // a subclass may implement the interface ==> no check at compile time
+ needRuntimeCheckcast = true;
+ return;
+ }
+ }
+ scope.problemReporter().typeCastError(this, castTb, expressionTb);
+ return;
+ }
+
+ // if (expressionTb.isInterface()) { cannot be anything else
+ if (castTb.isArrayType()) {
+ // ----- (castTb.isArray) expressionTb.isInterface ------
+ if (scope.isJavaLangCloneable(expressionTb)
+ || scope.isJavaIoSerializable(expressionTb)) // potential runtime error
+ needRuntimeCheckcast = true;
+ else
+ scope.problemReporter().typeCastError(this, castTb, expressionTb);
+ return;
+ } else
+ if (castTb.isClass()) {
+ // ----- (castTb.isClass) expressionTb.isInterface --------
+ if (scope.isJavaLangObject(castTb)) // no runtime error
+ return;
+ if (((ReferenceBinding) castTb).isFinal()) {
+ // no subclass for castTb, thus compile-time check is valid
+ if (!scope.areTypesCompatible(castTb, expressionTb)) {
+ // potential runtime error
+ scope.problemReporter().typeCastError(this, castTb, expressionTb);
+ return;
+ }
+ }
+ } else { // ----- (castTb.isInterface) expressionTb.isInterface -------
+ if (castTb != expressionTb
+ && (scope.compareTypes(castTb, expressionTb) == NotRelated)) {
+ MethodBinding[] castTbMethods = ((ReferenceBinding) castTb).methods();
+ MethodBinding[] expressionTbMethods =
+ ((ReferenceBinding) expressionTb).methods();
+ int exprMethodsLength = expressionTbMethods.length;
+ for (int i = 0, castMethodsLength = castTbMethods.length;
+ i < castMethodsLength;
+ i++)
+ for (int j = 0; j < exprMethodsLength; j++)
+ if (castTbMethods[i].returnType != expressionTbMethods[j].returnType)
+ if (castTbMethods[i].selector == expressionTbMethods[j].selector)
+ if (castTbMethods[i].areParametersEqual(expressionTbMethods[j]))
+ scope.problemReporter().typeCastError(this, castTb, expressionTb);
+ }
+ }
+ needRuntimeCheckcast = true;
+ return;
+ }
+
+ /**
+ * Cast expression code generation
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param valueRequired boolean
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ if (constant != NotAConstant) {
+ if (valueRequired
+ || needRuntimeCheckcast) { // Added for: 1F1W9IG: IVJCOM:WINNT - Compiler omits casting check
+ codeStream.generateConstant(constant, implicitConversion);
+ if (needRuntimeCheckcast) {
+ codeStream.checkcast(castTb);
+ if (!valueRequired)
+ codeStream.pop();
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ expression.generateCode(
+ currentScope,
+ codeStream,
+ valueRequired || needRuntimeCheckcast);
+ if (needRuntimeCheckcast) {
+ codeStream.checkcast(castTb);
+ if (!valueRequired)
+ codeStream.pop();
+ } else {
+ if (valueRequired)
+ codeStream.generateImplicitConversion(implicitConversion);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ // compute a new constant if the cast is effective
+
+ // due to the fact an expression may start with ( and that a cast can also start with (
+ // the field is an expression....it can be a TypeReference OR a NameReference Or
+ // any kind of Expression <-- this last one is invalid.......
+
+ constant = Constant.NotAConstant;
+ implicitConversion = T_undefined;
+ TypeBinding expressionTb = expression.resolveType(scope);
+ if (expressionTb == null)
+ return null;
+
+ if ((type instanceof TypeReference) || (type instanceof NameReference)) {
+ if ((castTb = type.resolveType(scope)) == null)
+ return null;
+ areTypesCastCompatible(scope, castTb, expressionTb);
+ return castTb;
+ } else { // expression as a cast !!!!!!!!
+ scope.problemReporter().invalidTypeReference(type);
+ return null;
+ }
+ }
+
+ public String toStringExpression() {
+ /*slow code*/
+
+ return "(" + type.toString(0) + ") " + expression.toStringExpression();
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ if (visitor.visit(this, blockScope)) {
+ type.traverse(visitor, blockScope);
+ expression.traverse(visitor, blockScope);
+ }
+ visitor.endVisit(this, blockScope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CharLiteral.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CharLiteral.java
new file mode 100644
index 0000000000..80b1655558
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CharLiteral.java
@@ -0,0 +1,106 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class CharLiteral extends NumberLiteral {
+ char value;
+ public CharLiteral(char[] token, int s, int e) {
+ super(token, s, e);
+ computeValue();
+ }
+
+ public void computeConstant() {
+ //The source is a char[3] first and last char are '
+ //This is true for both regular char AND unicode char
+ //BUT not for escape char like '\b' which are char[4]....
+
+ constant = Constant.fromValue(value);
+ }
+
+ private void computeValue() {
+ //The source is a char[3] first and last char are '
+ //This is true for both regular char AND unicode char
+ //BUT not for escape char like '\b' which are char[4]....
+
+ if ((value = source[1]) != '\\')
+ return;
+ char digit;
+ switch (digit = source[2]) {
+ case 'b' :
+ value = '\b';
+ break;
+ case 't' :
+ value = '\t';
+ break;
+ case 'n' :
+ value = '\n';
+ break;
+ case 'f' :
+ value = '\f';
+ break;
+ case 'r' :
+ value = '\r';
+ break;
+ case '\"' :
+ value = '\"';
+ break;
+ case '\'' :
+ value = '\'';
+ break;
+ case '\\' :
+ value = '\\';
+ break;
+ default : //octal (welled formed, i.e. ended by a ' )
+ int number = Character.getNumericValue(digit);
+ if ((digit = source[3]) != '\'')
+ number = (number * 8) + Character.getNumericValue(digit);
+ else {
+ constant = Constant.fromValue(value = (char) number);
+ break;
+ };
+ if ((digit = source[4]) != '\'')
+ number = (number * 8) + Character.getNumericValue(digit);
+ value = (char) number;
+ break;
+ }
+ }
+
+ /**
+ * CharLiteral code generation
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param valueRequired boolean
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ if (valueRequired)
+ if ((implicitConversion >> 4) == T_char)
+ codeStream.generateInlinedValue(value);
+ else
+ codeStream.generateConstant(constant, implicitConversion);
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public TypeBinding literalType(BlockScope scope) {
+ return CharBinding;
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ visitor.visit(this, blockScope);
+ visitor.endVisit(this, blockScope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java
new file mode 100644
index 0000000000..9dc92202c8
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java
@@ -0,0 +1,89 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class ClassLiteralAccess extends Expression {
+ public TypeReference type;
+ public TypeBinding targetType;
+ FieldBinding syntheticField;
+
+ public ClassLiteralAccess(int pos, TypeReference t) {
+ type = t;
+ sourceEnd = (sourceStart = pos) + 4; // "class" length - 1
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+
+ // if reachable, request the addition of a synthetic field for caching the class descriptor
+ SourceTypeBinding sourceType =
+ currentScope.outerMostMethodScope().enclosingSourceType();
+ if (!(sourceType.isInterface()
+ // no field generated in interface case (would'nt verify) see 1FHHEZL
+ || sourceType.isBaseType())) {
+ syntheticField = sourceType.addSyntheticField(targetType, currentScope);
+ }
+ return flowInfo;
+ }
+
+ /**
+ * MessageSendDotClass code generation
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param valueRequired boolean
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+
+ // in interface case, no caching occurs, since cannot make a cache field for interface
+ if (valueRequired)
+ codeStream.generateClassLiteralAccessForType(type.binding, syntheticField);
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ constant = NotAConstant;
+ if ((targetType = type.resolveType(scope)) == null)
+ return null;
+
+ if (targetType.isArrayType()
+ && ((ArrayBinding) targetType).leafComponentType == VoidBinding) {
+ scope.problemReporter().cannotAllocateVoidArray(this);
+ return null;
+ }
+
+ return scope.getJavaLangClass();
+ }
+
+ public String toStringExpression() {
+ /*slow code*/
+
+ String s = "";
+ s = s + type.toString(0) + ".class";
+ return s;
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ if (visitor.visit(this, blockScope)) {
+ type.traverse(visitor, blockScope);
+ }
+ visitor.endVisit(this, blockScope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Clinit.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Clinit.java
new file mode 100644
index 0000000000..8a0e9a650f
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Clinit.java
@@ -0,0 +1,174 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.parser.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+public class Clinit extends AbstractMethodDeclaration {
+ public final static char[] ConstantPoolName = "<clinit>".toCharArray();
+ public Clinit() {
+ modifiers = 0;
+ selector = ConstantPoolName;
+ }
+
+ public void analyseCode(
+ ClassScope classScope,
+ InitializationFlowContext staticInitializerFlowContext,
+ FlowInfo flowInfo) {
+
+ if (ignoreFurtherInvestigation)
+ return;
+ try {
+ ExceptionHandlingFlowContext clinitContext =
+ new ExceptionHandlingFlowContext(
+ staticInitializerFlowContext.parent,
+ this,
+ NoExceptions,
+ scope,
+ FlowInfo.DeadEnd);
+
+ // check for missing returning path
+ needFreeReturn =
+ !((flowInfo == FlowInfo.DeadEnd) || flowInfo.isFakeReachable());
+
+ // check missing blank final field initializations
+ flowInfo = flowInfo.mergedWith(staticInitializerFlowContext.initsOnReturn);
+ FieldBinding[] fields = scope.enclosingSourceType().fields();
+ for (int i = 0, count = fields.length; i < count; i++) {
+ FieldBinding field;
+ if ((field = fields[i]).isStatic()
+ && field.isFinal()
+ && (!flowInfo.isDefinitelyAssigned(fields[i]))) {
+ scope.problemReporter().uninitializedBlankFinalField(
+ field,
+ scope.referenceType().declarationOf(field));
+ // can complain against the field decl, since only one <clinit>
+ }
+ }
+ // check static initializers thrown exceptions
+ staticInitializerFlowContext.checkInitializerExceptions(
+ scope,
+ clinitContext,
+ flowInfo);
+ } catch (AbortMethod e) {
+ this.ignoreFurtherInvestigation = true;
+ }
+ }
+
+ /**
+ * Bytecode generation for a <clinit> method
+ *
+ * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope
+ * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile
+ */
+ public void generateCode(ClassScope classScope, ClassFile classFile) {
+ int clinitOffset = 0;
+ if (ignoreFurtherInvestigation) {
+ // should never have to add any <clinit> problem method
+ return;
+ }
+ try {
+ clinitOffset = classFile.contentsOffset;
+ ConstantPool constantPool = classFile.constantPool;
+ int constantPoolOffset = constantPool.currentOffset;
+ int constantPoolIndex = constantPool.currentIndex;
+ classFile.generateMethodInfoHeaderForClinit();
+ int codeAttributeOffset = classFile.contentsOffset;
+ classFile.generateCodeAttributeHeader();
+ CodeStream codeStream = classFile.codeStream;
+ codeStream.reset(this, classFile);
+ TypeDeclaration declaringType = classScope.referenceContext;
+
+ // initialize local positions - including initializer scope.
+ scope.computeLocalVariablePositions(0, codeStream); // should not be necessary
+ MethodScope staticInitializerScope = declaringType.staticInitializerScope;
+ staticInitializerScope.computeLocalVariablePositions(0, codeStream);
+ // offset by the argument size
+
+ // generate initializers
+ if (declaringType.fields != null) {
+ for (int i = 0, max = declaringType.fields.length; i < max; i++) {
+ FieldDeclaration fieldDecl;
+ if ((fieldDecl = declaringType.fields[i]).isStatic()) {
+ fieldDecl.generateCode(staticInitializerScope, codeStream);
+ }
+ }
+ }
+ if (codeStream.position == 0) {
+ // do not need to output a Clinit if no bytecodes
+ // so we reset the offset inside the byte array contents.
+ classFile.contentsOffset = clinitOffset;
+ // like we don't addd a method we need to undo the increment on the method count
+ classFile.methodCount--;
+ // reset the constant pool to its state before the clinit
+ constantPool.resetForClinit(constantPoolIndex, constantPoolOffset);
+ } else {
+ if (needFreeReturn) {
+ int oldPosition = codeStream.position;
+ codeStream.return_();
+ codeStream.updateLocalVariablesAttribute(oldPosition);
+ }
+ // Record the end of the clinit: point to the declaration of the class
+ codeStream.recordPositionsFrom(0, declaringType);
+ classFile.completeCodeAttributeForClinit(codeAttributeOffset);
+ }
+ } catch (AbortMethod e) {
+ // should never occur
+ // the clinit referenceContext is the type declaration
+ // All clinit problems will be reported against the type: AbortType instead of AbortMethod
+ // reset the contentsOffset to the value before generating the clinit code
+ // decrement the number of method info as well.
+ // This is done in the addProblemMethod and addProblemConstructor for other
+ // cases.
+ classFile.contentsOffset = clinitOffset;
+ classFile.methodCount--;
+ }
+ }
+
+ public boolean isClinit() {
+ return true;
+ }
+
+ public boolean isInitializationMethod() {
+ return true;
+ }
+
+ public boolean isStatic() {
+ return true;
+ }
+
+ public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
+ //the clinit is filled by hand ....
+ }
+
+ public void resolve(ClassScope scope) {
+ this.scope = new MethodScope(scope, scope.referenceContext, true);
+ }
+
+ public String toString(int tab) {
+ /* slow code */
+
+ String s = "";
+ s = s + tabString(tab);
+ s = s + "<clinit>()";
+ s = s + toStringStatements(tab + 1);
+ return s;
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ ClassScope classScope) {
+ visitor.visit(this, classScope);
+ visitor.endVisit(this, classScope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java
new file mode 100644
index 0000000000..78a07ae9b5
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java
@@ -0,0 +1,263 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class CompilationUnitDeclaration
+ extends AstNode
+ implements ProblemSeverities, ReferenceContext {
+ public ImportReference currentPackage;
+ public ImportReference[] imports;
+ public TypeDeclaration[] types;
+ //public char[][] name;
+
+ public boolean ignoreFurtherInvestigation = false;
+ // once pointless to investigate due to errors
+ public boolean ignoreMethodBodies = false;
+ /*
+ lookup is done first in the CompilationUnit then
+ on the explicit import types then in the current
+ pakage and finaly into the on demand imports.
+ */
+ public CompilationUnitScope scope;
+ public ProblemReporter problemReporter;
+ public CompilationResult compilationResult;
+ //public ProblemHandler.Policy handlingPolicy;
+
+ private LocalTypeBinding[] allLocalTypes;
+ public boolean isPropagatingInnerClassEmulation;
+ public CompilationUnitDeclaration(
+ ProblemReporter problemReporter,
+ CompilationResult compilationResult,
+ int sourceLength) {
+
+ this.problemReporter = problemReporter;
+ this.compilationResult = compilationResult;
+
+ //by definition of a compilation unit....
+ sourceStart = 0;
+ sourceEnd = sourceLength - 1;
+
+ }
+
+ /*
+ * We cause the compilation task to abort to a given extent.
+ */
+ public void abort(int abortLevel) {
+
+ switch (abortLevel) {
+ case AbortType :
+ throw new AbortType(compilationResult);
+ case AbortMethod :
+ throw new AbortMethod(compilationResult);
+ default :
+ throw new AbortCompilationUnit(compilationResult);
+ }
+ }
+
+ /*
+ * Dispatch code analysis AND request saturation of inner emulation
+ */
+ public void analyseCode() {
+ if (ignoreFurtherInvestigation)
+ return;
+ try {
+ if (types != null) {
+ for (int i = 0, count = types.length; i < count; i++) {
+ types[i].analyseCode(scope);
+ }
+ }
+ // request inner emulation propagation
+ propagateInnerEmulationForAllLocalTypes();
+ } catch (AbortCompilationUnit e) {
+ this.ignoreFurtherInvestigation = true;
+ return;
+ }
+ }
+
+ /*
+ * When unit result is about to be accepted, removed back pointers
+ * to compiler structures.
+ */
+ public void cleanUp() {
+
+ ClassFile[] classFiles = compilationResult.getClassFiles();
+ for (int i = 0, max = classFiles.length; i < max; i++) {
+ // clear the classFile back pointer to the bindings
+ ClassFile classFile = classFiles[i];
+ // null out the type's scope backpointers
+ ((SourceTypeBinding) classFile.referenceBinding).scope = null;
+ // null out the classfile backpointer to a type binding
+ classFile.referenceBinding = null;
+ classFile.codeStream = null; // codeStream holds onto ast and scopes
+ classFile.innerClassesBindings = null;
+ }
+ }
+
+ public CompilationResult compilationResult() {
+ return compilationResult;
+ }
+
+ /*
+ * Finds the matching type amoung this compilation unit types.
+ * Returns null if no type with this name is found.
+ * The type name is a compound name
+ * eg. if we're looking for X.A.B then a type name would be {X, A, B}
+ */
+ public TypeDeclaration declarationOfType(char[][] typeName) {
+ for (int i = 0; i < this.types.length; i++) {
+ TypeDeclaration typeDecl = this.types[i].declarationOfType(typeName);
+ if (typeDecl != null) {
+ return typeDecl;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Bytecode generation
+ */
+ public void generateCode() {
+ if (ignoreFurtherInvestigation) {
+ if (types != null) {
+ for (int i = 0, count = types.length; i < count; i++) {
+ types[i].ignoreFurtherInvestigation = true;
+ // propagate the flag to request problem type creation
+ types[i].generateCode(scope);
+ }
+ }
+ return;
+ }
+ try {
+ if (types != null) {
+ for (int i = 0, count = types.length; i < count; i++)
+ types[i].generateCode(scope);
+ }
+ } catch (AbortCompilationUnit e) {
+ }
+ }
+
+ public char[] getFileName() {
+ return compilationResult.getFileName();
+ }
+
+ public char[] getMainTypeName() {
+ if (compilationResult.compilationUnit == null) {
+ char[] fileName = compilationResult.getFileName();
+
+ int start = CharOperation.lastIndexOf('/', fileName) + 1;
+ if (start == 0 || start < CharOperation.lastIndexOf('\\', fileName))
+ start = CharOperation.lastIndexOf('\\', fileName) + 1;
+
+ int end = CharOperation.lastIndexOf('.', fileName);
+ if (end == -1)
+ end = fileName.length;
+
+ return CharOperation.subarray(fileName, start, end);
+ } else {
+ return compilationResult.compilationUnit.getMainTypeName();
+ }
+ }
+
+ public boolean isEmpty() {
+
+ return (currentPackage == null) && (imports == null) && (types == null);
+ }
+
+ /*
+ * Force inner local types to update their innerclass emulation
+ */
+ public void propagateInnerEmulationForAllLocalTypes() {
+
+ isPropagatingInnerClassEmulation = true;
+ if (allLocalTypes != null) {
+ for (int i = 0, max = allLocalTypes.length; i < max; i++) {
+ allLocalTypes[i].updateInnerEmulationDependents();
+ }
+ }
+ }
+
+ /*
+ * Keep track of all local types, so as to update their innerclass
+ * emulation later on.
+ */
+ public void record(LocalTypeBinding localType) {
+ if (allLocalTypes == null) {
+ allLocalTypes = new LocalTypeBinding[] { localType };
+ } else {
+ int length = allLocalTypes.length;
+ System.arraycopy(
+ allLocalTypes,
+ 0,
+ (allLocalTypes = new LocalTypeBinding[length + 1]),
+ 0,
+ length);
+ allLocalTypes[length] = localType;
+ }
+ }
+
+ public void resolve() {
+ try {
+ if (types != null)
+ for (int i = 0, count = types.length; i < count; i++)
+ types[i].resolve(scope);
+ } catch (AbortCompilationUnit e) {
+ this.ignoreFurtherInvestigation = true;
+ return;
+ }
+ }
+
+ public void tagAsHavingErrors() {
+ ignoreFurtherInvestigation = true;
+ }
+
+ public String toString(int tab) {
+ /*very slow code*/
+
+ String s = "";
+ if (currentPackage != null)
+ s = tabString(tab) + "package " + currentPackage.toString(0, false) + ";\n";
+
+ if (imports != null)
+ for (int i = 0; i < imports.length; i++) {
+ s += tabString(tab) + "import " + imports[i].toString() + ";\n";
+ };
+
+ if (types != null)
+ for (int i = 0; i < types.length; i++) {
+ s += types[i].toString(tab) + "\n";
+ }
+ return s;
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ CompilationUnitScope scope) {
+ if (ignoreFurtherInvestigation)
+ return;
+ try {
+ if (visitor.visit(this, scope)) {
+ if (imports != null) {
+ int importLength = imports.length;
+ for (int i = 0; i < importLength; i++)
+ imports[i].traverse(visitor, scope);
+ }
+ if (types != null) {
+ int typesLength = types.length;
+ for (int i = 0; i < typesLength; i++)
+ types[i].traverse(visitor, scope);
+ }
+ }
+ } catch (AbortCompilationUnit e) {
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java
new file mode 100644
index 0000000000..01ffd26335
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java
@@ -0,0 +1,166 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class CompoundAssignment extends Assignment implements OperatorIds {
+ public int operator;
+ public int assignmentImplicitConversion;
+
+ // var op exp is equivalent to var = (varType) var op exp
+ // assignmentImplicitConversion stores the cast needed for the assignment
+
+ public CompoundAssignment(
+ Expression lhs,
+ Expression expression,
+ int operator) {
+ //lhs is always a reference by construction ,
+ //but is build as an expression ==> the checkcast cannot fail
+
+ super(lhs, expression);
+ this.operator = operator;
+
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ // record setting a variable: various scenarii are possible, setting an array reference,
+ // a field reference, a blank final field reference, a field of an enclosing instance or
+ // just a local variable.
+
+ return lhs
+ .analyseAssignment(currentScope, flowContext, flowInfo, this, true)
+ .unconditionalInits();
+ }
+
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+
+ // various scenarii are possible, setting an array reference,
+ // a field reference, a blank final field reference, a field of an enclosing instance or
+ // just a local variable.
+
+ int pc = codeStream.position;
+ lhs.generateCompoundAssignment(
+ currentScope,
+ codeStream,
+ expression,
+ operator,
+ assignmentImplicitConversion,
+ valueRequired);
+ if (valueRequired) {
+ codeStream.generateImplicitConversion(implicitConversion);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public String operatorToString() {
+ switch (operator) {
+ case PLUS :
+ return "+=";
+ case MINUS :
+ return "-=";
+ case MULTIPLY :
+ return "*=";
+ case DIVIDE :
+ return "/=";
+ case AND :
+ return "&=";
+ case OR :
+ return "|=";
+ case XOR :
+ return "^=";
+ case REMAINDER :
+ return "%=";
+ case LEFT_SHIFT :
+ return "<<=";
+ case RIGHT_SHIFT :
+ return ">>=";
+ case UNSIGNED_RIGHT_SHIFT :
+ return ">>>=";
+ };
+ return "unknown operator";
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ constant = NotAConstant;
+ TypeBinding lhsTb = lhs.resolveType(scope);
+ TypeBinding expressionTb = expression.resolveType(scope);
+ if (lhsTb == null || expressionTb == null)
+ return null;
+
+ int lhsId = lhsTb.id;
+ int expressionId = expressionTb.id;
+ if (restrainUsageToNumericTypes() && !lhsTb.isNumericType()) {
+ scope.problemReporter().operatorOnlyValidOnNumericType(
+ this,
+ lhsTb,
+ expressionTb);
+ return null;
+ }
+ if (lhsId > 15 || expressionId > 15) {
+ if (lhsId != T_String) {
+ // String += Object is valid wheraas Object -= String is not
+ scope.problemReporter().invalidOperator(this, lhsTb, expressionTb);
+ return null;
+ }
+ expressionId = T_Object; // use the Object has tag table
+ }
+
+ // the code is an int
+ // (cast) left Op (cast) rigth --> result
+ // 0000 0000 0000 0000 0000
+ // <<16 <<12 <<8 <<4 <<0
+
+ // the conversion is stored INTO the reference (info needed for the code gen)
+ int result =
+ OperatorExpression.ResolveTypeTables[operator][(lhsId << 4) + expressionId];
+ if (result == T_undefined) {
+ scope.problemReporter().invalidOperator(this, lhsTb, expressionTb);
+ return null;
+ }
+ if (operator == PLUS && scope.isJavaLangObject(lhsTb)) {
+ // Object o = "hello";
+ // o += " world" // <--illegal
+ scope.problemReporter().invalidOperator(this, lhsTb, expressionTb);
+ return null;
+ }
+ lhs.implicitConversion = result >>> 12;
+ expression.implicitConversion = (result >>> 4) & 0x000FF;
+ assignmentImplicitConversion = (lhsId << 4) + (result & 0x0000F);
+ return lhsTb;
+ }
+
+ public boolean restrainUsageToNumericTypes() {
+ return false;
+ }
+
+ public String toStringExpressionNoParenthesis() {
+
+ return lhs.toStringExpression()
+ + " "
+ + operatorToString()
+ + " "
+ + expression.toStringExpression();
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ if (visitor.visit(this, scope)) {
+ lhs.traverse(visitor, scope);
+ expression.traverse(visitor, scope);
+ }
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
new file mode 100644
index 0000000000..0ed5365158
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
@@ -0,0 +1,307 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class ConditionalExpression extends OperatorExpression {
+ public Expression condition, valueIfTrue, valueIfFalse;
+ private int returnTypeSlotSize = 1;
+
+ // for local variables table attributes
+ int thenInitStateIndex = -1;
+ int elseInitStateIndex = -1;
+ int mergedInitStateIndex = -1;
+ public ConditionalExpression(
+ Expression condition,
+ Expression valueIfTrue,
+ Expression valueIfFalse) {
+ this.condition = condition;
+ this.valueIfTrue = valueIfTrue;
+ this.valueIfFalse = valueIfFalse;
+ sourceStart = condition.sourceStart;
+ sourceEnd = valueIfFalse.sourceEnd;
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ Constant inlinedCondition;
+ if ((inlinedCondition = condition.constant) != NotAConstant) {
+ if (inlinedCondition.booleanValue()) {
+ FlowInfo resultInfo =
+ valueIfTrue.analyseCode(currentScope, flowContext, flowInfo);
+ // analyse valueIfFalse, but do not take into account any of its infos
+ valueIfFalse.analyseCode(currentScope, flowContext, flowInfo.copy());
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(resultInfo);
+ return resultInfo;
+ } else {
+ // analyse valueIfTrue, but do not take into account any of its infos
+ valueIfTrue.analyseCode(currentScope, flowContext, flowInfo.copy());
+ FlowInfo mergeInfo =
+ valueIfFalse.analyseCode(currentScope, flowContext, flowInfo);
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(mergeInfo);
+ return mergeInfo;
+ }
+ }
+ // notice that the receiver investigation is not performed in the previous case, since there is
+ // not a chance it is worth trying to check anything on a constant expression.
+
+ flowInfo = condition.analyseCode(currentScope, flowContext, flowInfo);
+
+ // store a copy of the merged info, so as to compute the local variable attributes afterwards
+ thenInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(flowInfo.initsWhenTrue());
+ elseInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(
+ flowInfo.initsWhenFalse());
+ FlowInfo mergedInfo =
+ valueIfTrue
+ .analyseCode(currentScope, flowContext, flowInfo.initsWhenTrue().copy())
+ .unconditionalInits()
+ .mergedWith(
+ valueIfFalse
+ .analyseCode(currentScope, flowContext, flowInfo.initsWhenFalse().copy())
+ .unconditionalInits());
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(mergedInfo);
+ return mergedInfo;
+ }
+
+ /**
+ * Code generation for the conditional operator ?:
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param valueRequired boolean
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+
+ /* Reset the selector of the message pattern to use the optimized selectors,
+ * when compiling full Java messages, if compiling macroexpanded controls, then
+ * the selector is supposed correctly positionned.
+ */
+
+ int pc = codeStream.position, divergePC;
+ Label endifLabel, falseLabel;
+ if (constant != NotAConstant) {
+ if (valueRequired)
+ codeStream.generateConstant(constant, implicitConversion);
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+
+ Constant cst = condition.constant;
+ Constant condCst = condition.conditionalConstant();
+ boolean needTruePart =
+ !(((cst != NotAConstant) && (cst.booleanValue() == false))
+ || ((condCst != NotAConstant) && (condCst.booleanValue() == false)));
+ boolean needFalsePart =
+ !(((cst != NotAConstant) && (cst.booleanValue() == true))
+ || ((condCst != NotAConstant) && (condCst.booleanValue() == true)));
+
+ endifLabel = new Label(codeStream);
+
+ // Generate code for the condition
+ boolean needConditionValue = (cst == NotAConstant) && (condCst == NotAConstant);
+ condition.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ null,
+ (falseLabel = new Label(codeStream)),
+ needConditionValue);
+
+ if (thenInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ thenInitStateIndex);
+ codeStream.addDefinitelyAssignedVariables(currentScope, thenInitStateIndex);
+ }
+
+ // Then code generation
+ if (needTruePart) {
+ valueIfTrue.generateCode(currentScope, codeStream, valueRequired);
+
+ if (needFalsePart) {
+ // Jump over the else part
+ int position = codeStream.position;
+ codeStream.goto_(endifLabel);
+ codeStream.updateLastRecordedEndPC(position);
+ // Tune codestream stack size
+ if (valueRequired) {
+ codeStream.decrStackSize(returnTypeSlotSize);
+ }
+ }
+
+ }
+ if (needFalsePart) {
+ falseLabel.place();
+ if (elseInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ elseInitStateIndex);
+ codeStream.addDefinitelyAssignedVariables(currentScope, elseInitStateIndex);
+ }
+ valueIfFalse.generateCode(currentScope, codeStream, valueRequired);
+
+ // End of if statement
+ endifLabel.place();
+ }
+ // May loose some local variable initializations : affecting the local variable attributes
+ if (mergedInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ mergedInitStateIndex);
+ }
+ // implicit conversion
+ if (valueRequired)
+ codeStream.generateImplicitConversion(implicitConversion);
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ // specs p.368
+ constant = NotAConstant;
+ TypeBinding condTb = condition.resolveTypeExpecting(scope, BooleanBinding);
+ TypeBinding trueTb = valueIfTrue.resolveType(scope);
+ TypeBinding falseTb = valueIfFalse.resolveType(scope);
+ if (condTb == null || trueTb == null || falseTb == null)
+ return null;
+
+ // Propagate the constant value from the valueIfTrue and valueIFFalse expression if it is possible
+ if (condition.constant != NotAConstant
+ && valueIfTrue.constant != NotAConstant
+ && valueIfFalse.constant != NotAConstant) {
+ // all terms are constant expression so we can propagate the constant
+ // from valueIFTrue or valueIfFalse to teh receiver constant
+ constant =
+ (condition.constant.booleanValue())
+ ? valueIfTrue.constant
+ : valueIfFalse.constant;
+ }
+ if (trueTb == falseTb) { // harmed the implicit conversion
+ valueIfTrue.implicitWidening(trueTb, trueTb);
+ valueIfFalse.implicitConversion = valueIfTrue.implicitConversion;
+ if (trueTb == LongBinding || trueTb == DoubleBinding) {
+ returnTypeSlotSize = 2;
+ }
+ return trueTb;
+ }
+
+ // Determine the return type depending on argument types
+ // Numeric types
+ if (trueTb.isNumericType() && falseTb.isNumericType()) {
+ // (Short x Byte) or (Byte x Short)"
+ if ((trueTb == ByteBinding && falseTb == ShortBinding)
+ || (trueTb == ShortBinding && falseTb == ByteBinding)) {
+ valueIfTrue.implicitWidening(ShortBinding, trueTb);
+ valueIfFalse.implicitWidening(ShortBinding, falseTb);
+ return ShortBinding;
+ }
+
+ // <Byte|Short|Char> x constant(Int) ---> <Byte|Short|Char> and reciprocally
+ if ((trueTb == ByteBinding || trueTb == ShortBinding || trueTb == CharBinding)
+ && (falseTb == IntBinding
+ && valueIfFalse.isConstantValueOfTypeAssignableToType(falseTb, trueTb))) {
+ valueIfTrue.implicitWidening(trueTb, trueTb);
+ valueIfFalse.implicitWidening(trueTb, falseTb);
+ return trueTb;
+ }
+ if ((falseTb == ByteBinding
+ || falseTb == ShortBinding
+ || falseTb == CharBinding)
+ && (trueTb == IntBinding
+ && valueIfTrue.isConstantValueOfTypeAssignableToType(trueTb, falseTb))) {
+ valueIfTrue.implicitWidening(falseTb, trueTb);
+ valueIfFalse.implicitWidening(falseTb, falseTb);
+ return falseTb;
+ }
+
+ // Manual binary numeric promotion
+ // int
+ if (BaseTypeBinding.isNarrowing(trueTb.id, T_int)
+ && BaseTypeBinding.isNarrowing(falseTb.id, T_int)) {
+ valueIfTrue.implicitWidening(IntBinding, trueTb);
+ valueIfFalse.implicitWidening(IntBinding, falseTb);
+ return IntBinding;
+ }
+ // long
+ if (BaseTypeBinding.isNarrowing(trueTb.id, T_long)
+ && BaseTypeBinding.isNarrowing(falseTb.id, T_long)) {
+ valueIfTrue.implicitWidening(LongBinding, trueTb);
+ valueIfFalse.implicitWidening(LongBinding, falseTb);
+ returnTypeSlotSize = 2;
+ return LongBinding;
+ }
+ // float
+ if (BaseTypeBinding.isNarrowing(trueTb.id, T_float)
+ && BaseTypeBinding.isNarrowing(falseTb.id, T_float)) {
+ valueIfTrue.implicitWidening(FloatBinding, trueTb);
+ valueIfFalse.implicitWidening(FloatBinding, falseTb);
+ return FloatBinding;
+ }
+ // double
+ valueIfTrue.implicitWidening(DoubleBinding, trueTb);
+ valueIfFalse.implicitWidening(DoubleBinding, falseTb);
+ returnTypeSlotSize = 2;
+ return DoubleBinding;
+ }
+
+ // Type references (null null is already tested)
+ if ((trueTb.isBaseType() && trueTb != NullBinding)
+ || (falseTb.isBaseType() && falseTb != NullBinding)) {
+ scope.problemReporter().conditionalArgumentsIncompatibleTypes(
+ this,
+ trueTb,
+ falseTb);
+ return null;
+ }
+ if (scope.areTypesCompatible(falseTb, trueTb)) {
+ valueIfTrue.implicitWidening(trueTb, trueTb);
+ valueIfFalse.implicitWidening(trueTb, falseTb);
+ return trueTb;
+ }
+ if (scope.areTypesCompatible(trueTb, falseTb)) {
+ valueIfTrue.implicitWidening(falseTb, trueTb);
+ valueIfFalse.implicitWidening(falseTb, falseTb);
+ return falseTb;
+ }
+ scope.problemReporter().conditionalArgumentsIncompatibleTypes(
+ this,
+ trueTb,
+ falseTb);
+ return null;
+ }
+
+ public String toStringExpressionNoParenthesis() {
+ /* slow code*/
+
+ return condition.toStringExpression()
+ + " ? "
+ + valueIfTrue.toStringExpression()
+ + " : "
+ + valueIfFalse.toStringExpression();
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ if (visitor.visit(this, scope)) {
+ condition.traverse(visitor, scope);
+ valueIfTrue.traverse(visitor, scope);
+ valueIfFalse.traverse(visitor, scope);
+ }
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java
new file mode 100644
index 0000000000..73977014dc
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java
@@ -0,0 +1,342 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.parser.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class ConstructorDeclaration extends AbstractMethodDeclaration {
+ public ExplicitConstructorCall constructorCall;
+ public final static char[] ConstantPoolName = "<init>".toCharArray();
+ public boolean isDefaultConstructor = false;
+
+ public int referenceCount = 0;
+ // count how many times this constructor is referenced from other local constructors
+ public void analyseCode(
+ ClassScope classScope,
+ InitializationFlowContext initializerFlowContext,
+ FlowInfo flowInfo) {
+ if (ignoreFurtherInvestigation)
+ return;
+ try {
+ ExceptionHandlingFlowContext constructorContext =
+ new ExceptionHandlingFlowContext(
+ initializerFlowContext.parent,
+ this,
+ binding.thrownExceptions,
+ scope,
+ FlowInfo.DeadEnd);
+ initializerFlowContext.checkInitializerExceptions(
+ scope,
+ constructorContext,
+ flowInfo);
+
+ // propagate to constructor call
+ if (constructorCall != null) {
+ // if calling 'this(...)', then flag all non-static fields as definitely
+ // set since they are supposed to be set inside other local constructor
+ if (constructorCall.accessMode == ExplicitConstructorCall.This) {
+ FieldBinding[] fields = binding.declaringClass.fields();
+ for (int i = 0, count = fields.length; i < count; i++) {
+ FieldBinding field;
+ if (!(field = fields[i]).isStatic()) {
+ flowInfo.markAsDefinitelyAssigned(field);
+ }
+ }
+ }
+ flowInfo = constructorCall.analyseCode(scope, constructorContext, flowInfo);
+ }
+ // propagate to statements
+ if (statements != null) {
+ for (int i = 0, count = statements.length; i < count; i++) {
+ Statement stat;
+ if (!flowInfo.complainIfUnreachable((stat = statements[i]), scope)) {
+ flowInfo = stat.analyseCode(scope, constructorContext, flowInfo);
+ }
+ }
+ }
+ // check for missing returning path
+ needFreeReturn =
+ !((flowInfo == FlowInfo.DeadEnd) || flowInfo.isFakeReachable());
+
+ // check missing blank final field initializations
+ if ((constructorCall != null)
+ && (constructorCall.accessMode != ExplicitConstructorCall.This)) {
+ flowInfo = flowInfo.mergedWith(initializerFlowContext.initsOnReturn);
+ FieldBinding[] fields = binding.declaringClass.fields();
+ for (int i = 0, count = fields.length; i < count; i++) {
+ FieldBinding field;
+ if ((!(field = fields[i]).isStatic())
+ && field.isFinal()
+ && (!flowInfo.isDefinitelyAssigned(fields[i]))) {
+ scope.problemReporter().uninitializedBlankFinalField(
+ field,
+ isDefaultConstructor ? (AstNode) scope.referenceType() : this);
+ }
+ }
+ }
+ } catch (AbortMethod e) {
+ this.ignoreFurtherInvestigation = true;
+ }
+ }
+
+ public void checkName() {
+ //look if the name of the method is correct
+ //and proceed with the resolution of the special constructor statement
+
+ if (!CharOperation.equals(scope.enclosingSourceType().sourceName, selector))
+ scope.problemReporter().missingReturnType(this);
+
+ // if null ==> an error has occurs at parsing time ....
+ if (constructorCall != null) {
+ // e.g. using super() in java.lang.Object
+ if ((binding.declaringClass.id == T_Object)
+ && (constructorCall.accessMode != ExplicitConstructorCall.This)) {
+ if (constructorCall.accessMode == ExplicitConstructorCall.Super) {
+ scope.problemReporter().cannotUseSuperInJavaLangObject(constructorCall);
+ }
+ constructorCall = null;
+ return;
+ }
+ constructorCall.resolve(scope);
+ }
+ }
+
+ /**
+ * Bytecode generation for a constructor
+ *
+ * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope
+ * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile
+ */
+ public void generateCode(ClassScope classScope, ClassFile classFile) {
+ int problemResetPC = 0;
+ if (ignoreFurtherInvestigation) {
+ if (this.binding == null)
+ return; // Handle methods with invalid signature or duplicates
+ int problemsLength;
+ IProblem[] problems =
+ scope.referenceCompilationUnit().compilationResult.getProblems();
+ IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
+ System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
+ classFile.addProblemConstructor(this, binding, problemsCopy);
+ return;
+ }
+ try {
+ problemResetPC = classFile.contentsOffset;
+ classFile.generateMethodInfoHeader(binding);
+ int methodAttributeOffset = classFile.contentsOffset;
+ int attributeNumber = classFile.generateMethodInfoAttribute(binding);
+ if ((!binding.isNative()) && (!binding.isAbstract())) {
+ TypeDeclaration declaringType = classScope.referenceContext;
+ int codeAttributeOffset = classFile.contentsOffset;
+ classFile.generateCodeAttributeHeader();
+ CodeStream codeStream = classFile.codeStream;
+ codeStream.reset(this, classFile);
+ // initialize local positions - including initializer scope.
+ ReferenceBinding declaringClass = binding.declaringClass;
+ int argSize = 0;
+ scope.computeLocalVariablePositions(// consider synthetic arguments if any
+ argSize =
+ declaringClass.isNestedType()
+ ? ((NestedTypeBinding) declaringClass).syntheticArgumentsOffset
+ : 1,
+ codeStream);
+ if (arguments != null) {
+ for (int i = 0, max = arguments.length; i < max; i++) {
+ // arguments initialization for local variable debug attributes
+ LocalVariableBinding argBinding;
+ codeStream.addVisibleLocalVariable(argBinding = arguments[i].binding);
+ argBinding.recordInitializationStartPC(0);
+ TypeBinding argType;
+ if ((argType = argBinding.type) == LongBinding || (argType == DoubleBinding)) {
+ argSize += 2;
+ } else {
+ argSize++;
+ }
+ }
+ }
+ MethodScope initializerScope = declaringType.initializerScope;
+ initializerScope.computeLocalVariablePositions(argSize, codeStream);
+ // offset by the argument size (since not linked to method scope)
+
+ // generate constructor call
+ if (constructorCall != null) {
+ constructorCall.generateCode(scope, codeStream);
+ }
+ // generate field initialization - only if not invoking another constructor call of the same class
+ if ((constructorCall != null)
+ && (constructorCall.accessMode != ExplicitConstructorCall.This)) {
+ // generate synthetic fields initialization
+ if (declaringClass.isNestedType()) {
+ NestedTypeBinding nestedType = (NestedTypeBinding) declaringClass;
+ SyntheticArgumentBinding[] syntheticArgs =
+ nestedType.syntheticEnclosingInstances();
+ for (int i = 0, max = syntheticArgs == null ? 0 : syntheticArgs.length;
+ i < max;
+ i++) {
+ if (syntheticArgs[i].matchingField != null) {
+ codeStream.aload_0();
+ codeStream.load(syntheticArgs[i]);
+ codeStream.putfield(syntheticArgs[i].matchingField);
+ }
+ }
+ syntheticArgs = nestedType.syntheticOuterLocalVariables();
+ for (int i = 0, max = syntheticArgs == null ? 0 : syntheticArgs.length;
+ i < max;
+ i++) {
+ if (syntheticArgs[i].matchingField != null) {
+ codeStream.aload_0();
+ codeStream.load(syntheticArgs[i]);
+ codeStream.putfield(syntheticArgs[i].matchingField);
+ }
+ }
+ }
+ // generate user field initialization
+ if (declaringType.fields != null) {
+ for (int i = 0, max = declaringType.fields.length; i < max; i++) {
+ FieldDeclaration fieldDecl;
+ if (!(fieldDecl = declaringType.fields[i]).isStatic()) {
+ fieldDecl.generateCode(initializerScope, codeStream);
+ }
+ }
+ }
+ }
+ // generate statements
+ if (statements != null) {
+ for (int i = 0, max = statements.length; i < max; i++) {
+ statements[i].generateCode(scope, codeStream);
+ }
+ }
+ if (needFreeReturn) {
+ codeStream.return_();
+ }
+ // local variable attributes
+ codeStream.exitUserScope(scope);
+ codeStream.recordPositionsFrom(0, this);
+ classFile.completeCodeAttribute(codeAttributeOffset);
+ attributeNumber++;
+ }
+ classFile.completeMethodInfo(methodAttributeOffset, attributeNumber);
+
+ // if a problem got reported during code gen, then trigger problem method creation
+ if (ignoreFurtherInvestigation) {
+ throw new AbortMethod(scope.referenceCompilationUnit().compilationResult);
+ }
+ } catch (AbortMethod e) {
+ int problemsLength;
+ IProblem[] problems =
+ scope.referenceCompilationUnit().compilationResult.getProblems();
+ IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
+ System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
+ classFile.addProblemConstructor(this, binding, problemsCopy, problemResetPC);
+ }
+ }
+
+ public boolean isConstructor() {
+ return true;
+ }
+
+ public boolean isDefaultConstructor() {
+ return isDefaultConstructor;
+ }
+
+ public boolean isInitializationMethod() {
+ return true;
+ }
+
+ public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
+ //fill up the constructor body with its statements
+
+ if (ignoreFurtherInvestigation)
+ return;
+ if (isDefaultConstructor)
+ return;
+ parser.parse(this, unit);
+
+ }
+
+ /*
+ * Type checking for constructor, just another method, except for special check
+ * for recursive constructor invocations.
+ */
+ public void resolve(ClassScope upperScope) {
+
+ if (binding == null) {
+ ignoreFurtherInvestigation = true;
+ return;
+ }
+
+ super.resolve(upperScope);
+
+ try {
+ // checking for recursive constructor call
+ if (constructorCall != null) {
+ // indirect reference: increment target constructor reference count
+ if (constructorCall.binding != null
+ && !constructorCall.isSuperAccess()
+ && constructorCall.binding.isValidBinding()) {
+ (
+ (ConstructorDeclaration)
+ (
+ upperScope.referenceContext.declarationOf(
+ constructorCall.binding))).referenceCount++;
+ }
+ }
+ } catch (AbortMethod e) {
+ this.ignoreFurtherInvestigation = true;
+ }
+ }
+
+ public String toStringStatements(int tab) {
+ /* slow code */
+
+ String s = " {";
+ if (constructorCall != null) {
+ s = s + "\n" + constructorCall.toString(tab) + ";";
+ }
+ if (statements != null) {
+ for (int i = 0; i < statements.length; i++) {
+ s = s + "\n" + statements[i].toString(tab);
+ if (!(statements[i] instanceof Block)) {
+ s += ";";
+ }
+ }
+ }
+ s += "\n" + tabString(tab == 0 ? 0 : tab - 1) + "}";
+ return s;
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ ClassScope classScope) {
+ if (visitor.visit(this, classScope)) {
+ if (arguments != null) {
+ int argumentLength = arguments.length;
+ for (int i = 0; i < argumentLength; i++)
+ arguments[i].traverse(visitor, scope);
+ }
+ if (thrownExceptions != null) {
+ int thrownExceptionsLength = thrownExceptions.length;
+ for (int i = 0; i < thrownExceptionsLength; i++)
+ thrownExceptions[i].traverse(visitor, scope);
+ }
+ if (constructorCall != null)
+ constructorCall.traverse(visitor, scope);
+ if (statements != null) {
+ int statementsLength = statements.length;
+ for (int i = 0; i < statementsLength; i++)
+ statements[i].traverse(visitor, scope);
+ }
+ }
+ visitor.endVisit(this, classScope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Continue.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Continue.java
new file mode 100644
index 0000000000..3a524e5060
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Continue.java
@@ -0,0 +1,101 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class Continue extends BranchStatement {
+
+ public Continue(char[] l, int s, int e) {
+ super(l, s, e);
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+
+ // here requires to generate a sequence of finally blocks invocations depending corresponding
+ // to each of the traversed try statements, so that execution will terminate properly.
+
+ // lookup the label, this should answer the returnContext
+ FlowContext targetContext;
+ if (label == null) {
+ targetContext = flowContext.getTargetContextForDefaultContinue();
+ } else {
+ targetContext = flowContext.getTargetContextForContinueLabel(label);
+ }
+ if (targetContext == null) {
+ if (label == null) {
+ currentScope.problemReporter().invalidContinue(this);
+ } else {
+ currentScope.problemReporter().undefinedLabel(this); // need to improve
+ }
+ } else {
+ if (targetContext == FlowContext.NotContinuableContext) {
+ currentScope.problemReporter().invalidContinue(this);
+ return FlowInfo.DeadEnd;
+ }
+ targetLabel = targetContext.continueLabel();
+ targetContext.recordContinueFrom(flowInfo);
+ FlowContext traversedContext = flowContext;
+ int subIndex = 0, maxSub = 5;
+ subroutines = new AstNode[maxSub];
+ while (true) {
+ AstNode sub;
+ if ((sub = traversedContext.subRoutine()) != null) {
+ if (subIndex == maxSub) {
+ System.arraycopy(
+ subroutines,
+ 0,
+ (subroutines = new AstNode[maxSub *= 2]),
+ 0,
+ subIndex);
+ // grow
+ }
+ subroutines[subIndex++] = sub;
+ if (sub.cannotReturn()) {
+ break;
+ }
+ }
+ if (traversedContext == targetContext) {
+ break;
+ } else {
+ traversedContext = traversedContext.parent;
+ }
+ }
+ // resize subroutines
+ if (subIndex != maxSub) {
+ System.arraycopy(
+ subroutines,
+ 0,
+ (subroutines = new AstNode[subIndex]),
+ 0,
+ subIndex);
+ }
+ }
+ return FlowInfo.DeadEnd;
+ }
+
+ public String toString(int tab) {
+ /* slow code */
+
+ String s = tabString(tab);
+ s = s + "continue ";
+ if (label != null)
+ s = s + new String(label);
+ return s;
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ visitor.visit(this, blockScope);
+ visitor.endVisit(this, blockScope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DefaultCase.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DefaultCase.java
new file mode 100644
index 0000000000..7583a8a9a7
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DefaultCase.java
@@ -0,0 +1,77 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class DefaultCase extends Statement {
+
+ public CaseLabel targetLabel;
+ /**
+ * DefautCase constructor comment.
+ */
+ public DefaultCase(int startPosition) {
+ this.sourceStart = startPosition;
+ this.sourceEnd = startPosition + 6; //default.length-1 (good approximation)
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ return flowInfo;
+ }
+
+ /**
+ * Default case code generation
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ */
+ public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+
+ if ((bits & IsReachableMASK) == 0) {
+ return;
+ }
+ int pc = codeStream.position;
+ targetLabel.place();
+ codeStream.recordPositionsFrom(pc, this);
+
+ }
+
+ public Constant resolveCase(
+ BlockScope scope,
+ TypeBinding testType,
+ SwitchStatement switchStatement) {
+ // remember the default case into the associated switch statement
+ if (switchStatement.defaultCase != null)
+ scope.problemReporter().duplicateDefaultCase(this);
+
+ // on error the last default will be the selected one .... (why not) ....
+ switchStatement.defaultCase = this;
+ resolve(scope);
+ return null;
+ }
+
+ public String toString(int tab) {
+ /* slow code */
+
+ String s = tabString(tab);
+ s = s + "default : ";
+ return s;
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ visitor.visit(this, blockScope);
+ visitor.endVisit(this, blockScope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DoStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DoStatement.java
new file mode 100644
index 0000000000..aaa12ea8c4
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DoStatement.java
@@ -0,0 +1,185 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class DoStatement extends Statement {
+ public Expression condition;
+ public Statement action;
+
+ private Label breakLabel, continueLabel;
+
+ // for local variables table attributes
+ int mergedInitStateIndex = -1;
+ public DoStatement(Expression condition, Statement action, int s, int e) {
+ this.sourceStart = s;
+ this.sourceEnd = e;
+ this.condition = condition;
+ this.action = action;
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ breakLabel = new Label();
+ continueLabel = new Label();
+ LoopingFlowContext loopingContext =
+ new LoopingFlowContext(
+ flowContext,
+ this,
+ breakLabel,
+ continueLabel,
+ currentScope);
+
+ Constant conditionConstant = condition.constant;
+ Constant conditionalConstant = condition.conditionalConstant();
+ boolean isFalseCondition =
+ ((conditionConstant != NotAConstant)
+ && (conditionConstant.booleanValue() == false))
+ || ((conditionalConstant != NotAConstant)
+ && (conditionalConstant.booleanValue() == false));
+
+ if ((action != null) && !action.isEmptyBlock()) {
+ //if (!flowInfo.complainIfUnreachable(this, currentScope)){ // probably useless since would be tested outside the do
+ flowInfo = action.analyseCode(currentScope, loopingContext, flowInfo.copy());
+ // unnecessary to check here}
+
+ // code generation can be optimized when no need to continue in the loop
+ if ((flowInfo == FlowInfo.DeadEnd) || flowInfo.isFakeReachable()) {
+ if ((loopingContext.initsOnContinue == FlowInfo.DeadEnd)
+ || loopingContext.initsOnContinue.isFakeReachable()) {
+ continueLabel = null;
+ } else {
+ flowInfo = loopingContext.initsOnContinue; // for condition
+ if (isFalseCondition) {
+ // continueLabel = null; - cannot nil the label since may be targeted already by 'continue' statements
+ } else {
+ loopingContext.complainOnFinalAssignmentsInLoop(currentScope, flowInfo);
+ }
+ }
+ } else {
+ if (isFalseCondition) {
+ // continueLabel = null; - cannot nil the label since may be targeted already by 'continue' statements
+ } else {
+ loopingContext.complainOnFinalAssignmentsInLoop(currentScope, flowInfo);
+ }
+ }
+ }
+ LoopingFlowContext condLoopContext;
+ flowInfo =
+ condition.analyseCode(
+ currentScope,
+ (condLoopContext =
+ new LoopingFlowContext(flowContext, this, null, null, currentScope)),
+ (action == null
+ ? flowInfo
+ : (flowInfo.mergedWith(loopingContext.initsOnContinue))));
+ condLoopContext.complainOnFinalAssignmentsInLoop(currentScope, flowInfo);
+
+ // infinite loop
+ FlowInfo mergedInfo;
+ if ((condition.constant != NotAConstant)
+ && (condition.constant.booleanValue() == true)) {
+ mergedInfo = loopingContext.initsOnBreak;
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(mergedInfo);
+ return mergedInfo;
+ }
+
+ // end of loop: either condition false or break
+ mergedInfo =
+ flowInfo.initsWhenFalse().unconditionalInits().mergedWith(
+ loopingContext.initsOnBreak);
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(mergedInfo);
+ return mergedInfo;
+ }
+
+ /**
+ * Do statement code generation
+ *
+ */
+ public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+
+ if ((bits & IsReachableMASK) == 0) {
+ return;
+ }
+ int pc = codeStream.position;
+
+ // labels management
+ Label actionLabel = new Label(codeStream);
+ actionLabel.place();
+ breakLabel.codeStream = codeStream;
+ if (continueLabel != null) {
+ continueLabel.codeStream = codeStream;
+ }
+
+ // generate action
+ if (action != null) {
+ action.generateCode(currentScope, codeStream);
+ }
+ // generate condition
+ if (continueLabel != null) {
+ continueLabel.place();
+ condition.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ actionLabel,
+ null,
+ true);
+ }
+ breakLabel.place();
+
+ // May loose some local variable initializations : affecting the local variable attributes
+ if (mergedInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ mergedInitStateIndex);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+
+ }
+
+ public void resolve(BlockScope scope) {
+ TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding);
+ condition.implicitWidening(type, type);
+ if (action != null)
+ action.resolve(scope);
+ }
+
+ public String toString(int tab) {
+ /* slow code */
+
+ String inFront, s = tabString(tab);
+ inFront = s;
+ s = s + "do";
+ if (action == null)
+ s = s + " {}\n";
+ else
+ if (action instanceof Block)
+ s = s + "\n" + action.toString(tab + 1) + "\n";
+ else
+ s = s + " {\n" + action.toString(tab + 1) + ";}\n";
+ s = s + inFront + "while (" + condition.toStringExpression() + ")";
+ return s;
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ if (visitor.visit(this, scope)) {
+ if (action != null) {
+ action.traverse(visitor, scope);
+ }
+ condition.traverse(visitor, scope);
+ }
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DoubleLiteral.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DoubleLiteral.java
new file mode 100644
index 0000000000..73e8e4e172
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DoubleLiteral.java
@@ -0,0 +1,87 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class DoubleLiteral extends NumberLiteral {
+ double value;
+ public DoubleLiteral(char[] token, int s, int e) {
+ super(token, s, e);
+ }
+
+ public void computeConstant() {
+
+ //the source is correctly formated so the exception should never occurs
+
+ Double computedValue;
+ try {
+ computedValue = Double.valueOf(String.valueOf(source));
+ } catch (NumberFormatException e) {
+ return;
+ } //how can it happen ????
+
+ if (computedValue.doubleValue() > Double.MAX_VALUE)
+ return; //may be Infinity
+ if (computedValue.doubleValue() < Double.MIN_VALUE) {
+ //only a true 0 can be made of zeros :-)
+ //2.00000000000000000e-324 is illegal ....
+ label : for (
+ int i = 0;
+ i < source.length;
+ i++) { //it is welled formated so just test against '0' and potential . D d
+ switch (source[i]) {
+ case '0' :
+ case '.' :
+ case 'd' :
+ case 'D' :
+ break;
+ case 'e' :
+ case 'E' :
+ break label; //exposant are valid....!
+ default :
+ return;
+ }
+ }
+ } //error
+
+ constant = Constant.fromValue(value = computedValue.doubleValue());
+ }
+
+ /**
+ * Code generation for the double literak
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param valueRequired boolean
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ if (valueRequired)
+ if ((implicitConversion >> 4) == T_double)
+ codeStream.generateInlinedValue(value);
+ else
+ codeStream.generateConstant(constant, implicitConversion);
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public TypeBinding literalType(BlockScope scope) {
+ return DoubleBinding;
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ visitor.visit(this, blockScope);
+ visitor.endVisit(this, blockScope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java
new file mode 100644
index 0000000000..9ca9e8fc55
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java
@@ -0,0 +1,646 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class EqualExpression extends BinaryExpression {
+
+ public EqualExpression(Expression left, Expression right, int operator) {
+ super(left, right, operator);
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ if (((bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
+ if ((left.constant != NotAConstant) && (left.constant.typeID() == T_boolean)) {
+ if (left.constant.booleanValue()) { // true == anything
+ // this is equivalent to the right argument inits
+ return right.analyseCode(currentScope, flowContext, flowInfo);
+ } else { // false == anything
+ // this is equivalent to the right argument inits negated
+ return right
+ .analyseCode(currentScope, flowContext, flowInfo)
+ .asNegatedCondition();
+ }
+ }
+ if ((right.constant != NotAConstant)
+ && (right.constant.typeID() == T_boolean)) {
+ if (right.constant.booleanValue()) { // anything == true
+ // this is equivalent to the right argument inits
+ return left.analyseCode(currentScope, flowContext, flowInfo);
+ } else { // anything == false
+ // this is equivalent to the right argument inits negated
+ return left
+ .analyseCode(currentScope, flowContext, flowInfo)
+ .asNegatedCondition();
+ }
+ }
+ return right
+ .analyseCode(
+ currentScope,
+ flowContext,
+ left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits())
+ .unconditionalInits();
+ } else { //NOT_EQUAL :
+ if ((left.constant != NotAConstant) && (left.constant.typeID() == T_boolean)) {
+ if (!left.constant.booleanValue()) { // false != anything
+ // this is equivalent to the right argument inits
+ return right.analyseCode(currentScope, flowContext, flowInfo);
+ } else { // true != anything
+ // this is equivalent to the right argument inits negated
+ return right
+ .analyseCode(currentScope, flowContext, flowInfo)
+ .asNegatedCondition();
+ }
+ }
+ if ((right.constant != NotAConstant)
+ && (right.constant.typeID() == T_boolean)) {
+ if (!right.constant.booleanValue()) { // anything != false
+ // this is equivalent to the right argument inits
+ return left.analyseCode(currentScope, flowContext, flowInfo);
+ } else { // anything != true
+ // this is equivalent to the right argument inits negated
+ return left
+ .analyseCode(currentScope, flowContext, flowInfo)
+ .asNegatedCondition();
+ }
+ }
+ return right
+ .analyseCode(
+ currentScope,
+ flowContext,
+ left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits())
+ .asNegatedCondition()
+ .unconditionalInits();
+ }
+ }
+
+ public final boolean areTypesCastCompatible(
+ BlockScope scope,
+ TypeBinding castTb,
+ TypeBinding expressionTb) {
+ //see specifications p.68
+ //A more complete version of this method is provided on
+ //CastExpression (it deals with constant and need runtime checkcast)
+
+ //========ARRAY===============
+ if (expressionTb.isArrayType()) {
+ if (castTb.isArrayType()) {
+ //------- (castTb.isArray) expressionTb.isArray -----------
+ TypeBinding expressionEltTb = ((ArrayBinding) expressionTb).elementsType(scope);
+ if (expressionEltTb.isBaseType())
+ // <---stop the recursion-------
+ return ((ArrayBinding) castTb).elementsType(scope) == expressionEltTb;
+ //recursivly on the elts...
+ return areTypesCastCompatible(
+ scope,
+ ((ArrayBinding) castTb).elementsType(scope),
+ expressionEltTb);
+ }
+ if (castTb.isBaseType()) {
+ return false;
+ }
+ if (castTb.isClass()) {
+ //------(castTb.isClass) expressionTb.isArray ---------------
+ if (scope.isJavaLangObject(castTb))
+ return true;
+ return false;
+ }
+ if (castTb.isInterface()) {
+ //------- (castTb.isInterface) expressionTb.isArray -----------
+ if (scope.isJavaLangCloneable(castTb) || scope.isJavaIoSerializable(castTb)) {
+ return true;
+ }
+ return false;
+ }
+
+ //===houps=====
+ return false;
+ }
+
+ //------------(castType) null--------------
+ if (expressionTb == NullBinding) {
+ return !castTb.isBaseType();
+ }
+
+ //========BASETYPE==============
+ if (expressionTb.isBaseType()) {
+ return false;
+ }
+
+ //========REFERENCE TYPE===================
+
+ if (expressionTb.isClass()) {
+ if (castTb.isArrayType()) {
+ // ---- (castTb.isArray) expressionTb.isClass -------
+ if (scope.isJavaLangObject(expressionTb))
+ return true;
+ }
+ if (castTb.isBaseType()) {
+ return false;
+ }
+ if (castTb.isClass()) { // ----- (castTb.isClass) expressionTb.isClass ------
+ if (scope.areTypesCompatible(expressionTb, castTb))
+ return true;
+ else {
+ if (scope.areTypesCompatible(castTb, expressionTb)) {
+ return true;
+ }
+ return false;
+ }
+ }
+ if (castTb.isInterface()) {
+ // ----- (castTb.isInterface) expressionTb.isClass -------
+ if (((ReferenceBinding) expressionTb).isFinal()) {
+ //no subclass for expressionTb, thus compile-time check is valid
+ if (scope.areTypesCompatible(expressionTb, castTb))
+ return true;
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ //=========houps=============
+ return false;
+ }
+ if (expressionTb.isInterface()) {
+ if (castTb.isArrayType()) {
+ // ----- (castTb.isArray) expressionTb.isInterface ------
+ if (scope.isJavaLangCloneable(expressionTb)
+ || scope.isJavaIoSerializable(expressionTb))
+ //potential runtime error
+ {
+ return true;
+ }
+ return false;
+ }
+ if (castTb.isBaseType()) {
+ return false;
+ }
+ if (castTb.isClass()) {
+ // ----- (castTb.isClass) expressionTb.isInterface --------
+ if (scope.isJavaLangObject(castTb))
+ return true;
+ if (((ReferenceBinding) castTb).isFinal()) {
+ //no subclass for castTb, thus compile-time check is valid
+ if (scope.areTypesCompatible(castTb, expressionTb)) {
+ return true;
+ }
+ return false;
+ }
+ return true;
+ }
+ if (castTb.isInterface()) {
+ // ----- (castTb.isInterface) expressionTb.isInterface -------
+ if (castTb != expressionTb
+ && (scope.compareTypes(castTb, expressionTb) == NotRelated)) {
+ MethodBinding[] castTbMethods = ((ReferenceBinding) castTb).methods();
+ int castTbMethodsLength = castTbMethods.length;
+ MethodBinding[] expressionTbMethods =
+ ((ReferenceBinding) expressionTb).methods();
+ int expressionTbMethodsLength = expressionTbMethods.length;
+ for (int i = 0; i < castTbMethodsLength; i++) {
+ for (int j = 0; j < expressionTbMethodsLength; j++) {
+ if (castTbMethods[i].selector == expressionTbMethods[j].selector) {
+ if (castTbMethods[i].returnType != expressionTbMethods[j].returnType) {
+ if (castTbMethods[i].areParametersEqual(expressionTbMethods[j])) {
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ //=========hoops===========
+ return false;
+ }
+
+ //==========HOUPS==========
+ return false;
+ }
+
+ public final void computeConstant(TypeBinding leftTb, TypeBinding rightTb) {
+
+ if ((left.constant != NotAConstant) && (right.constant != NotAConstant)) {
+ constant =
+ Constant.computeConstantOperationEQUAL_EQUAL(
+ left.constant,
+ rightTb.id,
+ EQUAL_EQUAL,
+ right.constant,
+ rightTb.id);
+ if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT_EQUAL)
+ constant = Constant.fromValue(!constant.booleanValue());
+ } else
+ constant = NotAConstant;
+ }
+
+ /**
+ * Normal == or != code generation
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param valueRequired boolean
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+
+ if (constant != NotAConstant) {
+ int pc = codeStream.position;
+ if (valueRequired)
+ codeStream.generateConstant(constant, implicitConversion);
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ Label falseLabel = new Label(codeStream);
+ generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ null,
+ falseLabel,
+ valueRequired);
+ if (valueRequired) {
+ // comparison is TRUE
+ codeStream.iconst_1();
+ if ((bits & ValueForReturnMASK) != 0) {
+ codeStream.ireturn();
+ // comparison is FALSE
+ falseLabel.place();
+ codeStream.iconst_0();
+ } else {
+ Label endLabel = new Label(codeStream);
+ codeStream.goto_(endLabel);
+ codeStream.decrStackSize(1);
+ // comparison is FALSE
+ falseLabel.place();
+ codeStream.iconst_0();
+ endLabel.place();
+ }
+ }
+ }
+
+ /**
+ * Boolean operator code generation
+ * Optimized operations are: == and !=
+ */
+ public void generateOptimizedBoolean(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Label trueLabel,
+ Label falseLabel,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) {
+ if (constant.booleanValue() == true) {
+ // constant == true
+ if (valueRequired) {
+ if (falseLabel == null) {
+ // implicit falling through the FALSE case
+ if (trueLabel != null) {
+ codeStream.goto_(trueLabel);
+ }
+ }
+ }
+ } else {
+ // constant == false
+ if (valueRequired) {
+ if (falseLabel != null) {
+ // implicit falling through the TRUE case
+ if (trueLabel == null) {
+ codeStream.goto_(falseLabel);
+ }
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ if (((bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
+ if ((left.implicitConversion & 0xF) /*compile-time*/
+ == T_boolean) {
+ generateOptimizedBooleanEqual(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ valueRequired);
+ } else {
+ generateOptimizedNonBooleanEqual(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ valueRequired);
+ }
+ } else {
+ if ((left.implicitConversion & 0xF) /*compile-time*/
+ == T_boolean) {
+ generateOptimizedBooleanEqual(
+ currentScope,
+ codeStream,
+ falseLabel,
+ trueLabel,
+ valueRequired);
+ } else {
+ generateOptimizedNonBooleanEqual(
+ currentScope,
+ codeStream,
+ falseLabel,
+ trueLabel,
+ valueRequired);
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ /**
+ * Boolean generation for == with boolean operands
+ *
+ * Note this code does not optimize conditional constants !!!!
+ */
+ public void generateOptimizedBooleanEqual(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Label trueLabel,
+ Label falseLabel,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ // optimized cases: true == x, false == x
+ if (left.constant != NotAConstant) {
+ boolean inline = left.constant.booleanValue();
+ right.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ (inline ? trueLabel : falseLabel),
+ (inline ? falseLabel : trueLabel),
+ valueRequired);
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ } // optimized cases: x == true, x == false
+ if (right.constant != NotAConstant) {
+ boolean inline = right.constant.booleanValue();
+ left.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ (inline ? trueLabel : falseLabel),
+ (inline ? falseLabel : trueLabel),
+ valueRequired);
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ // default case
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // implicit falling through the FALSE case
+ codeStream.if_icmpeq(trueLabel);
+ }
+ } else {
+ // implicit falling through the TRUE case
+ if (trueLabel == null) {
+ codeStream.if_icmpne(falseLabel);
+ } else {
+ // no implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ /**
+ * Boolean generation for == with non-boolean operands
+ *
+ */
+ public void generateOptimizedNonBooleanEqual(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Label trueLabel,
+ Label falseLabel,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ Constant inline;
+ if ((inline = right.constant) != NotAConstant) {
+ // optimized case: x == null
+ if (right.constant == NullConstant.Default) {
+ left.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // implicit falling through the FALSE case
+ codeStream.ifnull(trueLabel);
+ }
+ } else {
+ // implicit falling through the TRUE case
+ if (trueLabel == null) {
+ codeStream.ifnonnull(falseLabel);
+ } else {
+ // no implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ // optimized case: x == 0
+ if (((left.implicitConversion >> 4) == T_int) && (inline.intValue() == 0)) {
+ left.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // implicit falling through the FALSE case
+ codeStream.ifeq(trueLabel);
+ }
+ } else {
+ // implicit falling through the TRUE case
+ if (trueLabel == null) {
+ codeStream.ifne(falseLabel);
+ } else {
+ // no implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ }
+ if ((inline = left.constant) != NotAConstant) {
+ // optimized case: null == x
+ if (left.constant == NullConstant.Default) {
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // implicit falling through the FALSE case
+ codeStream.ifnull(trueLabel);
+ }
+ } else {
+ // implicit falling through the TRUE case
+ if (trueLabel == null) {
+ codeStream.ifnonnull(falseLabel);
+ } else {
+ // no implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ // optimized case: 0 == x
+ if (((left.implicitConversion >> 4) == T_int) && (inline.intValue() == 0)) {
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // implicit falling through the FALSE case
+ codeStream.ifeq(trueLabel);
+ }
+ } else {
+ // implicit falling through the TRUE case
+ if (trueLabel == null) {
+ codeStream.ifne(falseLabel);
+ } else {
+ // no implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ }
+ // default case
+ left.generateCode(currentScope, codeStream, valueRequired);
+ right.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // implicit falling through the FALSE case
+ switch (left.implicitConversion >> 4) { // operand runtime type
+ case T_int :
+ codeStream.if_icmpeq(trueLabel);
+ break;
+ case T_float :
+ codeStream.fcmpl();
+ codeStream.ifeq(trueLabel);
+ break;
+ case T_long :
+ codeStream.lcmp();
+ codeStream.ifeq(trueLabel);
+ break;
+ case T_double :
+ codeStream.dcmpl();
+ codeStream.ifeq(trueLabel);
+ break;
+ default :
+ codeStream.if_acmpeq(trueLabel);
+ }
+ }
+ } else {
+ // implicit falling through the TRUE case
+ if (trueLabel == null) {
+ switch (left.implicitConversion >> 4) { // operand runtime type
+ case T_int :
+ codeStream.if_icmpne(falseLabel);
+ break;
+ case T_float :
+ codeStream.fcmpl();
+ codeStream.ifne(falseLabel);
+ break;
+ case T_long :
+ codeStream.lcmp();
+ codeStream.ifne(falseLabel);
+ break;
+ case T_double :
+ codeStream.dcmpl();
+ codeStream.ifne(falseLabel);
+ break;
+ default :
+ codeStream.if_acmpne(falseLabel);
+ }
+ } else {
+ // no implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public boolean isCompactableOperation() {
+ return false;
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ // always return BooleanBinding
+ TypeBinding leftTb = left.resolveType(scope);
+ TypeBinding rightTb = right.resolveType(scope);
+ if (leftTb == null || rightTb == null) {
+ constant = NotAConstant;
+ return null;
+ }
+
+ // both base type
+ if (leftTb.isBaseType() && rightTb.isBaseType()) {
+ // the code is an int
+ // (cast) left == (cast) rigth --> result
+ // 0000 0000 0000 0000 0000
+ // <<16 <<12 <<8 <<4 <<0
+ int result = ResolveTypeTables[EQUAL_EQUAL][(leftTb.id << 4) + rightTb.id];
+ left.implicitConversion = result >>> 12;
+ right.implicitConversion = (result >>> 4) & 0x000FF;
+ bits |= result & 0xF;
+ if ((result & 0x0000F) == T_undefined) {
+ constant = Constant.NotAConstant;
+ scope.problemReporter().invalidOperator(this, leftTb, rightTb);
+ return null;
+ }
+ computeConstant(leftTb, rightTb);
+ return BooleanBinding;
+ }
+
+ // Object references
+ // spec 15.20.3
+ if (areTypesCastCompatible(scope, rightTb, leftTb)
+ || areTypesCastCompatible(scope, leftTb, rightTb)) {
+ // (special case for String)
+ if ((rightTb.id == T_String) && (leftTb.id == T_String))
+ computeConstant(leftTb, rightTb);
+ else
+ constant = NotAConstant;
+ if (rightTb.id == T_String)
+ right.implicitConversion = String2String;
+ if (leftTb.id == T_String)
+ left.implicitConversion = String2String;
+ return BooleanBinding;
+ }
+ constant = NotAConstant;
+ scope.problemReporter().notCompatibleTypesError(this, leftTb, rightTb);
+ return null;
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ if (visitor.visit(this, scope)) {
+ left.traverse(visitor, scope);
+ right.traverse(visitor, scope);
+ }
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java
new file mode 100644
index 0000000000..71588ff699
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java
@@ -0,0 +1,300 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class ExplicitConstructorCall
+ extends Statement
+ implements InvocationSite {
+ public Expression[] arguments;
+ public Expression qualification;
+ public MethodBinding binding;
+
+ public int accessMode;
+
+ public final static int ImplicitSuper = 1;
+ public final static int Super = 2;
+ public final static int This = 3;
+
+ public VariableBinding[][] implicitArguments;
+ boolean discardEnclosingInstance;
+
+ MethodBinding syntheticAccessor;
+
+ public ExplicitConstructorCall(int accessMode) {
+ this.accessMode = accessMode;
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+
+ // must verify that exceptions potentially thrown by this expression are caught in the method.
+
+ try {
+ ((MethodScope) currentScope).isConstructorCall = true;
+
+ // process enclosing instance
+ if (qualification != null) {
+ flowInfo =
+ qualification
+ .analyseCode(currentScope, flowContext, flowInfo)
+ .unconditionalInits();
+ }
+ // process arguments
+ if (arguments != null) {
+ for (int i = 0, max = arguments.length; i < max; i++) {
+ flowInfo =
+ arguments[i]
+ .analyseCode(currentScope, flowContext, flowInfo)
+ .unconditionalInits();
+ }
+ }
+
+ ReferenceBinding[] thrownExceptions;
+ if ((thrownExceptions = binding.thrownExceptions) != NoExceptions) {
+ // check exceptions
+ flowContext.checkExceptionHandlers(
+ thrownExceptions,
+ (accessMode == ImplicitSuper)
+ ? (AstNode) currentScope.methodScope().referenceContext
+ : (AstNode) this,
+ flowInfo,
+ currentScope);
+ }
+ manageEnclosingInstanceAccessIfNecessary(currentScope);
+ manageSyntheticAccessIfNecessary(currentScope);
+ return flowInfo;
+ } finally {
+ ((MethodScope) currentScope).isConstructorCall = false;
+ }
+ }
+
+ /**
+ * Constructor call code generation
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ */
+ public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+ if ((bits & IsReachableMASK) == 0) {
+ return;
+ }
+ try {
+ ((MethodScope) currentScope).isConstructorCall = true;
+
+ int pc = codeStream.position;
+ codeStream.aload_0();
+
+ // handling innerclass constructor invocation
+ ReferenceBinding targetType;
+ if ((targetType = binding.declaringClass).isNestedType()) {
+ codeStream.generateSyntheticArgumentValues(
+ currentScope,
+ targetType,
+ discardEnclosingInstance ? null : qualification,
+ this);
+ }
+ // regular code gen
+ if (arguments != null) {
+ for (int i = 0, max = arguments.length; i < max; i++) {
+ arguments[i].generateCode(currentScope, codeStream, true);
+ }
+ }
+ if (syntheticAccessor != null) {
+ // synthetic accessor got some extra arguments appended to its signature, which need values
+ for (int i = 0,
+ max = syntheticAccessor.parameters.length - binding.parameters.length;
+ i < max;
+ i++) {
+ codeStream.aconst_null();
+ }
+ codeStream.invokespecial(syntheticAccessor);
+ } else {
+ codeStream.invokespecial(binding);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ } finally {
+ ((MethodScope) currentScope).isConstructorCall = false;
+ }
+ }
+
+ public boolean isImplicitSuper() {
+ //return true if I'm of these compiler added statement super();
+
+ return (accessMode == ImplicitSuper);
+ }
+
+ public boolean isSuperAccess() {
+ return accessMode != This;
+ }
+
+ public boolean isTypeAccess() {
+ return true;
+ }
+
+ /* Inner emulation consists in either recording a dependency
+ * link only, or performing one level of propagation.
+ *
+ * Dependency mechanism is used whenever dealing with source target
+ * types, since by the time we reach them, we might not yet know their
+ * exact need.
+ */
+ void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
+ ReferenceBinding invocationType, superType;
+
+ // perform some emulation work in case there is some and we are inside a local type only
+ if ((superType = binding.declaringClass).isNestedType()
+ && currentScope.enclosingSourceType().isLocalType()) {
+
+ if (superType.isLocalType()) {
+ ((LocalTypeBinding) superType).addInnerEmulationDependent(
+ currentScope,
+ qualification != null,
+ true);
+ // request direct access
+ } else {
+ // locally propagate, since we already now the desired shape for sure
+ currentScope.propagateInnerEmulation(superType, qualification != null, true);
+ // request direct access
+
+ }
+ }
+ }
+
+ public void manageSyntheticAccessIfNecessary(BlockScope currentScope) {
+
+ // perform some emulation work in case there is some and we are inside a local type only
+ if (binding.isPrivate() && (accessMode != This)) {
+
+ if (currentScope
+ .environment()
+ .options
+ .isPrivateConstructorAccessChangingVisibility) {
+ binding.tagForClearingPrivateModifier();
+ // constructor will not be dumped as private, no emulation required thus
+ } else {
+ syntheticAccessor =
+ ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding);
+ currentScope.problemReporter().needToEmulateMethodAccess(binding, this);
+ }
+ }
+ }
+
+ public void resolve(BlockScope scope) {
+ // the return type should be void for a constructor.
+ // the test is made into getConstructor
+
+ // mark the fact that we are in a constructor call.....
+ // unmark at all returns
+ try {
+ ((MethodScope) scope).isConstructorCall = true;
+ ReferenceBinding receiverType = scope.enclosingSourceType();
+ if (accessMode != This)
+ receiverType = receiverType.superclass();
+
+ if (receiverType == null) {
+ return;
+ }
+
+ // qualification should be from the type of the enclosingType
+ if (qualification != null) {
+ ReferenceBinding enclosingType = receiverType.enclosingType();
+ if (enclosingType == null) {
+ scope.problemReporter().unnecessaryEnclosingInstanceSpecification(
+ qualification,
+ receiverType);
+ discardEnclosingInstance = true;
+ } else {
+ TypeBinding qTb = qualification.resolveTypeExpecting(scope, enclosingType);
+ qualification.implicitWidening(qTb, qTb);
+ }
+ }
+
+ // arguments buffering for the method lookup
+ TypeBinding[] argTypes = NoParameters;
+ if (arguments != null) {
+ boolean argHasError = false; // typeChecks all arguments
+ int length = arguments.length;
+ argTypes = new TypeBinding[length];
+ for (int i = 0; i < length; i++)
+ if ((argTypes[i] = arguments[i].resolveType(scope)) == null)
+ argHasError = true;
+ if (argHasError)
+ return;
+ }
+ if ((binding = scope.getConstructor(receiverType, argTypes, this))
+ .isValidBinding()) {
+ if (isMethodUseDeprecated(binding, scope))
+ scope.problemReporter().deprecatedMethod(binding, this);
+
+ // see for user-implicit widening conversion
+ if (arguments != null) {
+ int length = arguments.length;
+ TypeBinding[] paramTypes = binding.parameters;
+ for (int i = 0; i < length; i++)
+ arguments[i].implicitWidening(paramTypes[i], argTypes[i]);
+ }
+ } else {
+ if (binding.declaringClass == null)
+ binding.declaringClass = receiverType;
+ scope.problemReporter().invalidConstructor(this, binding);
+ }
+ } finally {
+ ((MethodScope) scope).isConstructorCall = false;
+ }
+ }
+
+ public void setDepth(int depth) {
+ // ignore for here
+ }
+
+ public void setFieldIndex(int depth) {
+ // ignore for here
+ }
+
+ public String toString(int tab) {
+ /* slow code */
+
+ String s = tabString(tab);
+ if (qualification != null)
+ s = s + qualification.toStringExpression() + ".";
+ if (accessMode == This) {
+ s = s + "this(";
+ } else {
+ s = s + "super(";
+ }
+ if (arguments != null)
+ for (int i = 0; i < arguments.length; i++) {
+ s = s + arguments[i].toStringExpression();
+ if (i != arguments.length - 1)
+ s = s + ", ";
+ };
+ ;
+ s = s + ")";
+ return s;
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ if (visitor.visit(this, scope)) {
+ if (qualification != null) {
+ qualification.traverse(visitor, scope);
+ }
+ if (arguments != null) {
+ int argumentLength = arguments.length;
+ for (int i = 0; i < argumentLength; i++)
+ arguments[i].traverse(visitor, scope);
+ }
+ }
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
new file mode 100644
index 0000000000..050874f4d0
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
@@ -0,0 +1,485 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+public abstract class Expression extends Statement {
+ //some expression may not be used - from a java semantic point
+ //of view only - as statements. Other may. In order to avoid the creation
+ //of wrappers around expression in order to tune them as expression
+ //Expression is a subclass of Statement. See the message isValidJavaStatement()
+
+ public int implicitConversion;
+ public Constant constant;
+
+ public Expression() {
+ super();
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo,
+ boolean valueRequired) {
+ return analyseCode(currentScope, flowContext, flowInfo);
+ }
+
+ public Constant conditionalConstant() {
+
+ return constant;
+ }
+
+ /* Dislike this name
+ */
+
+ public static final boolean convertToTypeFromTypeValue(
+ int left,
+ int right,
+ Constant cst) {
+ //true if there is no loose of information while casting.
+ //right is constant's type.id
+
+ //a faster solution would be to use combinaison of
+ //some range.........????
+
+ /*
+ org.eclipse.jdt.internal.compiler.util.Constant cst ;
+ cst = org.eclipse.jdt.internal.compiler.util.Constant.fromValue((float)898565456.0) ;
+ org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding.convertToTypeFromTypeValue(
+ org.eclipse.jdt.internal.compiler.ast.TypeReference.T_int,
+ org.eclipse.jdt.internal.compiler.ast.TypeReference.T_float,
+ cst)
+ */
+
+ if (left == right)
+ return true;
+ switch (left) {
+ case T_char :
+ switch (right) {
+ case T_char :
+ return true;
+ case T_double :
+ return cst.doubleValue() == cst.charValue();
+ case T_float :
+ return cst.floatValue() == cst.charValue();
+ case T_int :
+ return cst.intValue() == cst.charValue();
+ case T_short :
+ return cst.shortValue() == cst.charValue();
+ case T_byte :
+ return cst.byteValue() == cst.charValue();
+ case T_long :
+ return cst.longValue() == cst.charValue();
+ default :
+ return false;
+ } //boolean
+
+ case T_float :
+ switch (right) {
+ case T_char :
+ return cst.charValue() == cst.floatValue();
+ case T_double :
+ return cst.doubleValue() == cst.floatValue();
+ case T_float :
+ return true;
+ case T_int :
+ return cst.intValue() == cst.floatValue();
+ case T_short :
+ return cst.shortValue() == cst.floatValue();
+ case T_byte :
+ return cst.byteValue() == cst.floatValue();
+ case T_long :
+ return cst.longValue() == cst.floatValue();
+ default :
+ return false;
+ } //boolean
+ case T_double :
+ switch (right) {
+ case T_char :
+ return cst.charValue() == cst.doubleValue();
+ case T_double :
+ return true;
+ case T_float :
+ return cst.floatValue() == cst.doubleValue();
+ case T_int :
+ return cst.intValue() == cst.doubleValue();
+ case T_short :
+ return cst.shortValue() == cst.doubleValue();
+ case T_byte :
+ return cst.byteValue() == cst.doubleValue();
+ case T_long :
+ return cst.longValue() == cst.doubleValue();
+ default :
+ return false;
+ } //boolean
+ case T_byte :
+ switch (right) {
+ case T_char :
+ return cst.charValue() == cst.byteValue();
+ case T_double :
+ return cst.doubleValue() == cst.byteValue();
+ case T_float :
+ return cst.floatValue() == cst.byteValue();
+ case T_int :
+ return cst.intValue() == cst.byteValue();
+ case T_short :
+ return cst.shortValue() == cst.byteValue();
+ case T_byte :
+ return true;
+ case T_long :
+ return cst.longValue() == cst.byteValue();
+ default :
+ return false;
+ } //boolean
+ case T_short :
+ switch (right) {
+ case T_char :
+ return cst.charValue() == cst.shortValue();
+ case T_double :
+ return cst.doubleValue() == cst.shortValue();
+ case T_float :
+ return cst.floatValue() == cst.shortValue();
+ case T_int :
+ return cst.intValue() == cst.shortValue();
+ case T_short :
+ return true;
+ case T_byte :
+ return cst.byteValue() == cst.shortValue();
+ case T_long :
+ return cst.longValue() == cst.shortValue();
+ default :
+ return false;
+ } //boolean
+ case T_int :
+ switch (right) {
+ case T_char :
+ return cst.charValue() == cst.intValue();
+ case T_double :
+ return cst.doubleValue() == cst.intValue();
+ case T_float :
+ return cst.floatValue() == cst.intValue();
+ case T_int :
+ return true;
+ case T_short :
+ return cst.shortValue() == cst.intValue();
+ case T_byte :
+ return cst.byteValue() == cst.intValue();
+ case T_long :
+ return cst.longValue() == cst.intValue();
+ default :
+ return false;
+ } //boolean
+ case T_long :
+ switch (right) {
+ case T_char :
+ return cst.charValue() == cst.longValue();
+ case T_double :
+ return cst.doubleValue() == cst.longValue();
+ case T_float :
+ return cst.floatValue() == cst.longValue();
+ case T_int :
+ return cst.intValue() == cst.longValue();
+ case T_short :
+ return cst.shortValue() == cst.longValue();
+ case T_byte :
+ return cst.byteValue() == cst.longValue();
+ case T_long :
+ return true;
+ default :
+ return false;
+ } //boolean
+ default :
+ return false;
+ } //boolean
+ }
+
+ /**
+ * Expression statements are plain expressions, however they generate like
+ * normal expressions with no value required.
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ */
+ public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+ if ((bits & IsReachableMASK) == 0) {
+ return;
+ }
+ generateCode(currentScope, codeStream, false);
+ }
+
+ /**
+ * Every expression is responsible for generating its implicit conversion when necessary.
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param valueRequired boolean
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+
+ if (constant != NotAConstant) {
+ // generate a constant expression
+ int pc = codeStream.position;
+ codeStream.generateConstant(constant, implicitConversion);
+ codeStream.recordPositionsFrom(pc, this);
+ } else {
+ // actual non-constant code generation
+ throw new ShouldNotImplement("Missing code gen implementation");
+ }
+ }
+
+ /**
+ * Default generation of a boolean value
+ */
+ public void generateOptimizedBoolean(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Label trueLabel,
+ Label falseLabel,
+ boolean valueRequired) {
+
+ // a label valued to nil means: by default we fall through the case...
+ // both nil means we leave the value on the stack
+
+ if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) {
+ int pc = codeStream.position;
+ if (constant.booleanValue() == true) {
+ // constant == true
+ if (valueRequired) {
+ if (falseLabel == null) {
+ // implicit falling through the FALSE case
+ if (trueLabel != null) {
+ codeStream.goto_(trueLabel);
+ }
+ }
+ }
+ } else {
+ if (valueRequired) {
+ if (falseLabel != null) {
+ // implicit falling through the TRUE case
+ if (trueLabel == null) {
+ codeStream.goto_(falseLabel);
+ }
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ generateCode(currentScope, codeStream, valueRequired);
+ // branching
+ int position = codeStream.position;
+ if (valueRequired) {
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // Implicit falling through the FALSE case
+ codeStream.ifne(trueLabel);
+ }
+ } else {
+ if (trueLabel == null) {
+ // Implicit falling through the TRUE case
+ codeStream.ifeq(falseLabel);
+ } else {
+ // No implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ }
+ // reposition the endPC
+ codeStream.updateLastRecordedEndPC(position);
+ }
+
+ public void generateOptimizedStringBuffer(
+ BlockScope blockScope,
+ org.eclipse.jdt.internal.compiler.codegen.CodeStream codeStream,
+ int typeID) {
+ /* Optimized (java) code generation for string concatenations that involve StringBuffer
+ * creation: going through this path means that there is no need for a new StringBuffer
+ * creation, further operands should rather be only appended to the current one.
+ * By default: no optimization.
+ */
+
+ generateCode(blockScope, codeStream, true);
+ codeStream.invokeStringBufferAppendForType(typeID);
+ }
+
+ public void generateOptimizedStringBufferCreation(
+ BlockScope blockScope,
+ CodeStream codeStream,
+ int typeID) {
+ /* Optimized (java) code generation for string concatenations that involve StringBuffer
+ * creation: going through this path means that there is no need for a new StringBuffer
+ * creation, further operands should rather be only appended to the current one.
+ */
+
+ // Optimization only for integers and strings
+
+ if (typeID == T_Object) {
+ // in the case the runtime value of valueOf(Object) returns null, we have to use append(Object) instead of directly valueOf(Object)
+ // append(Object) returns append(valueOf(Object)), which means that the null case is handled by append(String).
+ codeStream.newStringBuffer();
+ codeStream.dup();
+ codeStream.invokeStringBufferDefaultConstructor();
+ generateCode(blockScope, codeStream, true);
+ codeStream.invokeStringBufferAppendForType(T_Object);
+ return;
+ }
+ codeStream.newStringBuffer();
+ codeStream.dup();
+ if ((typeID == T_String) || (typeID == T_null)) {
+ if (constant != NotAConstant) {
+ codeStream.ldc(constant.stringValue());
+ } else {
+ generateCode(blockScope, codeStream, true);
+ codeStream.invokeStringValueOf(T_Object);
+ }
+ } else {
+ generateCode(blockScope, codeStream, true);
+ codeStream.invokeStringValueOf(typeID);
+ }
+ codeStream.invokeStringBufferStringConstructor();
+ }
+
+ public void implicitWidening(
+ TypeBinding runtimeTimeType,
+ TypeBinding compileTimeType) {
+ // Base types need that the widening is explicitly done by the compiler using some bytecode like i2f
+
+ if (runtimeTimeType == null || compileTimeType == null)
+ return;
+
+ if (compileTimeType.id == T_null) {
+ // this case is possible only for constant null
+ // The type of runtime is a reference type
+ // The code gen use the constant id thus any value
+ // for the runtime id (akak the <<4) could be used.
+ // T_Object is used as some general T_reference
+ implicitConversion = (T_Object << 4) + T_null;
+ return;
+ }
+
+ switch (runtimeTimeType.id) {
+ case T_byte :
+ case T_short :
+ case T_char :
+ implicitConversion = (T_int << 4) + compileTimeType.id;
+ break;
+ case T_String :
+ case T_float :
+ case T_boolean :
+ case T_double :
+ case T_int : //implicitConversion may result in i2i which will result in NO code gen
+ case T_long :
+ implicitConversion = (runtimeTimeType.id << 4) + compileTimeType.id;
+ break;
+ default : //nothing on regular object ref
+ }
+ }
+
+ public boolean isCompactableOperation() {
+ return false;
+ }
+
+ public boolean isConstantValueOfTypeAssignableToType(
+ TypeBinding constantType,
+ TypeBinding targetType) {
+ //Return true if the conversion is done AUTOMATICALLY by the vm
+ //while the javaVM is an int based-machine, thus for example pushing
+ //a byte onto the stack , will automatically creates a int on the stack
+ //(this request some work d be done by the VM on signed numbers)
+
+ if (constant == Constant.NotAConstant)
+ return false;
+ if (constantType == targetType)
+ return true;
+ if (constantType.isBaseType() && targetType.isBaseType()) {
+ //No free assignment conversion from anything but to integral ones.
+ if ((constantType == IntBinding
+ || BaseTypeBinding.isWidening(T_int, constantType.id))
+ && (BaseTypeBinding.isNarrowing(targetType.id, T_int))) {
+ //use current explicit conversion in order to get some new value to compare with current one
+ return convertToTypeFromTypeValue(targetType.id, constantType.id, constant);
+ }
+ }
+ return false;
+ }
+
+ public boolean isTypeReference() {
+ return false;
+ }
+
+ public void resolve(BlockScope scope) {
+ // drops the returning expression's type whatever the type is.
+
+ this.resolveType(scope);
+ return;
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ // by default... subclasses should implement a better TC if required.
+
+ return null;
+ }
+
+ public TypeBinding resolveTypeExpecting(
+ BlockScope scope,
+ TypeBinding expectedTb) {
+ TypeBinding thisTb = this.resolveType(scope);
+ if (thisTb == null)
+ return null;
+ if (!scope.areTypesCompatible(thisTb, expectedTb)) {
+ scope.problemReporter().typeMismatchError(thisTb, expectedTb, this);
+ return null;
+ }
+ return thisTb;
+ }
+
+ public String toString(int tab) {
+
+ //Subclass re-define toStringExpression
+
+ String s = tabString(tab);
+ if (constant != null)
+ //before TC has runned
+ if (constant != NotAConstant)
+ //after the TC has runned
+ s += " /*cst:" + constant.toString() + "*/ ";
+ return s + toStringExpression(tab);
+ }
+
+ public String toStringExpression() {
+
+ //Subclass re-define toStringExpression
+ //This method is abstract and should never be called
+ //but we provide some code that is running.....just in case
+ //of developpement time (while every thing is not built)
+
+ return super.toString(0);
+ }
+
+ public String toStringExpression(int tab) {
+ // default is regular toString expression (qualified allocation expressions redifine this method)
+ return this.toStringExpression();
+ }
+
+ public Expression toTypeReference() {
+ //by default undefined
+
+ //this method is meanly used by the parser in order to transform
+ //an expression that is used as a type reference in a cast ....
+ //--appreciate the fact that castExpression and ExpressionWithParenthesis
+ //--starts with the same pattern.....
+
+ return this;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExtendedStringLiteral.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExtendedStringLiteral.java
new file mode 100644
index 0000000000..f464b0a87e
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExtendedStringLiteral.java
@@ -0,0 +1,67 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
+
+public class ExtendedStringLiteral extends StringLiteral {
+ private static final int INIT_SIZE = 30;
+ public ExtendedStringLiteral(StringLiteral str, CharLiteral character) {
+ //build a string+char literal
+
+ super(str.source, str.sourceStart, str.sourceEnd);
+ extendWith(character);
+ }
+
+ public ExtendedStringLiteral(StringLiteral str1, StringLiteral str2) {
+ //build a two-strings literal
+
+ super(str1.source, str1.sourceStart, str1.sourceEnd);
+ extendWith(str2);
+ }
+
+ public ExtendedStringLiteral extendWith(CharLiteral lit) {
+ //add the lit source to mine, just as if it was mine
+
+ //uddate the source
+ int length = source.length;
+ System.arraycopy(source, 0, (source = new char[length + 1]), 0, length);
+ source[length] = lit.value;
+ //position at the end of all literals
+ sourceEnd = lit.sourceEnd;
+ return this;
+ }
+
+ public ExtendedStringLiteral extendWith(StringLiteral lit) {
+ //add the lit source to mine, just as if it was mine
+
+ //uddate the source
+ int length = source.length;
+ System.arraycopy(
+ source,
+ 0,
+ source = new char[length + lit.source.length],
+ 0,
+ length);
+ System.arraycopy(lit.source, 0, source, length, lit.source.length);
+ //position at the end of all literals
+ sourceEnd = lit.sourceEnd;
+ return this;
+ }
+
+ public String toStringExpression() {
+ /* slow code */
+
+ String str = "ExtendedStringLiteral{" + new String(source) + "}";
+ return str;
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ visitor.visit(this, scope);
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FalseLiteral.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FalseLiteral.java
new file mode 100644
index 0000000000..45374d58ca
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FalseLiteral.java
@@ -0,0 +1,77 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class FalseLiteral extends MagicLiteral {
+ static final char[] source = { 'f', 'a', 'l', 's', 'e' };
+ public FalseLiteral(int s, int e) {
+ super(s, e);
+ }
+
+ public void computeConstant() {
+
+ constant = Constant.fromValue(false);
+ }
+
+ /**
+ * Code generation for false literal
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param valueRequired boolean
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ if (valueRequired)
+ codeStream.iconst_0();
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public void generateOptimizedBoolean(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Label trueLabel,
+ Label falseLabel,
+ boolean valueRequired) {
+
+ // falseLabel being not nil means that we will not fall through into the FALSE case
+
+ int pc = codeStream.position;
+ if (valueRequired) {
+ if (falseLabel != null) {
+ // implicit falling through the TRUE case
+ if (trueLabel == null) {
+ codeStream.goto_(falseLabel);
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public TypeBinding literalType(BlockScope scope) {
+ return BooleanBinding;
+ }
+
+ /**
+ *
+ */
+ public char[] source() {
+ return source;
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ visitor.visit(this, scope);
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java
new file mode 100644
index 0000000000..57f1be1ee6
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java
@@ -0,0 +1,187 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+public class FieldDeclaration extends AbstractVariableDeclaration {
+ public FieldBinding binding;
+ boolean hasBeenResolved = false;
+
+ //allows to retrieve both the "type" part of the declaration (part1)
+ //and also the part that decribe the name and the init and optionally
+ //some other dimension ! ....
+ //public int[] a, b[] = X, c ;
+ //for b that would give for
+ // - part1 : public int[]
+ // - part2 : b[] = X,
+
+ public int endPart1Position;
+ public int endPart2Position;
+ public FieldDeclaration() {
+ }
+
+ public FieldDeclaration(
+ Expression initialization,
+ char[] name,
+ int sourceStart,
+ int sourceEnd) {
+
+ this.initialization = initialization;
+ this.name = name;
+
+ //due to some declaration like
+ // int x, y = 3, z , x ;
+ //the sourceStart and the sourceEnd is ONLY on the name
+
+ this.sourceStart = sourceStart;
+ this.sourceEnd = sourceEnd;
+ }
+
+ public FlowInfo analyseCode(
+ MethodScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ if (initialization != null) {
+ flowInfo =
+ initialization
+ .analyseCode(currentScope, flowContext, flowInfo)
+ .unconditionalInits();
+ flowInfo.markAsDefinitelyAssigned(binding);
+ } else {
+ flowInfo.markAsDefinitelyNotAssigned(binding);
+ // clear the bit in case it was already set (from enclosing info)
+ }
+ return flowInfo;
+ }
+
+ /**
+ * Code generation for a field declaration
+ * i.e. normal assignment to a field
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ */
+ public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+ if ((bits & IsReachableMASK) == 0) {
+ return;
+ }
+ // do not generate initialization code if final and static (constant is then
+ // recorded inside the field itself).
+ int pc = codeStream.position;
+ boolean isStatic;
+ if (initialization != null
+ && !((isStatic = binding.isStatic()) && binding.constant != NotAConstant)) {
+ // non-static field, need receiver
+ if (!isStatic)
+ codeStream.aload_0();
+ // generate initialization value
+ initialization.generateCode(currentScope, codeStream, true);
+ // store into field
+ if (isStatic) {
+ codeStream.putstatic(binding);
+ } else {
+ codeStream.putfield(binding);
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public TypeBinding getTypeBinding(Scope scope) {
+ return type.getTypeBinding(scope);
+ }
+
+ public boolean isField() {
+ return true;
+ }
+
+ public boolean isStatic() {
+ if (binding != null)
+ return binding.isStatic();
+ return (modifiers & AccStatic) != 0;
+ }
+
+ public String name() {
+
+ return String.valueOf(name);
+ }
+
+ public void resolve(MethodScope initializationScope) {
+ // the two <constant = Constant.NotAConstant> could be regrouped into
+ // a single line but it is clearer to have two lines while the reason of their
+ // existence is not at all the same. See comment for the second one.
+
+ //--------------------------------------------------------
+ if (!hasBeenResolved && binding != null && binding.isValidBinding()) {
+ hasBeenResolved = true;
+ if (isTypeUseDeprecated(binding.type, initializationScope))
+ initializationScope.problemReporter().deprecatedType(binding.type, type);
+
+ this.type.binding = this.binding.type; // update binding for type reference
+
+ // the resolution of the initialization hasn't been done
+ if (initialization == null) {
+ binding.constant = Constant.NotAConstant;
+ } else {
+ // break dead-lock cycles by forcing constant to NotAConstant
+ int previous = initializationScope.fieldDeclarationIndex;
+ try {
+ initializationScope.fieldDeclarationIndex = binding.id;
+ binding.constant = Constant.NotAConstant;
+ TypeBinding tb = binding.type;
+ TypeBinding initTb;
+ if (initialization instanceof ArrayInitializer) {
+ if ((initTb = initialization.resolveTypeExpecting(initializationScope, tb))
+ != null) {
+ ((ArrayInitializer) initialization).binding = (ArrayBinding) initTb;
+ initialization.implicitWidening(tb, initTb);
+ }
+ } else
+ if ((initTb = initialization.resolveType(initializationScope)) != null) {
+ if (initialization.isConstantValueOfTypeAssignableToType(initTb, tb)
+ || (tb.isBaseType() && BaseTypeBinding.isWidening(tb.id, initTb.id)))
+ initialization.implicitWidening(tb, initTb);
+ else
+ if (initializationScope.areTypesCompatible(initTb, tb))
+ initialization.implicitWidening(tb, initTb);
+ else
+ initializationScope.problemReporter().typeMismatchError(initTb, tb, this);
+ if (binding.isFinal()) // cast from constant actual type to variable type
+ binding.constant =
+ initialization.constant.castTo(
+ (binding.type.id << 4) + initialization.constant.typeID());
+ } else {
+ binding.constant = NotAConstant;
+ }
+ } finally {
+ initializationScope.fieldDeclarationIndex = previous;
+ if (binding.constant == null)
+ binding.constant = Constant.NotAConstant;
+ }
+ }
+ // cannot define static non-constant field inside nested class
+ if (binding.isStatic() && binding.constant == NotAConstant)
+ if (binding.declaringClass.isNestedType()
+ && binding.declaringClass.isClass()
+ && !binding.declaringClass.isStatic())
+ initializationScope.problemReporter().unexpectedStaticModifierForField(
+ (SourceTypeBinding) binding.declaringClass,
+ this);
+ }
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, MethodScope scope) {
+ visitor.visit(this, scope);
+ type.traverse(visitor, scope);
+ if (initialization != null)
+ initialization.traverse(visitor, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java
new file mode 100644
index 0000000000..1626718b05
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java
@@ -0,0 +1,454 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class FieldReference extends Reference implements InvocationSite {
+ public Expression receiver;
+ public char[] token;
+ public FieldBinding binding;
+
+ public long nameSourcePosition; //(start<<32)+end
+
+ MethodBinding syntheticReadAccessor, syntheticWriteAccessor;
+ public FieldReference(char[] source, long pos) {
+ token = source;
+ nameSourcePosition = pos;
+ //by default the position are the one of the field (not true for super access)
+ sourceStart = (int) (pos >>> 32);
+ sourceEnd = (int) (pos & 0x00000000FFFFFFFFL);
+
+ }
+
+ public FlowInfo analyseAssignment(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo,
+ Assignment assignment,
+ boolean isCompound) {
+
+ // compound assignment extra work
+ if (isCompound) { // check the variable part is initialized if blank final
+ if (binding.isFinal()
+ && receiver.isThis()
+ && currentScope.allowBlankFinalFieldAssignment(binding)
+ && (!flowInfo.isDefinitelyAssigned(binding))) {
+ currentScope.problemReporter().uninitializedBlankFinalField(binding, this);
+ // we could improve error msg here telling "cannot use compound assignment on final blank field"
+ }
+ manageSyntheticReadAccessIfNecessary(currentScope);
+ }
+ if (assignment.expression != null) {
+ flowInfo =
+ assignment
+ .expression
+ .analyseCode(currentScope, flowContext, flowInfo)
+ .unconditionalInits();
+ }
+ flowInfo =
+ receiver
+ .analyseCode(currentScope, flowContext, flowInfo, !binding.isStatic())
+ .unconditionalInits();
+ manageSyntheticWriteAccessIfNecessary(currentScope);
+
+ // check if assigning a final field
+ if (binding.isFinal()) {
+ // in a context where it can be assigned?
+ if (receiver.isThis()
+ && currentScope.allowBlankFinalFieldAssignment(binding)) {
+ if (flowInfo.isPotentiallyAssigned(binding)) {
+ currentScope.problemReporter().duplicateInitializationOfBlankFinalField(
+ binding,
+ this);
+ }
+ flowInfo.markAsDefinitelyAssigned(binding);
+ flowContext.recordSettingFinal(binding, this);
+ } else {
+ // assigning a final field outside an initializer or constructor
+ currentScope.problemReporter().cannotAssignToFinalField(binding, this);
+ }
+ }
+ return flowInfo;
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ return analyseCode(currentScope, flowContext, flowInfo, true);
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo,
+ boolean valueRequired) {
+ receiver.analyseCode(currentScope, flowContext, flowInfo, !binding.isStatic());
+ if (valueRequired) {
+ manageSyntheticReadAccessIfNecessary(currentScope);
+ }
+ return flowInfo;
+ }
+
+ public FieldBinding fieldBinding() {
+ //FLOW ANALYSIS
+
+ return binding;
+ }
+
+ public void generateAssignment(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Assignment assignment,
+ boolean valueRequired) {
+
+ receiver.generateCode(currentScope, codeStream, !binding.isStatic());
+ assignment.expression.generateCode(currentScope, codeStream, true);
+ fieldStore(codeStream, binding, syntheticWriteAccessor, valueRequired);
+ if (valueRequired) {
+ codeStream.generateImplicitConversion(assignment.implicitConversion);
+ }
+ }
+
+ /**
+ * Field reference code generation
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param valueRequired boolean
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ if (constant != NotAConstant) {
+ if (valueRequired) {
+ codeStream.generateConstant(constant, implicitConversion);
+ }
+ } else {
+ boolean isStatic = binding.isStatic();
+ receiver.generateCode(
+ currentScope,
+ codeStream,
+ valueRequired && (!isStatic) && (binding.constant == NotAConstant));
+ if (valueRequired) {
+ if (binding.constant == NotAConstant) {
+ if (binding.declaringClass == null) { // array length
+ codeStream.arraylength();
+ } else {
+ if (syntheticReadAccessor == null) {
+ if (isStatic) {
+ codeStream.getstatic(binding);
+ } else {
+ codeStream.getfield(binding);
+ }
+ } else {
+ codeStream.invokestatic(syntheticReadAccessor);
+ }
+ }
+ codeStream.generateImplicitConversion(implicitConversion);
+ } else {
+ codeStream.generateConstant(binding.constant, implicitConversion);
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public void generateCompoundAssignment(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Expression expression,
+ int operator,
+ int assignmentImplicitConversion,
+ boolean valueRequired) {
+ boolean isStatic;
+ receiver.generateCode(
+ currentScope,
+ codeStream,
+ !(isStatic = binding.isStatic()));
+ if (isStatic) {
+ if (syntheticReadAccessor == null) {
+ codeStream.getstatic(binding);
+ } else {
+ codeStream.invokestatic(syntheticReadAccessor);
+ }
+ } else {
+ codeStream.dup();
+ if (syntheticReadAccessor == null) {
+ codeStream.getfield(binding);
+ } else {
+ codeStream.invokestatic(syntheticReadAccessor);
+ }
+ }
+ int operationTypeID;
+ if ((operationTypeID = implicitConversion >> 4) == T_String) {
+ codeStream.generateStringAppend(currentScope, null, expression);
+ } else {
+ // promote the array reference to the suitable operation type
+ codeStream.generateImplicitConversion(implicitConversion);
+ // generate the increment value (will by itself be promoted to the operation value)
+ if (expression == IntLiteral.One) { // prefix operation
+ codeStream.generateConstant(expression.constant, implicitConversion);
+ } else {
+ expression.generateCode(currentScope, codeStream, true);
+ }
+ // perform the operation
+ codeStream.sendOperator(operator, operationTypeID);
+ // cast the value back to the array reference type
+ codeStream.generateImplicitConversion(assignmentImplicitConversion);
+ }
+ fieldStore(codeStream, binding, syntheticWriteAccessor, valueRequired);
+ }
+
+ public void generatePostIncrement(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ CompoundAssignment postIncrement,
+ boolean valueRequired) {
+ boolean isStatic;
+ receiver.generateCode(
+ currentScope,
+ codeStream,
+ !(isStatic = binding.isStatic()));
+ if (isStatic) {
+ if (syntheticReadAccessor == null) {
+ codeStream.getstatic(binding);
+ } else {
+ codeStream.invokestatic(syntheticReadAccessor);
+ }
+ } else {
+ codeStream.dup();
+ if (syntheticReadAccessor == null) {
+ codeStream.getfield(binding);
+ } else {
+ codeStream.invokestatic(syntheticReadAccessor);
+ }
+ }
+ if (valueRequired) {
+ if (isStatic) {
+ if ((binding.type == LongBinding) || (binding.type == DoubleBinding)) {
+ codeStream.dup2();
+ } else {
+ codeStream.dup();
+ }
+ } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value]
+ if ((binding.type == LongBinding) || (binding.type == DoubleBinding)) {
+ codeStream.dup2_x1();
+ } else {
+ codeStream.dup_x1();
+ }
+ }
+ }
+ codeStream.generateConstant(
+ postIncrement.expression.constant,
+ implicitConversion);
+ codeStream.sendOperator(postIncrement.operator, binding.type.id);
+ codeStream.generateImplicitConversion(
+ postIncrement.assignmentImplicitConversion);
+ fieldStore(codeStream, binding, syntheticWriteAccessor, false);
+ }
+
+ public static final Constant getConstantFor(
+ FieldBinding binding,
+ boolean implicitReceiver,
+ Reference ref,
+ int indexInQualification) {
+ //propagation of the constant.
+
+ //ref can be a FieldReference, a SingleNameReference or a QualifiedNameReference
+ //indexInQualification may have a value greater than zero only for QualifiednameReference
+ //if ref==null then indexInQualification==0 AND implicitReceiver == false. This case is a
+ //degenerated case where a fake reference field (null)
+ //is associted to a real FieldBinding in order
+ //to allow its constant computation using the regular path (i.e. find the fieldDeclaration
+ //and proceed to its type resolution). As implicitReceiver is false, no error reporting
+ //against ref will be used ==> no nullPointerException risk ....
+
+ //special treatment for langage-built-in field (their declaring class is null)
+ if (binding.declaringClass == null) {
+ //currently only one field "length" : the constant computation is never done
+ return NotAConstant;
+ }
+ if (!binding.isFinal()) {
+ return binding.constant = NotAConstant;
+ }
+ if (binding.constant != null) {
+ if (indexInQualification == 0) {
+ return binding.constant;
+ }
+ //see previous comment for the (sould-always-be) valid cast
+ QualifiedNameReference qnr = (QualifiedNameReference) ref;
+ if (indexInQualification == (qnr.indexOfFirstFieldBinding - 1)) {
+ return binding.constant;
+ }
+ return NotAConstant;
+ }
+ //The field has not been yet type checked.
+ //It also means that the field is not coming from a class that
+ //has already been compiled. It can only be from a class within
+ //compilation units to process. Thus the field is NOT from a BinaryTypeBinbing
+
+ SourceTypeBinding tb = (SourceTypeBinding) binding.declaringClass;
+ TypeDeclaration typeDecl = tb.scope.referenceContext;
+
+ //fetch the field declaration
+ FieldDeclaration fieldDecl = null;
+ int index = 0;
+ FieldDeclaration[] fields = typeDecl.fields;
+ while (fieldDecl == null) {
+ if ((fields[index].isField())
+ && (CharOperation.equals(fields[index].name, binding.name)))
+ fieldDecl = fields[index];
+ else
+ index++;
+ }
+ //what scope to use (depend on the staticness of the field binding)
+ MethodScope fieldScope =
+ binding.isStatic()
+ ? typeDecl.staticInitializerScope
+ : typeDecl.initializerScope;
+ if (implicitReceiver) { //Determine if the ref is legal in the current class of the field
+ //i.e. not a forward reference .... (they are allowed when the receiver is explicit ! ... Please don't ask me why !...yet another java mystery...)
+ if (fieldScope.fieldDeclarationIndex == MethodScope.NotInFieldDecl) {
+ // no field is currently being analysed in typeDecl
+ fieldDecl.resolve(fieldScope); //side effect on binding :-) ...
+ return binding.constant;
+ }
+ //We are re-entering the same class fields analysing
+ if (((ref == null)
+ || ((ref.bits & DepthMASK) == 0)) // not implicit ref to enclosing field
+ && (binding.id > fieldScope.fieldDeclarationIndex)) {
+ //forward reference. The declaration remains unresolved.
+ tb.scope.problemReporter().forwardReference(ref, indexInQualification, tb);
+ return NotAConstant;
+ }
+ fieldDecl.resolve(fieldScope); //side effect on binding :-) ...
+ return binding.constant;
+ }
+ //the field reference is explicity. It has to be a "simple" like field reference to get the
+ //constant propagation. For example in Packahe.Type.field1.field2 , field1 may have its
+ //constant having a propagation where field2 is always not propagating its
+ if (indexInQualification == 0) {
+ fieldDecl.resolve(fieldScope); //side effect on binding :-) ...
+ return binding.constant;
+ }
+ // Side-effect on the field binding may not be propagated out for the qualified reference
+ // unless it occurs in first place of the name sequence
+ fieldDecl.resolve(fieldScope); //side effect on binding :-) ...
+ //see previous comment for the cast that should always be valid
+ QualifiedNameReference qnr = (QualifiedNameReference) ref;
+ if (indexInQualification == (qnr.indexOfFirstFieldBinding - 1)) {
+ return binding.constant;
+ } else {
+ return NotAConstant;
+ }
+ }
+
+ public boolean isFieldReference() {
+
+ return true;
+ }
+
+ public boolean isSuperAccess() {
+
+ return receiver.isSuper();
+ }
+
+ public boolean isTypeAccess() {
+ return receiver != null && receiver.isTypeReference();
+ }
+
+ /*
+ * No need to emulate access to protected fields since not implicitly accessed
+ */
+ public void manageSyntheticReadAccessIfNecessary(BlockScope currentScope) {
+ if (binding.isPrivate()
+ && (currentScope.enclosingSourceType() != binding.declaringClass)
+ && (binding.constant == NotAConstant)) {
+ syntheticReadAccessor = binding.getSyntheticReadAccess();
+ }
+ }
+
+ /*
+ * No need to emulate access to protected fields since not implicitly accessed
+ */
+ public void manageSyntheticWriteAccessIfNecessary(BlockScope currentScope) {
+ if (binding.isPrivate()
+ && (currentScope.enclosingSourceType() != binding.declaringClass)) {
+ syntheticWriteAccessor = binding.getSyntheticWriteAccess();
+ }
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ // Answer the signature type of the field.
+ // constants are propaged when the field is final
+ // and initialized with a (compile time) constant
+
+ // regular receiver reference
+ TypeBinding receiverType = receiver.resolveType(scope);
+ if (receiverType == null) {
+ constant = NotAConstant;
+ return null;
+ }
+ // the case receiverType.isArrayType and token = 'length' is handled by the scope API
+ binding = scope.getField(receiverType, token, this);
+ if (!binding.isValidBinding()) {
+ constant = NotAConstant;
+ scope.problemReporter().invalidField(this, receiverType);
+ return null;
+ }
+
+ if (isFieldUseDeprecated(binding, scope))
+ scope.problemReporter().deprecatedField(binding, this);
+
+ // check for this.x in static is done in the resolution of the receiver
+ constant =
+ FieldReference.getConstantFor(
+ binding,
+ receiver == ThisReference.ThisImplicit,
+ this,
+ 0);
+ if (!receiver.isThis())
+ constant = NotAConstant;
+
+ // if the binding declaring class is not visible, need special action
+ // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
+ if (binding.declaringClass != receiverType
+ && binding.declaringClass != null // array.length
+ && binding.constant == NotAConstant
+ && !binding.declaringClass.canBeSeenBy(scope))
+ binding = new FieldBinding(binding, (ReferenceBinding) receiverType);
+ return binding.type;
+ }
+
+ public void setDepth(int d) {
+ }
+
+ public void setFieldIndex(int index) {
+ }
+
+ public String toStringExpression() {
+ /* slow code */
+
+ return receiver.toString() + "." + new String(token);
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ if (visitor.visit(this, scope)) {
+ receiver.traverse(visitor, scope);
+ }
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FloatLiteral.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FloatLiteral.java
new file mode 100644
index 0000000000..9b1f782ddb
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FloatLiteral.java
@@ -0,0 +1,88 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class FloatLiteral extends NumberLiteral {
+ float value;
+ final static float Float_MIN_VALUE = Float.intBitsToFloat(1);
+ // work-around VAJ problem 1F6IGUU
+ public FloatLiteral(char[] token, int s, int e) {
+ super(token, s, e);
+ }
+
+ public void computeConstant() {
+
+ //the source is correctly formated so the exception should never occurs
+
+ Float computedValue;
+ try {
+ computedValue = Float.valueOf(String.valueOf(source));
+ } catch (NumberFormatException e) {
+ return;
+ }
+
+ if (computedValue.doubleValue() > Float.MAX_VALUE) {
+ return; //may be Infinity
+ }
+ if (computedValue.floatValue() < Float_MIN_VALUE) {
+ // see 1F6IGUU
+ //only a true 0 can be made of zeros
+ //1.00000000e-46f is illegal ....
+ label : for (int i = 0; i < source.length; i++) {
+ switch (source[i]) {
+ case '.' :
+ case 'f' :
+ case 'F' :
+ case '0' :
+ break;
+ case 'e' :
+ case 'E' :
+ break label; //exposant are valid !....
+ default :
+ return; //error
+
+ }
+ }
+ }
+ constant = Constant.fromValue(value = computedValue.floatValue());
+ }
+
+ /**
+ * Code generation for float literal
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param valueRequired boolean
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ if (valueRequired)
+ if ((implicitConversion >> 4) == T_float)
+ codeStream.generateInlinedValue(value);
+ else
+ codeStream.generateConstant(constant, implicitConversion);
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public TypeBinding literalType(BlockScope scope) {
+ return FloatBinding;
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ visitor.visit(this, blockScope);
+ visitor.endVisit(this, blockScope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java
new file mode 100644
index 0000000000..2eea27da2c
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java
@@ -0,0 +1,323 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class ForStatement extends Statement {
+ public Statement[] initializations;
+ public Expression condition;
+ public Statement[] increments;
+ public Statement action;
+
+ //when there is no local declaration, there is no need of a new scope
+ //scope is positionned either to a new scope, or to the "upper"scope (see resolveType)
+ public boolean neededScope;
+ public BlockScope scope;
+
+ private Label breakLabel, continueLabel;
+
+ // for local variables table attributes
+ int preCondInitStateIndex = -1;
+ int condIfTrueInitStateIndex = -1;
+ int mergedInitStateIndex = -1;
+ public ForStatement(
+ Statement[] initializations,
+ Expression condition,
+ Statement[] increments,
+ Statement action,
+ boolean neededScope,
+ int s,
+ int e) {
+ this.sourceStart = s;
+ this.sourceEnd = e;
+ this.initializations = initializations;
+ this.condition = condition;
+ this.increments = increments;
+ this.action = action;
+ this.neededScope = neededScope;
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ breakLabel = new Label();
+ continueLabel = new Label();
+
+ // process the initializations
+ if (initializations != null) {
+ int count = initializations.length, i = 0;
+ while (i < count) {
+ flowInfo = initializations[i++].analyseCode(scope, flowContext, flowInfo);
+ }
+ }
+ preCondInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(flowInfo);
+
+ // process the condition
+ if (condition != null) {
+ if ((condition.constant == NotAConstant)
+ || (condition.constant.booleanValue() != true)) {
+ LoopingFlowContext condLoopContext;
+ flowInfo =
+ condition.analyseCode(
+ scope,
+ (condLoopContext =
+ new LoopingFlowContext(flowContext, this, null, null, scope)),
+ flowInfo);
+ condLoopContext.complainOnFinalAssignmentsInLoop(scope, flowInfo);
+ }
+ }
+
+ // process the action
+ LoopingFlowContext loopingContext;
+ FlowInfo actionInfo;
+ if ((action == null) || action.isEmptyBlock()) {
+ if ((condition == null)
+ || ((condition.constant != NotAConstant)
+ && (condition.constant.booleanValue() == true))) {
+ return FlowInfo.DeadEnd;
+ } else {
+ actionInfo = flowInfo.initsWhenTrue().copy();
+ loopingContext =
+ new LoopingFlowContext(flowContext, this, breakLabel, continueLabel, scope);
+ }
+ } else {
+ loopingContext =
+ new LoopingFlowContext(flowContext, this, breakLabel, continueLabel, scope);
+ FlowInfo initsWhenTrue = flowInfo.initsWhenTrue();
+ condIfTrueInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(initsWhenTrue);
+ actionInfo =
+ action
+ .analyseCode(
+ scope,
+ loopingContext,
+ ((condition != null)
+ && (condition.constant != NotAConstant)
+ && (condition.constant.booleanValue() == false))
+ ? // unreachable when condition inlined to false
+ FlowInfo.DeadEnd : initsWhenTrue.copy());
+
+ // code generation can be optimized when no need to continue in the loop
+ if ((actionInfo == FlowInfo.DeadEnd) || actionInfo.isFakeReachable()) {
+ if ((loopingContext.initsOnContinue == FlowInfo.DeadEnd)
+ || loopingContext.initsOnContinue.isFakeReachable()) {
+ continueLabel = null;
+ } else {
+ loopingContext.complainOnFinalAssignmentsInLoop(
+ scope,
+ loopingContext.initsOnContinue);
+ }
+ } else {
+ loopingContext.complainOnFinalAssignmentsInLoop(scope, actionInfo);
+ actionInfo =
+ actionInfo.mergedWith(loopingContext.initsOnContinue.unconditionalInits());
+ // for increments
+ }
+ }
+ if ((continueLabel != null) && (increments != null)) {
+ LoopingFlowContext loopContext =
+ new LoopingFlowContext(flowContext, this, null, null, scope);
+ int i = 0, count = increments.length;
+ while (i < count)
+ actionInfo = increments[i++].analyseCode(scope, loopContext, actionInfo);
+ loopContext.complainOnFinalAssignmentsInLoop(scope, flowInfo);
+ }
+
+ // infinite loop
+ FlowInfo mergedInfo;
+ if ((condition == null)
+ || ((condition.constant != NotAConstant)
+ && (condition.constant.booleanValue() == true))) {
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(
+ mergedInfo = loopingContext.initsOnBreak);
+ return mergedInfo;
+ }
+
+ //end of loop: either condition false or break
+ mergedInfo =
+ flowInfo.initsWhenFalse().unconditionalInits().mergedWith(
+ loopingContext.initsOnBreak.unconditionalInits());
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(mergedInfo);
+ return mergedInfo;
+ }
+
+ /**
+ * For statement code generation
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ */
+ public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+ if ((bits & IsReachableMASK) == 0) {
+ return;
+ }
+ int pc = codeStream.position;
+
+ // generate the initializations
+ if (initializations != null) {
+ for (int i = 0, max = initializations.length; i < max; i++) {
+ initializations[i].generateCode(scope, codeStream);
+ }
+ }
+
+ // label management
+ Label actionLabel = new Label(codeStream);
+ Label conditionLabel = new Label(codeStream);
+ breakLabel.codeStream = codeStream;
+ if (continueLabel != null) {
+ continueLabel.codeStream = codeStream;
+ }
+ // jump over the actionBlock
+ if ((condition != null)
+ && (condition.constant == NotAConstant)
+ && !((action == null || action.isEmptyBlock()) && (increments == null))) {
+ int jumpPC = codeStream.position;
+ codeStream.goto_(conditionLabel);
+ codeStream.recordPositionsFrom(jumpPC, condition);
+ }
+ // generate the loop action
+ actionLabel.place();
+ if (action != null) {
+ // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect
+ if (condIfTrueInitStateIndex != -1) {
+ // insert all locals initialized inside the condition into the action generated prior to the condition
+ codeStream.addDefinitelyAssignedVariables(
+ currentScope,
+ condIfTrueInitStateIndex);
+ }
+ action.generateCode(scope, codeStream);
+ }
+ // continuation point
+ if (continueLabel != null) {
+ continueLabel.place();
+ // generate the increments for next iteration
+ if (increments != null) {
+ for (int i = 0, max = increments.length; i < max; i++) {
+ increments[i].generateCode(scope, codeStream);
+ }
+ }
+ }
+
+ // May loose some local variable initializations : affecting the local variable attributes
+ if (preCondInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ preCondInitStateIndex);
+ }
+
+ // generate the condition
+ conditionLabel.place();
+ if ((condition != null) && (condition.constant == NotAConstant)) {
+ condition.generateOptimizedBoolean(scope, codeStream, actionLabel, null, true);
+ } else {
+ if (continueLabel != null) {
+ codeStream.goto_(actionLabel);
+ }
+ }
+ breakLabel.place();
+
+ // May loose some local variable initializations : affecting the local variable attributes
+ if (neededScope) {
+ codeStream.exitUserScope(scope);
+ }
+ if (mergedInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ mergedInitStateIndex);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public void resolve(BlockScope upperScope) {
+ // use the scope that will hold the init declarations
+
+ scope = neededScope ? new BlockScope(upperScope) : upperScope;
+ if (initializations != null)
+ for (int i = 0, length = initializations.length; i < length; i++)
+ initializations[i].resolve(scope);
+ if (condition != null) {
+ TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding);
+ condition.implicitWidening(type, type);
+ }
+ if (increments != null)
+ for (int i = 0, length = increments.length; i < length; i++)
+ increments[i].resolve(scope);
+ if (action != null)
+ action.resolve(scope);
+ }
+
+ public String toString(int tab) {
+ /* slow code */
+
+ String s = tabString(tab) + "for (";
+ if (!neededScope)
+ s = s + " //--NO upperscope scope needed\n" + tabString(tab) + " ";
+ //inits
+ if (initializations != null) {
+ for (int i = 0; i < initializations.length; i++) {
+ //nice only with expressions
+ s = s + initializations[i].toString(0);
+ if (i != (initializations.length - 1))
+ s = s + " , ";
+ }
+ };
+ s = s + "; ";
+ //cond
+ if (condition != null)
+ s = s + condition.toStringExpression();
+ s = s + "; ";
+ //updates
+ if (increments != null) {
+ for (int i = 0; i < increments.length; i++) {
+ //nice only with expressions
+ s = s + increments[i].toString(0);
+ if (i != (increments.length - 1))
+ s = s + " , ";
+ }
+ };
+ s = s + ") ";
+ //block
+ if (action == null)
+ s = s + "{}";
+ else
+ s = s + "\n" + action.toString(tab + 1);
+ return s;
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ if (visitor.visit(this, blockScope)) {
+ if (initializations != null) {
+ int initializationsLength = initializations.length;
+ for (int i = 0; i < initializationsLength; i++)
+ initializations[i].traverse(visitor, scope);
+ }
+
+ if (condition != null)
+ condition.traverse(visitor, scope);
+
+ if (increments != null) {
+ int incrementsLength = increments.length;
+ for (int i = 0; i < incrementsLength; i++)
+ increments[i].traverse(visitor, scope);
+ }
+
+ if (action != null)
+ action.traverse(visitor, scope);
+ }
+ visitor.endVisit(this, blockScope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java
new file mode 100644
index 0000000000..daed077772
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java
@@ -0,0 +1,263 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class IfStatement extends Statement {
+ //this class represents the case of only one statement in
+ //either else and/or then branches.
+
+ public Expression condition;
+ public Statement thenStatement;
+ public Statement elseStatement;
+
+ boolean thenExit;
+
+ // for local variables table attributes
+ int thenInitStateIndex = -1;
+ int elseInitStateIndex = -1;
+ int mergedInitStateIndex = -1;
+ public IfStatement(
+ Expression condition,
+ Statement thenStatement,
+ int s,
+ int e) {
+ this.condition = condition;
+ this.thenStatement = thenStatement;
+ sourceStart = s;
+ sourceEnd = e;
+ }
+
+ public IfStatement(
+ Expression condition,
+ Statement thenStatement,
+ Statement elseStatement,
+ int s,
+ int e) {
+ this.condition = condition;
+ this.thenStatement = thenStatement;
+ this.elseStatement = elseStatement;
+ sourceEnd = e;
+ sourceStart = s;
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ FlowInfo thenFlowInfo, elseFlowInfo;
+
+ // process the condition
+ flowInfo = condition.analyseCode(currentScope, flowContext, flowInfo);
+
+ // process the THEN part
+ if (thenStatement == null) {
+ thenFlowInfo = flowInfo.initsWhenTrue();
+ } else {
+ Constant cst;
+ thenFlowInfo =
+ ((((cst = condition.constant) != NotAConstant)
+ && (cst.booleanValue() == false))
+ || (((cst = condition.conditionalConstant()) != NotAConstant)
+ && (cst.booleanValue() == false)))
+ ? (flowInfo.initsWhenTrue().copy().markAsFakeReachable(true))
+ : flowInfo.initsWhenTrue().copy();
+ // Save info for code gen
+ thenInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(thenFlowInfo);
+ if (!thenFlowInfo.complainIfUnreachable(thenStatement, currentScope)) {
+ thenFlowInfo =
+ thenStatement.analyseCode(currentScope, flowContext, thenFlowInfo);
+ }
+ };
+ // optimizing the jump around the ELSE part
+ thenExit = (thenFlowInfo == FlowInfo.DeadEnd) || thenFlowInfo.isFakeReachable();
+
+ // process the ELSE part
+ if (elseStatement == null) {
+ elseFlowInfo = flowInfo.initsWhenFalse();
+ } else {
+ Constant cst;
+ elseFlowInfo =
+ ((((cst = condition.constant) != NotAConstant) && (cst.booleanValue() == true))
+ || (((cst = condition.conditionalConstant()) != NotAConstant)
+ && (cst.booleanValue() == true)))
+ ? (flowInfo.initsWhenFalse().copy().markAsFakeReachable(true))
+ : flowInfo.initsWhenFalse().copy();
+ // Save info for code gen
+ elseInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(elseFlowInfo);
+ if (!elseFlowInfo.complainIfUnreachable(elseStatement, currentScope)) {
+ elseFlowInfo =
+ elseStatement.analyseCode(currentScope, flowContext, elseFlowInfo);
+ }
+ }
+
+ // merge THEN & ELSE initializations
+ FlowInfo mergedInfo;
+ if ((condition.constant != NotAConstant)
+ && (condition.constant.booleanValue() == true)) {
+ if (thenExit) {
+ mergedInfo = elseFlowInfo.markAsFakeReachable(true);
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(mergedInfo);
+ return mergedInfo;
+ } else {
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(thenFlowInfo);
+ return thenFlowInfo;
+ }
+ } else {
+ if ((condition.constant != NotAConstant)
+ && (condition.constant.booleanValue() == false)) {
+ if (elseFlowInfo.isDeadEnd()) {
+ mergedInfo = thenFlowInfo.markAsFakeReachable(true);
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(mergedInfo);
+ return mergedInfo;
+ } else {
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(elseFlowInfo);
+ return elseFlowInfo;
+ }
+ }
+ }
+ mergedInfo = thenFlowInfo.mergedWith(elseFlowInfo.unconditionalInits());
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(mergedInfo);
+ return mergedInfo;
+ }
+
+ /**
+ * If code generation
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ */
+ public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+ if ((bits & IsReachableMASK) == 0) {
+ return;
+ }
+ int pc = codeStream.position, divergePC;
+ Label endifLabel = new Label(codeStream);
+
+ // optimizing the then/else part code gen
+ Constant cst, condCst;
+ boolean hasThenPart =
+ !((((cst = condition.constant) != NotAConstant)
+ && (cst.booleanValue() == false))
+ || (thenStatement == null)
+ || (thenStatement.isEmptyBlock())
+ || (((condCst = condition.conditionalConstant()) != NotAConstant)
+ && (condCst.booleanValue() == false)));
+ boolean hasElsePart =
+ !(((cst != NotAConstant) && (cst.booleanValue() == true))
+ || (elseStatement == null)
+ || (elseStatement.isEmptyBlock())
+ || (((condCst = condition.conditionalConstant()) != NotAConstant)
+ && (condCst.booleanValue() == true)));
+
+ if (hasThenPart) {
+ Label falseLabel;
+ // generate boolean condition
+ condition.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ null,
+ (falseLabel = new Label(codeStream)),
+ true);
+ // May loose some local variable initializations : affecting the local variable attributes
+ if (thenInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ thenInitStateIndex);
+ codeStream.addDefinitelyAssignedVariables(currentScope, thenInitStateIndex);
+ }
+ // generate then statement
+ thenStatement.generateCode(currentScope, codeStream);
+ // jump around the else statement
+ if (hasElsePart && !thenExit) {
+ int position = codeStream.position;
+ codeStream.goto_(endifLabel);
+ codeStream.updateLastRecordedEndPC(position);
+ //goto is tagged as part of the thenAction block
+ }
+ falseLabel.place();
+ } else {
+ if (hasElsePart) {
+ // generate boolean condition
+ condition.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ endifLabel,
+ null,
+ true);
+ } else {
+ // generate condition side-effects
+ condition.generateCode(currentScope, codeStream, false);
+ codeStream.recordPositionsFrom(pc, this);
+ }
+ }
+ // generate else statement
+ if (hasElsePart) {
+ // May loose some local variable initializations : affecting the local variable attributes
+ if (elseInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ elseInitStateIndex);
+ codeStream.addDefinitelyAssignedVariables(currentScope, elseInitStateIndex);
+ }
+ elseStatement.generateCode(currentScope, codeStream);
+ }
+ endifLabel.place();
+ // May loose some local variable initializations : affecting the local variable attributes
+ if (mergedInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ mergedInitStateIndex);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public void resolve(BlockScope scope) {
+ TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding);
+ condition.implicitWidening(type, type);
+ if (thenStatement != null)
+ thenStatement.resolve(scope);
+ if (elseStatement != null)
+ elseStatement.resolve(scope);
+ }
+
+ public String toString(int tab) {
+ /*slow code */
+
+ String inFront, s = tabString(tab);
+ inFront = s;
+ s = s + "if (" + condition.toStringExpression() + ") \n";
+ s = s + thenStatement.toString(tab + 2) + ";";
+ if (elseStatement != null)
+ s = s + "\n" + inFront + "else\n" + elseStatement.toString(tab + 2) + ";";
+ return s;
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ if (visitor.visit(this, blockScope)) {
+ condition.traverse(visitor, blockScope);
+ if (thenStatement != null)
+ thenStatement.traverse(visitor, blockScope);
+ if (elseStatement != null)
+ elseStatement.traverse(visitor, blockScope);
+ }
+ visitor.endVisit(this, blockScope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ImportReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ImportReference.java
new file mode 100644
index 0000000000..2e9ba72a89
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ImportReference.java
@@ -0,0 +1,62 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class ImportReference extends AstNode {
+ public char[][] tokens;
+ public long[] sourcePositions;
+ //each entry is using the code : (start<<32) + end
+ public boolean onDemand = true; //most of the time
+
+ public int declarationSourceStart;
+ public int declarationSourceEnd;
+
+ public ImportReference(char[][] sources, long[] poss, boolean d) {
+ tokens = sources;
+ sourcePositions = poss;
+ onDemand = d;
+ sourceEnd =
+ (int) (sourcePositions[sourcePositions.length - 1] & 0x00000000FFFFFFFF);
+ sourceStart = (int) (sourcePositions[0] >>> 32);
+ }
+
+ /**
+ * @return char[][]
+ */
+ public char[][] getImportName() {
+ return tokens;
+ }
+
+ public String toString(int tab) {
+
+ return toString(tab, true);
+ }
+
+ public String toString(int tab, boolean withOnDemand) {
+ /* when withOnDemand is false, only the name is printed */
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < tokens.length; i++) {
+ buffer.append(tokens[i]);
+ if (i < (tokens.length - 1)) {
+ buffer.append(".");
+ }
+ }
+ if (withOnDemand && onDemand) {
+ buffer.append(".*");
+ }
+ return buffer.toString();
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ CompilationUnitScope scope) {
+ visitor.visit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Initializer.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Initializer.java
new file mode 100644
index 0000000000..3b0b1e0d43
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Initializer.java
@@ -0,0 +1,105 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.parser.*;
+
+public class Initializer extends FieldDeclaration {
+ //public boolean isStatic = false ;
+ public Block block;
+ public int lastFieldID;
+ public int bodyStart;
+ public Initializer(Block block, int modifiers) {
+ this.block = block;
+ this.modifiers = modifiers;
+
+ declarationSourceStart = sourceStart = block.sourceStart;
+ }
+
+ public FlowInfo analyseCode(
+ MethodScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ return block.analyseCode(currentScope, flowContext, flowInfo);
+ }
+
+ /**
+ * Code generation for a non-static initializer
+ * i.e. normal block code gen
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ */
+ public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+ if ((bits & IsReachableMASK) == 0) {
+ return;
+ }
+ int pc = codeStream.position;
+ block.generateCode(currentScope, codeStream);
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public boolean isField() {
+ return false;
+ }
+
+ public boolean isStatic() {
+ return (modifiers & AccStatic) != 0;
+ }
+
+ public void parseStatements(
+ Parser parser,
+ TypeDeclaration type,
+ CompilationUnitDeclaration unit) {
+ //fill up the method body with statement
+
+ parser.parse(this, type, unit);
+ }
+
+ public void resolve(MethodScope scope) {
+ int previous = scope.fieldDeclarationIndex;
+ try {
+ scope.fieldDeclarationIndex = lastFieldID;
+ if (isStatic()) {
+ ReferenceBinding declaringType = scope.enclosingSourceType();
+ if (declaringType.isNestedType() && !declaringType.isStatic())
+ scope.problemReporter().innerTypesCannotDeclareStaticInitializers(
+ declaringType,
+ this);
+ }
+ block.resolve(scope);
+ } finally {
+ scope.fieldDeclarationIndex = previous;
+ }
+ }
+
+ public String toString(int tab) {
+ /*slow code */
+
+ if (modifiers != 0) {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(tabString(tab));
+ buffer.append(modifiersString(modifiers));
+ buffer.append("{\n");
+ buffer.append(block.toStringStatements(tab));
+ buffer.append(tabString(tab));
+ buffer.append("}");
+ return buffer.toString();
+ } else {
+ return block.toString(tab);
+ }
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, MethodScope scope) {
+ visitor.visit(this, scope);
+ block.traverse(visitor, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InnerTypeDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InnerTypeDeclaration.java
new file mode 100644
index 0000000000..b93207d976
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InnerTypeDeclaration.java
@@ -0,0 +1,12 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+public class InnerTypeDeclaration extends TypeDeclaration {
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java
new file mode 100644
index 0000000000..b7a3780427
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java
@@ -0,0 +1,250 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class InstanceOfExpression extends OperatorExpression {
+ public Expression expression;
+ public TypeReference type;
+ public InstanceOfExpression(
+ Expression expression,
+ TypeReference type,
+ int operator) {
+ this.expression = expression;
+ this.type = type;
+ this.bits |= operator << OperatorSHIFT;
+ this.sourceStart = expression.sourceStart;
+ this.sourceEnd = type.sourceEnd;
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ return expression
+ .analyseCode(currentScope, flowContext, flowInfo)
+ .unconditionalInits();
+ }
+
+ public final boolean areTypesCastCompatible(
+ BlockScope scope,
+ TypeBinding castTb,
+ TypeBinding expressionTb) {
+ // see specifications p.68
+ //A more cpmplete version of this method is provided on
+ //CastExpression (it deals with constant and need runtime checkcast)
+
+ //by grammatical construction, the first test is ALWAYS false
+ //if (castTb.isBaseType())
+ //{ if (expressionTb.isBaseType())
+ // { if (expression.isConstantValueOfTypeAssignableToType(expressionTb,castTb))
+ // { return true;}
+ // else
+ // { if (expressionTb==castTb)
+ // { return true;}
+ // else
+ // { if (scope.areTypesCompatible(expressionTb,castTb))
+ // { return true; }
+ //
+ // if (BaseTypeBinding.isNarrowing(castTb.id,expressionTb.id))
+ // { return true;}
+ // return false;}}}
+ // else
+ // { return false; }}
+ //else
+ { //-------------checkcast to something which is NOT a basetype----------------------------------
+
+ if (NullBinding == expressionTb)
+ //null is compatible with every thing ....
+ {
+ return true;
+ }
+ if (expressionTb.isArrayType()) {
+ if (castTb.isArrayType()) {
+ //------- (castTb.isArray) expressionTb.isArray -----------
+ TypeBinding expressionEltTb = ((ArrayBinding) expressionTb).elementsType(scope);
+ if (expressionEltTb.isBaseType())
+ // <---stop the recursion-------
+ return ((ArrayBinding) castTb).elementsType(scope) == expressionEltTb;
+ //recursivly on the elts...
+ return areTypesCastCompatible(
+ scope,
+ ((ArrayBinding) castTb).elementsType(scope),
+ expressionEltTb);
+ }
+ if (castTb.isClass()) {
+ //------(castTb.isClass) expressionTb.isArray ---------------
+ if (scope.isJavaLangObject(castTb))
+ return true;
+ return false;
+ }
+ if (castTb.isInterface()) {
+ //------- (castTb.isInterface) expressionTb.isArray -----------
+ if (scope.isJavaLangCloneable(castTb) || scope.isJavaIoSerializable(castTb)) {
+ return true;
+ }
+ return false;
+ }
+
+ //=========hoops=============
+ return false;
+ }
+ if (expressionTb.isBaseType()) {
+ return false;
+ }
+ if (expressionTb.isClass()) {
+ if (castTb.isArrayType()) {
+ // ---- (castTb.isArray) expressionTb.isClass -------
+ if (scope.isJavaLangObject(expressionTb)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ if (castTb.isClass()) { // ----- (castTb.isClass) expressionTb.isClass ------
+ if (scope.areTypesCompatible(expressionTb, castTb))
+ return true;
+ else {
+ if (scope.areTypesCompatible(castTb, expressionTb)) {
+ return true;
+ }
+ return false;
+ }
+ }
+ if (castTb.isInterface()) {
+ // ----- (castTb.isInterface) expressionTb.isClass -------
+ if (((ReferenceBinding) expressionTb).isFinal()) {
+ //no subclass for expressionTb, thus compile-time check is valid
+ if (scope.areTypesCompatible(expressionTb, castTb))
+ return true;
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ //=========hoops==============
+ return false;
+ }
+ if (expressionTb.isInterface()) {
+ if (castTb.isArrayType()) {
+ // ----- (castTb.isArray) expressionTb.isInterface ------
+ if (scope.isJavaLangCloneable(expressionTb)
+ || scope.isJavaIoSerializable(expressionTb))
+ //potential runtime error
+ {
+ return true;
+ }
+ return false;
+ }
+ if (castTb.isClass()) {
+ // ----- (castTb.isClass) expressionTb.isInterface --------
+ if (scope.isJavaLangObject(castTb))
+ return true;
+ if (((ReferenceBinding) castTb).isFinal()) {
+ //no subclass for castTb, thus compile-time check is valid
+ if (scope.areTypesCompatible(castTb, expressionTb)) {
+ return true;
+ }
+ return false;
+ }
+ return true;
+ }
+ if (castTb.isInterface()) {
+ // ----- (castTb.isInterface) expressionTb.isInterface -------
+ if (castTb != expressionTb
+ && (scope.compareTypes(castTb, expressionTb) == NotRelated)) {
+ MethodBinding[] castTbMethods = ((ReferenceBinding) castTb).methods();
+ int castTbMethodsLength = castTbMethods.length;
+ MethodBinding[] expressionTbMethods =
+ ((ReferenceBinding) expressionTb).methods();
+ int expressionTbMethodsLength = expressionTbMethods.length;
+ for (int i = 0; i < castTbMethodsLength; i++) {
+ for (int j = 0; j < expressionTbMethodsLength; j++) {
+ if (castTbMethods[i].selector == expressionTbMethods[j].selector) {
+ if (castTbMethods[i].returnType != expressionTbMethods[j].returnType) {
+ if (castTbMethods[i].areParametersEqual(expressionTbMethods[j])) {
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ //============hoops===========
+ return false;
+ } // true;}
+
+ //=======hoops==========
+ return false;
+ }
+ }
+
+ /**
+ * Code generation for instanceOfExpression
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param valueRequired boolean
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ expression.generateCode(currentScope, codeStream, true);
+ codeStream.instance_of(type.binding);
+ if (!valueRequired)
+ codeStream.pop();
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ constant = NotAConstant;
+ TypeBinding expressionTb = expression.resolveType(scope);
+ TypeBinding checkTb = type.resolveType(scope);
+ if (expressionTb == null || checkTb == null)
+ return null;
+
+ //===== by grammatical construction, the next test is always false =====
+ //if (checkTb.isBaseType()) {
+ // scope.problemReporter().invalidTypeError(type,checkTb);
+ // return null;
+ //}
+
+ if (!areTypesCastCompatible(scope, checkTb, expressionTb)) {
+ scope.problemReporter().notCompatibleTypesError(this, expressionTb, checkTb);
+ return null;
+ }
+ return BooleanBinding;
+ }
+
+ public String toStringExpressionNoParenthesis() {
+ /* slow code*/
+
+ if (((bits & OperatorMASK) >> OperatorSHIFT) != INSTANCEOF)
+ return "houps instanceof houps";
+ return expression.toStringExpression() + " instanceof " + type.toString(0);
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ if (visitor.visit(this, scope)) {
+ expression.traverse(visitor, scope);
+ type.traverse(visitor, scope);
+ }
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IntLiteral.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IntLiteral.java
new file mode 100644
index 0000000000..6780b7b823
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IntLiteral.java
@@ -0,0 +1,178 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class IntLiteral extends NumberLiteral {
+ public int value;
+
+ public static final IntLiteral One =
+ new IntLiteral(new char[] { '1' }, 0, 0, 1);
+ //used for ++ and --
+
+ static final Constant FORMAT_ERROR = new DoubleConstant(1.0 / 0.0); // NaN;
+ public IntLiteral(char[] token, int s, int e) {
+ super(token, s, e);
+ }
+
+ public IntLiteral(char[] token, int s, int e, int value) {
+ this(token, s, e);
+ this.value = value;
+ }
+
+ public IntLiteral(int intValue) {
+ //special optimized constructor : the cst is the argument
+
+ //value that should not be used
+ // tokens = null ;
+ // sourceStart = 0;
+ // sourceEnd = 0;
+ super(null, 0, 0);
+ constant = Constant.fromValue(intValue);
+ value = intValue;
+
+ }
+
+ public void computeConstant() {
+ //a special constant is use for the potential Integer.MAX_VALUE+1
+ //which is legal if used with a - as prefix....cool....
+ //notice that Integer.MIN_VALUE == -2147483648
+
+ long MAX = Integer.MAX_VALUE;
+ if (this == One) {
+ constant = Constant.One;
+ return;
+ }
+
+ int length = source.length;
+ long computedValue = 0L;
+ if (source[0] == '0') {
+ MAX = 0xFFFFFFFFL; //a long in order to be positive !
+ if (length == 1) {
+ constant = Constant.fromValue(0);
+ return;
+ }
+ final int shift, radix;
+ int j;
+ if ((source[1] == 'x') | (source[1] == 'X')) {
+ shift = 4;
+ j = 2;
+ radix = 16;
+ } else {
+ shift = 3;
+ j = 1;
+ radix = 8;
+ }
+ while (source[j] == '0') {
+ j++; //jump over redondant zero
+ if (j == length) { //watch for 000000000000000000 :-(
+ constant = Constant.fromValue(value = (int) computedValue);
+ return;
+ }
+ }
+
+ while (j < length) {
+ int digitValue;
+ if ((digitValue = Character.digit(source[j++], radix)) < 0) {
+ constant = FORMAT_ERROR;
+ return;
+ }
+ computedValue = (computedValue << shift) | digitValue;
+ if (computedValue > MAX)
+ return /*constant stays null*/;
+ }
+ } else { //-----------regular case : radix = 10-----------
+ for (int i = 0; i < length; i++) {
+ int digitValue;
+ if ((digitValue = Character.digit(source[i], 10)) < 0) {
+ constant = FORMAT_ERROR;
+ return;
+ }
+ computedValue = 10 * computedValue + digitValue;
+ if (computedValue > MAX)
+ return /*constant stays null*/;
+ }
+ }
+
+ constant = Constant.fromValue(value = (int) computedValue);
+
+ }
+
+ /**
+ * Code generation for int literal
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param valueRequired boolean
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ if (valueRequired)
+ if ((implicitConversion >> 4) == T_int)
+ codeStream.generateInlinedValue(value);
+ else
+ codeStream.generateConstant(constant, implicitConversion);
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public TypeBinding literalType(BlockScope scope) {
+ return IntBinding;
+ }
+
+ public final boolean mayRepresentMIN_VALUE() {
+ //a special autorized int literral is 2147483648
+ //which is ONE over the limit. This special case
+ //only is used in combinaison with - to denote
+ //the minimal value of int -2147483648
+
+ return (
+ (source.length == 10)
+ && (source[0] == '2')
+ && (source[1] == '1')
+ && (source[2] == '4')
+ && (source[3] == '7')
+ && (source[4] == '4')
+ && (source[5] == '8')
+ && (source[6] == '3')
+ && (source[7] == '6')
+ && (source[8] == '4')
+ && (source[9] == '8'));
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ // the format may be incorrect while the scanner could detect
+ // such an error only on painfull tests...easier and faster here
+
+ TypeBinding tb = super.resolveType(scope);
+ if (constant == FORMAT_ERROR) {
+ constant = NotAConstant;
+ scope.problemReporter().constantOutOfFormat(this);
+ return null;
+ }
+ return tb;
+ }
+
+ public String toStringExpression() {
+
+ if (source == null)
+ /* special optimized IntLiteral that are created by the compiler */
+ return String.valueOf(value);
+
+ return super.toStringExpression();
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ visitor.visit(this, scope);
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IntLiteralMinValue.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IntLiteralMinValue.java
new file mode 100644
index 0000000000..6139f3582a
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IntLiteralMinValue.java
@@ -0,0 +1,27 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class IntLiteralMinValue extends IntLiteral {
+
+ final static char[] CharValue =
+ new char[] { '-', '2', '1', '4', '7', '4', '8', '3', '6', '4', '8' };
+ final static Constant MIN_VALUE = Constant.fromValue(Integer.MIN_VALUE);
+
+ public IntLiteralMinValue() {
+ super(CharValue, 0, 0, Integer.MIN_VALUE);
+ constant = MIN_VALUE;
+ }
+
+ public void computeConstant() {
+
+ /*precomputed at creation time*/
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java
new file mode 100644
index 0000000000..27548ba008
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java
@@ -0,0 +1,112 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class LabeledStatement extends Statement {
+ public Statement statement;
+ public char[] label;
+ public Label targetLabel;
+
+ // for local variables table attributes
+ int mergedInitStateIndex = -1;
+ /**
+ * LabeledStatement constructor comment.
+ */
+ public LabeledStatement(char[] l, Statement st, int s, int e) {
+ statement = st;
+ label = l;
+ sourceStart = s;
+ sourceEnd = e;
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+
+ // need to stack a context to store explicit label, answer inits in case of normal completion merged
+ // with those relative to the exit path from break statement occurring inside the labeled statement.
+
+ if (statement == null) {
+ return flowInfo;
+ } else {
+ LabelFlowContext labelContext;
+ FlowInfo mergedInfo =
+ statement
+ .analyseCode(
+ currentScope,
+ (labelContext =
+ new LabelFlowContext(
+ flowContext,
+ this,
+ label,
+ (targetLabel = new Label()),
+ currentScope)),
+ flowInfo)
+ .mergedWith(labelContext.initsOnBreak);
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(mergedInfo);
+ return mergedInfo;
+ }
+ }
+
+ public AstNode concreteStatement() {
+ return statement.concreteStatement();
+ }
+
+ /**
+ * Code generation for labeled statement
+ *
+ * may not need actual source positions recording
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ */
+ public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+ int pc = codeStream.position;
+ if (targetLabel != null) {
+ targetLabel.codeStream = codeStream;
+ if (statement != null) {
+ statement.generateCode(currentScope, codeStream);
+ }
+ targetLabel.place();
+ }
+ // May loose some local variable initializations : affecting the local variable attributes
+ if (mergedInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ mergedInitStateIndex);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public void resolve(BlockScope scope) {
+ statement.resolve(scope);
+ }
+
+ public String toString(int tab) {
+ /* slow code */
+
+ String s = tabString(tab);
+ s += new String(label) + ": " + statement.toString(0);
+ return s;
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ if (visitor.visit(this, blockScope)) {
+ statement.traverse(visitor, blockScope);
+ }
+ visitor.endVisit(this, blockScope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Literal.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Literal.java
new file mode 100644
index 0000000000..951ad21be2
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Literal.java
@@ -0,0 +1,34 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public abstract class Literal extends Expression {
+
+ public Literal(int s, int e) {
+ sourceStart = s;
+ sourceEnd = e;
+ }
+
+ public abstract void computeConstant();
+ //ON ERROR constant STAYS NULL
+ public abstract TypeBinding literalType(BlockScope scope);
+ public TypeBinding resolveType(BlockScope scope) {
+ // compute the real value, which must range its type's range
+
+ computeConstant();
+ if (constant == null) {
+ scope.problemReporter().constantOutOfRange(this);
+ constant = Constant.NotAConstant;
+ return null;
+ }
+ return literalType(scope);
+ }
+
+ public abstract char[] source();
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java
new file mode 100644
index 0000000000..88d3cb1065
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java
@@ -0,0 +1,201 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class LocalDeclaration extends AbstractVariableDeclaration {
+ public LocalVariableBinding binding;
+ public LocalDeclaration(
+ Expression expr,
+ char[] name,
+ int sourceStart,
+ int sourceEnd) {
+
+ initialization = expr;
+ this.name = name;
+ this.sourceStart = sourceStart;
+ this.sourceEnd = sourceEnd;
+ if (initialization != null) {
+ declarationSourceEnd = initialization.sourceEnd;
+ } else {
+ declarationSourceEnd = sourceEnd;
+ }
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+
+ // record variable initialization if any
+
+ /* EXTRA REFERENCE RECORDING
+ if (!binding.type.isBaseType()) {
+ // need to manually remember the variable type as part of the reference information
+ currentScope.referenceType().recordReferenceTo(binding.type);
+ }
+ */
+
+ if (initialization == null)
+ return flowInfo;
+ flowInfo =
+ initialization
+ .analyseCode(currentScope, flowContext, flowInfo)
+ .unconditionalInits();
+ flowInfo.markAsDefinitelyAssigned(binding);
+ return flowInfo;
+ }
+
+ public void checkModifiers() {
+ //only potential valid modifier is <<final>>
+
+ if (((modifiers & AccJustFlag) | AccFinal) != AccFinal)
+ //AccModifierProblem -> other (non-visibility problem)
+ //AccAlternateModifierProblem -> duplicate modifier
+ //AccModifierProblem | AccAlternateModifierProblem -> visibility problem"
+
+ // -x-1 returns the bitInvert
+
+ modifiers =
+ (modifiers & (-AccAlternateModifierProblem - 1)) | AccModifierProblem;
+ }
+
+ /**
+ * Code generation for a local declaration
+ * i.e. normal assignment to a local variable + unused variable handling
+ */
+ public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+ if ((bits & IsReachableMASK) == 0) {
+ return;
+ }
+ int pc = codeStream.position;
+ Constant inlinedValue;
+ // something to initialize?
+ if (binding.resolvedPosition != -1) {
+ codeStream.addVisibleLocalVariable(binding);
+ }
+ if (initialization != null) {
+ // initialize to constant value?
+ if ((inlinedValue = initialization.constant) != NotAConstant) {
+ // forget initializing unused or final locals set to constant value (final ones are inlined)
+ if (binding.resolvedPosition != -1) { // may need to preserve variable
+ int initPC = codeStream.position;
+ codeStream.generateConstant(inlinedValue, initialization.implicitConversion);
+ codeStream.recordPositionsFrom(initPC, initialization);
+ codeStream.store(binding, false);
+ binding.recordInitializationStartPC(codeStream.position);
+ // codeStream.lastInitStateIndexWhenRemovingInits = -2; // reinitialize remove index
+ // codeStream.lastInitStateIndexWhenAddingInits = -2; // reinitialize add index
+ }
+ } else { // initializing to non-constant value
+ initialization.generateCode(currentScope, codeStream, true);
+ // if binding unused generate then discard the value
+ if (binding.resolvedPosition != -1) {
+ codeStream.store(binding, false);
+ if (binding.initializationCount == 0) {
+ /* Variable may have been initialized during the code initializing it
+ e.g. int i = (i = 1);
+ */
+ binding.recordInitializationStartPC(codeStream.position);
+ // codeStream.lastInitStateIndexWhenRemovingInits = -2; // reinitialize remove index
+ // codeStream.lastInitStateIndexWhenAddingInits = -2; // reinitialize add index
+ }
+ } else {
+ if ((binding.type == LongBinding) || (binding.type == DoubleBinding)) {
+ codeStream.pop2();
+ } else {
+ codeStream.pop();
+ }
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public String name() {
+
+ return String.valueOf(name);
+ }
+
+ public void resolve(BlockScope scope) {
+ // create a binding and add it to the scope
+ TypeBinding tb = type.resolveType(scope);
+
+ checkModifiers();
+
+ if (tb != null) {
+ if (tb == VoidBinding) {
+ scope.problemReporter().variableTypeCannotBeVoid(this);
+ return;
+ }
+ if (tb.isArrayType() && ((ArrayBinding) tb).leafComponentType == VoidBinding) {
+ scope.problemReporter().variableTypeCannotBeVoidArray(this);
+ return;
+ }
+ }
+
+ // duplicate checks
+ if ((binding = scope.duplicateName(name)) != null) {
+ // the name already exists... may carry on with the first binding...
+ scope.problemReporter().redefineLocal(this);
+ } else {
+ binding = new LocalVariableBinding(this, tb, modifiers);
+ scope.addLocalVariable(binding);
+ binding.constant = NotAConstant;
+ // allow to recursivelly target the binding....
+ // the correct constant is harmed if correctly computed at the end of this method
+ }
+
+ if (tb == null) {
+ if (initialization != null)
+ initialization.resolveType(scope); // want to report all possible errors
+ return;
+ }
+
+ // store the constant for final locals
+ if (initialization != null) {
+ if (initialization instanceof ArrayInitializer) {
+ TypeBinding initTb = initialization.resolveTypeExpecting(scope, tb);
+ if (initTb != null) {
+ ((ArrayInitializer) initialization).binding = (ArrayBinding) initTb;
+ initialization.implicitWidening(tb, initTb);
+ }
+ } else {
+ TypeBinding initTb = initialization.resolveType(scope);
+ if (initTb != null) {
+ if (initialization.isConstantValueOfTypeAssignableToType(initTb, tb)
+ || (tb.isBaseType() && BaseTypeBinding.isWidening(tb.id, initTb.id))
+ || scope.areTypesCompatible(initTb, tb))
+ initialization.implicitWidening(tb, initTb);
+ else
+ scope.problemReporter().typeMismatchError(initTb, tb, this);
+ }
+ }
+
+ // change the constant in the binding when it is final
+ // (the optimization of the constant propagation will be done later on)
+ // cast from constant actual type to variable type
+ binding.constant =
+ binding.isFinal()
+ ? initialization.constant.castTo((tb.id << 4) + initialization.constant.typeID())
+ : NotAConstant;
+ }
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ if (visitor.visit(this, scope)) {
+ type.traverse(visitor, scope);
+ if (initialization != null)
+ initialization.traverse(visitor, scope);
+ }
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalTypeDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalTypeDeclaration.java
new file mode 100644
index 0000000000..ff6f5b657a
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalTypeDeclaration.java
@@ -0,0 +1,60 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+public class LocalTypeDeclaration extends InnerTypeDeclaration {
+ public AbstractMethodDeclaration enclosingMethod;
+
+ /**
+ * Iteration for a local innertype
+ *
+ */
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ if (ignoreFurtherInvestigation)
+ return;
+ try {
+ if (visitor.visit(this, blockScope)) {
+ if (superclass != null)
+ superclass.traverse(visitor, scope);
+ if (superInterfaces != null) {
+ int superInterfaceLength = superInterfaces.length;
+ for (int i = 0; i < superInterfaceLength; i++)
+ superInterfaces[i].traverse(visitor, scope);
+ }
+ if (memberTypes != null) {
+ int memberTypesLength = memberTypes.length;
+ for (int i = 0; i < memberTypesLength; i++)
+ memberTypes[i].traverse(visitor, scope);
+ }
+ if (fields != null) {
+ int fieldsLength = fields.length;
+ for (int i = 0; i < fieldsLength; i++) {
+ FieldDeclaration field;
+ if ((field = fields[i]).isStatic()) {
+ // local type cannot have static fields
+ } else {
+ field.traverse(visitor, initializerScope);
+ }
+ }
+ }
+ if (methods != null) {
+ int methodsLength = methods.length;
+ for (int i = 0; i < methodsLength; i++)
+ methods[i].traverse(visitor, scope);
+ }
+ }
+ visitor.endVisit(this, blockScope);
+ } catch (AbortType e) {
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LongLiteral.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LongLiteral.java
new file mode 100644
index 0000000000..8b6b28d478
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LongLiteral.java
@@ -0,0 +1,171 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class LongLiteral extends NumberLiteral {
+ long value;
+
+ static final Constant FORMAT_ERROR = new DoubleConstant(1.0 / 0.0); // NaN;
+
+ public LongLiteral(char[] token, int s, int e) {
+ super(token, s, e);
+ }
+
+ public LongLiteral(char[] token, int s, int e, long value) {
+ this(token, s, e);
+ this.value = value;
+ }
+
+ public void computeConstant() {
+ //the overflow (when radix=10) is tested using the fact that
+ //the value should always grow during its computation
+
+ int length = source.length - 1;
+ //minus one because the last char is 'l' or 'L'
+
+ long computedValue;
+ if (source[0] == '0') {
+ if (length == 1) {
+ constant = Constant.fromValue(0);
+ return;
+ }
+ final int shift, radix;
+ int j;
+ if ((source[1] == 'x') | (source[1] == 'X')) {
+ shift = 4;
+ j = 2;
+ radix = 16;
+ } else {
+ shift = 3;
+ j = 1;
+ radix = 8;
+ }
+ int nbDigit = 0;
+ while (source[j] == '0') {
+ j++; //jump over redondant zero
+ if (j == length) { //watch for 0000000000000L
+ constant = Constant.fromValue(value = 0L);
+ return;
+ }
+ }
+
+ int digitValue;
+ if ((digitValue = Character.digit(source[j++], radix)) < 0) {
+ constant = FORMAT_ERROR;
+ return;
+ }
+ if (digitValue >= 8)
+ nbDigit = 4;
+ else
+ if (digitValue >= 4)
+ nbDigit = 3;
+ else
+ if (digitValue >= 2)
+ nbDigit = 2;
+ else
+ nbDigit = 1; //digitValue is not 0
+ computedValue = digitValue;
+ while (j < length) {
+ if ((digitValue = Character.digit(source[j++], radix)) < 0) {
+ constant = FORMAT_ERROR;
+ return;
+ }
+ if ((nbDigit += shift) > 64)
+ return /*constant stays null*/;
+ computedValue = (computedValue << shift) | digitValue;
+ }
+ } else { //-----------case radix=10-----------------
+ long previous = computedValue = 0;
+ for (int i = 0; i < length; i++) {
+ int digitValue;
+ if ((digitValue = Character.digit(source[i], 10)) < 0)
+ return /*constant stays null*/;
+ previous = computedValue;
+ computedValue = 10 * computedValue + digitValue;
+ if (previous > computedValue)
+ return /*constant stays null*/;
+ }
+ }
+
+ constant = Constant.fromValue(value = computedValue);
+ }
+
+ /**
+ * Code generation for long literal
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param valueRequired boolean
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ if (valueRequired)
+ if ((implicitConversion >> 4) == T_long)
+ codeStream.generateInlinedValue(value);
+ else
+ codeStream.generateConstant(constant, implicitConversion);
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public TypeBinding literalType(BlockScope scope) {
+ return LongBinding;
+ }
+
+ public final boolean mayRepresentMIN_VALUE() {
+ //a special autorized int literral is 9223372036854775808L
+ //which is ONE over the limit. This special case
+ //only is used in combinaison with - to denote
+ //the minimal value of int -9223372036854775808L
+
+ return (
+ (source.length == 20)
+ && (source[0] == '9')
+ && (source[1] == '2')
+ && (source[2] == '2')
+ && (source[3] == '3')
+ && (source[4] == '3')
+ && (source[5] == '7')
+ && (source[6] == '2')
+ && (source[7] == '0')
+ && (source[8] == '3')
+ && (source[9] == '6')
+ && (source[10] == '8')
+ && (source[11] == '5')
+ && (source[12] == '4')
+ && (source[13] == '7')
+ && (source[14] == '7')
+ && (source[15] == '5')
+ && (source[16] == '8')
+ && (source[17] == '0')
+ && (source[18] == '8'));
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ // the format may be incorrect while the scanner could detect
+ // such error only on painfull tests...easier and faster here
+
+ TypeBinding tb = super.resolveType(scope);
+ if (constant == FORMAT_ERROR) {
+ constant = NotAConstant;
+ scope.problemReporter().constantOutOfFormat(this);
+ return null;
+ }
+ return tb;
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ visitor.visit(this, scope);
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LongLiteralMinValue.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LongLiteralMinValue.java
new file mode 100644
index 0000000000..b7fa7fcee6
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LongLiteralMinValue.java
@@ -0,0 +1,47 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class LongLiteralMinValue extends LongLiteral {
+
+ final static char[] CharValue =
+ new char[] {
+ '-',
+ '9',
+ '2',
+ '2',
+ '3',
+ '3',
+ '7',
+ '2',
+ '0',
+ '3',
+ '6',
+ '8',
+ '5',
+ '4',
+ '7',
+ '7',
+ '5',
+ '8',
+ '0',
+ '8',
+ 'L' };
+ final static Constant MIN_VALUE = Constant.fromValue(Long.MIN_VALUE);
+
+ public LongLiteralMinValue() {
+ super(CharValue, 0, 0, Long.MIN_VALUE);
+ constant = MIN_VALUE;
+ }
+
+ public void computeConstant() {
+
+ /*precomputed at creation time*/
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MagicLiteral.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MagicLiteral.java
new file mode 100644
index 0000000000..2ae66e10a3
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MagicLiteral.java
@@ -0,0 +1,27 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+public abstract class MagicLiteral extends Literal {
+ public MagicLiteral(int s, int e) {
+ super(s, e);
+ }
+
+ public boolean isValidJavaStatement() {
+ //should never be reach, but with a bug in the ast tree....
+ //see comment on the Statement class
+
+ return false;
+ }
+
+ /**
+ * source method comment.
+ */
+ public char[] source() {
+ return null;
+ }
+
+ public String toStringExpression() {
+
+ return new String(source());
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MemberTypeDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MemberTypeDeclaration.java
new file mode 100644
index 0000000000..6ee701fefc
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MemberTypeDeclaration.java
@@ -0,0 +1,58 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
+import org.eclipse.jdt.internal.compiler.problem.AbortType;
+
+public class MemberTypeDeclaration extends InnerTypeDeclaration {
+ public TypeDeclaration enclosingType;
+ /**
+ * Iteration for a member innertype
+ *
+ */
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ ClassScope classScope) {
+ if (ignoreFurtherInvestigation)
+ return;
+ try {
+ if (visitor.visit(this, classScope)) {
+ if (superclass != null)
+ superclass.traverse(visitor, scope);
+ if (superInterfaces != null) {
+ int superInterfaceLength = superInterfaces.length;
+ for (int i = 0; i < superInterfaceLength; i++)
+ superInterfaces[i].traverse(visitor, scope);
+ }
+ if (memberTypes != null) {
+ int memberTypesLength = memberTypes.length;
+ for (int i = 0; i < memberTypesLength; i++)
+ memberTypes[i].traverse(visitor, scope);
+ }
+ if (fields != null) {
+ int fieldsLength = fields.length;
+ for (int i = 0; i < fieldsLength; i++) {
+ FieldDeclaration field;
+ if ((field = fields[i]).isStatic()) {
+ field.traverse(visitor, staticInitializerScope);
+ } else {
+ field.traverse(visitor, initializerScope);
+ }
+ }
+ }
+ if (methods != null) {
+ int methodsLength = methods.length;
+ for (int i = 0; i < methodsLength; i++)
+ methods[i].traverse(visitor, scope);
+ }
+ }
+ visitor.endVisit(this, classScope);
+ } catch (AbortType e) {
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
new file mode 100644
index 0000000000..797668f2c2
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
@@ -0,0 +1,309 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class MessageSend extends Expression implements InvocationSite {
+ public Expression receiver;
+ public char[] selector;
+ public Expression[] arguments;
+ public MethodBinding binding;
+
+ public long nameSourcePosition; //(start<<32)+end
+
+ MethodBinding syntheticAccessor;
+
+ public MessageSend() {
+
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+
+ flowInfo =
+ receiver
+ .analyseCode(currentScope, flowContext, flowInfo, !binding.isStatic())
+ .unconditionalInits();
+ if (arguments != null) {
+ int length = arguments.length;
+ for (int i = 0; i < length; i++) {
+ flowInfo =
+ arguments[i]
+ .analyseCode(currentScope, flowContext, flowInfo)
+ .unconditionalInits();
+ }
+ }
+ ReferenceBinding[] thrownExceptions;
+ if ((thrownExceptions = binding.thrownExceptions) != NoExceptions) {
+ // must verify that exceptions potentially thrown by this expression are caught in the method
+ flowContext.checkExceptionHandlers(
+ thrownExceptions,
+ this,
+ flowInfo,
+ currentScope);
+ }
+ // if invoking through an enclosing instance, then must perform the field generation -- only if reachable
+ manageEnclosingInstanceAccessIfNecessary(currentScope);
+ manageSyntheticAccessIfNecessary(currentScope);
+ return flowInfo;
+ }
+
+ /**
+ * MessageSend code generation
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param valueRequired boolean
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+
+ int pc = codeStream.position;
+
+ // generate receiver/enclosing instance access
+ boolean isStatic = binding.isStatic();
+ // outer access ?
+ if (!isStatic && ((bits & DepthMASK) != 0)) {
+ // outer method can be reached through emulation
+ Object[] path =
+ currentScope.getExactEmulationPath(
+ currentScope.enclosingSourceType().enclosingTypeAt(
+ (bits & DepthMASK) >> DepthSHIFT));
+ if (path == null) {
+ // emulation was not possible (should not happen per construction)
+ currentScope.problemReporter().needImplementation();
+ } else {
+ codeStream.generateOuterAccess(path, this, currentScope);
+ }
+ } else {
+ receiver.generateCode(currentScope, codeStream, !isStatic);
+ }
+ // generate arguments
+ if (arguments != null) {
+ for (int i = 0, max = arguments.length; i < max; i++) {
+ arguments[i].generateCode(currentScope, codeStream, true);
+ }
+ }
+ // actual message invocation
+ if (syntheticAccessor == null) {
+ if (isStatic) {
+ codeStream.invokestatic(binding);
+ } else {
+ if ((receiver.isSuper()) || binding.isPrivate()) {
+ codeStream.invokespecial(binding);
+ } else {
+ if (binding.declaringClass.isInterface()) {
+ codeStream.invokeinterface(binding);
+ } else {
+ codeStream.invokevirtual(binding);
+ }
+ }
+ }
+ } else {
+ codeStream.invokestatic(syntheticAccessor);
+ }
+ // operation on the returned value
+ if (valueRequired) {
+ // implicit conversion if necessary
+ codeStream.generateImplicitConversion(implicitConversion);
+ } else {
+ // pop return value if any
+ switch (binding.returnType.id) {
+ case T_long :
+ case T_double :
+ codeStream.pop2();
+ break;
+ case T_void :
+ break;
+ default :
+ codeStream.pop();
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public boolean isSuperAccess() {
+ return receiver.isSuper();
+ }
+
+ public boolean isTypeAccess() {
+ return receiver != null && receiver.isTypeReference();
+ }
+
+ public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
+ if (((bits & DepthMASK) != 0)
+ && (!binding.isStatic())
+ && (receiver == ThisReference.ThisImplicit)) {
+ ReferenceBinding compatibleType = currentScope.enclosingSourceType();
+ // the declaringClass of the target binding must be compatible with the enclosing
+ // type at <depth> levels outside
+ for (int i = 0, depth = (bits & DepthMASK) >> DepthSHIFT; i < depth; i++) {
+ compatibleType = compatibleType.enclosingType();
+ }
+ currentScope.emulateOuterAccess((SourceTypeBinding) compatibleType, false);
+ // request cascade of accesses
+ }
+ }
+
+ public void manageSyntheticAccessIfNecessary(BlockScope currentScope) {
+
+ if (((bits & DepthMASK) != 0)
+ || currentScope.enclosingSourceType() != binding.declaringClass) {
+ // implicit only have a depth set
+ if (binding.isPrivate()) { // private access
+ syntheticAccessor =
+ ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding);
+ currentScope.problemReporter().needToEmulateMethodAccess(binding, this);
+ return;
+ }
+ if (receiver == ThisReference.ThisImplicit
+ && binding.isProtected()
+ && (bits & DepthMASK) != 0 // only if outer access
+ && binding.declaringClass.getPackage()
+ != currentScope.enclosingSourceType().getPackage()) {
+ // protected access (implicit access only)
+ syntheticAccessor =
+ (
+ (SourceTypeBinding) currentScope.enclosingSourceType().enclosingTypeAt(
+ (bits & DepthMASK) >> DepthSHIFT)).addSyntheticMethod(
+ binding);
+ currentScope.problemReporter().needToEmulateMethodAccess(binding, this);
+ }
+ if (receiver instanceof QualifiedSuperReference) { // qualified super
+ SourceTypeBinding destinationType =
+ (SourceTypeBinding) (((QualifiedSuperReference) receiver)
+ .currentCompatibleType);
+ syntheticAccessor = destinationType.addSyntheticMethod(binding);
+ currentScope.problemReporter().needToEmulateMethodAccess(binding, this);
+ }
+ }
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ // Answer the signature return type
+ // Base type promotion
+
+ constant = NotAConstant;
+ TypeBinding receiverType = receiver.resolveType(scope);
+ // will check for null after args are resolved
+ TypeBinding[] argumentTypes = NoParameters;
+ if (arguments != null) {
+ boolean argHasError = false; // typeChecks all arguments
+ int length = arguments.length;
+ argumentTypes = new TypeBinding[length];
+ for (int i = 0; i < length; i++)
+ if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null)
+ argHasError = true;
+ if (argHasError)
+ return null;
+ }
+ if (receiverType == null)
+ return null;
+
+ // base type cannot receive any message
+ if (receiverType.isBaseType()) {
+ scope.problemReporter().errorNoMethodFor(this, receiverType, argumentTypes);
+ return null;
+ }
+
+ binding =
+ receiver == ThisReference.ThisImplicit
+ ? scope.getImplicitMethod(selector, argumentTypes, this)
+ : scope.getMethod(receiverType, selector, argumentTypes, this);
+ if (!binding.isValidBinding()) {
+ if (binding.declaringClass == null) {
+ if (receiverType instanceof ReferenceBinding) {
+ binding.declaringClass = (ReferenceBinding) receiverType;
+ } else { // really bad error ....
+ scope.problemReporter().errorNoMethodFor(this, receiverType, argumentTypes);
+ return null;
+ }
+ }
+ scope.problemReporter().invalidMethod(this, binding);
+ return null;
+ }
+ if (!binding.isStatic()) {
+ // the "receiver" must not be a type, i.e. a NameReference that the TC has bound to a Type
+ if (receiver instanceof NameReference) {
+ if ((((NameReference) receiver).bits & BindingIds.TYPE) != 0) {
+ scope.problemReporter().mustUseAStaticMethod(this, binding);
+ return null;
+ }
+ }
+ }
+ if (arguments != null)
+ for (int i = 0; i < arguments.length; i++)
+ arguments[i].implicitWidening(binding.parameters[i], argumentTypes[i]);
+
+ //-------message send that are known to fail at compile time-----------
+ if (binding.isAbstract()) {
+ if (receiver.isSuper()) {
+ scope.problemReporter().cannotDireclyInvokeAbstractMethod(this, binding);
+ return null;
+ }
+ // abstract private methods cannot occur nor abstract static............
+ }
+ if (isMethodUseDeprecated(binding, scope))
+ scope.problemReporter().deprecatedMethod(binding, this);
+ // if the binding declaring class is not visible, need special action
+ // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
+ if (binding.declaringClass != receiverType
+ && !binding.declaringClass.canBeSeenBy(scope))
+ binding = new MethodBinding(binding, (ReferenceBinding) receiverType);
+ return binding.returnType;
+ }
+
+ public void setDepth(int depth) {
+ if (depth > 0) {
+ bits |= (depth & 0xFF) << DepthSHIFT; // encoded on 8 bits
+ }
+ }
+
+ public void setFieldIndex(int depth) {
+ // ignore for here
+ }
+
+ public String toStringExpression() {
+ /*slow code*/
+
+ String s = "";
+ if (receiver != ThisReference.ThisImplicit)
+ s = s + receiver.toStringExpression() + ".";
+ s = s + new String(selector) + "(";
+ if (arguments != null)
+ for (int i = 0; i < arguments.length; i++) {
+ s = s + arguments[i].toStringExpression();
+ if (i != arguments.length - 1)
+ s = s + " , ";
+ };
+ ;
+ s = s + ")";
+ return s;
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ if (visitor.visit(this, blockScope)) {
+ receiver.traverse(visitor, blockScope);
+ if (arguments != null) {
+ int argumentsLength = arguments.length;
+ for (int i = 0; i < argumentsLength; i++)
+ arguments[i].traverse(visitor, blockScope);
+ }
+ }
+ visitor.endVisit(this, blockScope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java
new file mode 100644
index 0000000000..c4fe2f7339
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java
@@ -0,0 +1,108 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.parser.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class MethodDeclaration extends AbstractMethodDeclaration {
+ public TypeReference returnType;
+ /**
+ * MethodDeclaration constructor comment.
+ */
+ public MethodDeclaration() {
+ super();
+ }
+
+ public void checkName() {
+ // look if the name of the method is correct
+ if (isTypeUseDeprecated(binding.returnType, scope))
+ scope.problemReporter().deprecatedType(binding.returnType, returnType);
+
+ if (CharOperation.equals(scope.enclosingSourceType().sourceName, selector))
+ scope.problemReporter().methodWithConstructorName(this);
+
+ // by grammatical construction, interface methods are always abstract
+ if (scope.enclosingSourceType().isInterface())
+ return;
+
+ // if a method has an semicolon body and is not declared as abstract==>error
+ // native methods may have a semicolon body
+ if ((modifiers & AccSemicolonBody) != 0) {
+ if ((modifiers & AccNative) == 0)
+ if ((modifiers & AccAbstract) == 0)
+ scope.problemReporter().methodNeedingAbstractModifier(this);
+ } else {
+ // the method HAS a body --> abstract native modifiers are forbiden
+ if (((modifiers & AccNative) != 0) || ((modifiers & AccAbstract) != 0))
+ scope.problemReporter().methodNeedingNoBody(this);
+ }
+ }
+
+ public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
+ //fill up the method body with statement
+
+ if (ignoreFurtherInvestigation)
+ return;
+ parser.parse(this, unit);
+
+ }
+
+ public void resolve(ClassScope upperScope) {
+ if (binding == null) {
+ ignoreFurtherInvestigation = true;
+ return;
+ }
+ // ========= abort on fatal error =============
+ try {
+ if (this.returnType != null) {
+ this.returnType.binding = this.binding.returnType;
+ // record the return type binding
+ }
+ } catch (AbortMethod e) {
+ this.ignoreFurtherInvestigation = true;
+ }
+ super.resolve(upperScope);
+
+ }
+
+ public String returnTypeToString(int tab) {
+ /*slow code */
+
+ if (returnType == null)
+ return "";
+ return returnType.toString(tab) + " ";
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ ClassScope classScope) {
+ if (visitor.visit(this, classScope)) {
+ if (returnType != null)
+ returnType.traverse(visitor, scope);
+ if (arguments != null) {
+ int argumentLength = arguments.length;
+ for (int i = 0; i < argumentLength; i++)
+ arguments[i].traverse(visitor, scope);
+ }
+ if (thrownExceptions != null) {
+ int thrownExceptionsLength = thrownExceptions.length;
+ for (int i = 0; i < thrownExceptionsLength; i++)
+ thrownExceptions[i].traverse(visitor, scope);
+ }
+ if (statements != null) {
+ int statementsLength = statements.length;
+ for (int i = 0; i < statementsLength; i++)
+ statements[i].traverse(visitor, scope);
+ }
+ }
+ visitor.endVisit(this, classScope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NameReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NameReference.java
new file mode 100644
index 0000000000..a7a2f52436
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NameReference.java
@@ -0,0 +1,60 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public abstract class NameReference
+ extends Reference
+ implements InvocationSite, BindingIds {
+ public Binding binding;
+ //may be aTypeBinding-aFieldBinding-aLocalVariableBinding
+
+ //the error printing
+ //some name reference are build as name reference but
+ //only used as type reference. When it happens, instead of
+ //creating a new objet (aTypeReference) we just flag a boolean
+ //This concesion is valuable while their are cases when the NameReference
+ //will be a TypeReference (static message sends.....) and there is
+ //no changeClass in java.
+ public NameReference() {
+ super();
+ bits |= TYPE | VARIABLE; // restrictiveFlag
+
+ }
+
+ public FieldBinding fieldBinding() {
+ //this method should be sent ONLY after a check against isFieldReference()
+ //check its use doing senders.........
+
+ return (FieldBinding) binding;
+ }
+
+ public boolean isSuperAccess() {
+ return false;
+ }
+
+ public boolean isTypeAccess() {
+ // null is acceptable when we are resolving the first part of a reference
+ return binding == null || binding instanceof ReferenceBinding;
+ }
+
+ public boolean isTypeReference() {
+ return binding instanceof ReferenceBinding;
+ }
+
+ public void setDepth(int depth) {
+ if (depth > 0) {
+ bits |= (depth & 0xFF) << DepthSHIFT; // encoded on 8 bits
+ }
+ }
+
+ public void setFieldIndex(int index) {
+ }
+
+ public abstract String unboundReferenceErrorName();
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullLiteral.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullLiteral.java
new file mode 100644
index 0000000000..695c20d49d
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullLiteral.java
@@ -0,0 +1,56 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class NullLiteral extends MagicLiteral {
+ static final char[] source = { 'n', 'u', 'l', 'l' };
+ public NullLiteral(int s, int e) {
+ super(s, e);
+ }
+
+ public void computeConstant() {
+
+ constant = Constant.fromValue(null);
+ }
+
+ /**
+ * Code generation for the null literal
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param valueRequired boolean
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ if (valueRequired)
+ codeStream.aconst_null();
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public TypeBinding literalType(BlockScope scope) {
+ return NullBinding;
+ }
+
+ /**
+ *
+ */
+ public char[] source() {
+ return source;
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ visitor.visit(this, scope);
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NumberLiteral.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NumberLiteral.java
new file mode 100644
index 0000000000..671cb80bf9
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NumberLiteral.java
@@ -0,0 +1,30 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+public abstract class NumberLiteral extends Literal {
+ char[] source;
+ public NumberLiteral(char[] token, int s, int e) {
+ this(s, e);
+ source = token;
+ }
+
+ public NumberLiteral(int s, int e) {
+ super(s, e);
+ }
+
+ public boolean isValidJavaStatement() {
+ //should never be reach, but with a bug in the ast tree....
+ //see comment on the Statement class
+
+ return false;
+ }
+
+ public char[] source() {
+ return source;
+ }
+
+ public String toStringExpression() {
+
+ return new String(source);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/OR_OR_Expression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/OR_OR_Expression.java
new file mode 100644
index 0000000000..a4fd839599
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/OR_OR_Expression.java
@@ -0,0 +1,379 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class OR_OR_Expression extends BinaryExpression {
+ //dedicated treatment for the &&
+ int rightInitStateIndex = -1;
+ int mergedInitStateIndex = -1;
+
+ public OR_OR_Expression(Expression left, Expression right, int operator) {
+ super(left, right, operator);
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+
+ if (left.constant != NotAConstant) {
+ if (!left.constant.booleanValue()) { // false || anything
+ // in this case only, we are sure that local inits performed in
+ // the argument <anything> will be executed even though it was
+ // a conditional operation
+ return right.analyseCode(currentScope, flowContext, flowInfo);
+ } else { // true || anything
+ // in this case only, we are sure that local inits performed in
+ // the argument <anything> will *not* be executed even though it
+ // was a conditional operation
+ return flowInfo;
+ }
+ }
+ if (right.constant != NotAConstant) {
+ if (right.constant.booleanValue()) { // anything || true
+ // whatever is on the left, we will succeed, so the result must merge the left inits when answering
+ // initsWhenTrue.
+ // the initsWhenFalse are undetermined, since this path will be fake reachable...
+ FlowInfo mergedInfo =
+ left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(mergedInfo);
+ return mergedInfo;
+ } else { // anything || false
+ // ignore the right part
+ FlowInfo mergedInfo = left.analyseCode(currentScope, flowContext, flowInfo);
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(mergedInfo);
+ return mergedInfo;
+ }
+ }
+
+ if (right.constant != NotAConstant) {
+ // anything && true/false
+ // in this case only, we are sure that local inits performed in
+ // the argument <anything> will be executed even though it was
+ // a conditional operation
+ FlowInfo mergedInfo = left.analyseCode(currentScope, flowContext, flowInfo);
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(mergedInfo);
+ return mergedInfo;
+ }
+
+ FlowInfo leftInfo, rightInfo;
+ leftInfo = left.analyseCode(currentScope, flowContext, flowInfo);
+ rightInfo = leftInfo.initsWhenFalse().copy();
+ rightInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(rightInfo);
+ rightInfo = right.analyseCode(currentScope, flowContext, rightInfo);
+ FlowInfo mergedInfo = FlowInfo.conditional(
+ // merging two true initInfos for such a negative case: if ((t && (b = t)) || f) r = b; // b may not have been initialized
+ leftInfo.initsWhenTrue().unconditionalInits().mergedWith(
+ rightInfo.initsWhenTrue().copy().unconditionalInits()),
+ rightInfo.initsWhenFalse());
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(mergedInfo);
+ return mergedInfo;
+ }
+
+ public void computeConstant(BlockScope scope, int leftId, int rightId) {
+ //the TC has been done so leftId and rightId are both equal to T_boolean
+
+ Constant cst;
+ if ((cst = left.constant) != NotAConstant) {
+ if (cst.booleanValue() == true) { // true || x --> true
+ constant = cst; // inlined to constant(false)
+ } else { // false || x --> x
+ if ((constant = right.constant) == NotAConstant) {
+ // compute conditionalConstant
+ optimizedBooleanConstant(
+ leftId,
+ (bits & OperatorMASK) >> OperatorSHIFT,
+ rightId);
+ }
+ }
+ } else {
+ constant = NotAConstant;
+ // compute conditionalConstant
+ optimizedBooleanConstant(
+ leftId,
+ (bits & OperatorMASK) >> OperatorSHIFT,
+ rightId);
+ }
+ }
+
+ /**
+ * Code generation for a binary operation
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param valueRequired boolean
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ Label falseLabel, endLabel;
+ if (constant != Constant.NotAConstant) {
+ if (valueRequired)
+ codeStream.generateConstant(constant, implicitConversion);
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ bits |= OnlyValueRequiredMASK;
+ generateOptimizedConditionalOr(
+ currentScope,
+ codeStream,
+ null,
+ (falseLabel = new Label(codeStream)),
+ valueRequired);
+ /* improving code gen for such a case: boolean b = i < 0 || true;
+ * since the label has never been used, we have the inlined value on the stack. */
+ if (falseLabel.hasForwardReferences()) {
+ if (valueRequired) {
+ codeStream.iconst_1();
+ if ((bits & ValueForReturnMASK) != 0) {
+ codeStream.ireturn();
+ falseLabel.place();
+ codeStream.iconst_0();
+ } else {
+ codeStream.goto_(endLabel = new Label(codeStream));
+ codeStream.decrStackSize(1);
+ falseLabel.place();
+ codeStream.iconst_0();
+ endLabel.place();
+ }
+ } else {
+ falseLabel.place();
+ }
+ }
+ if (valueRequired) {
+ codeStream.generateImplicitConversion(implicitConversion);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ /**
+ * Boolean operator code generation
+ * Optimized operations are: ||
+ */
+ public void generateOptimizedBoolean(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Label trueLabel,
+ Label falseLabel,
+ boolean valueRequired) {
+ if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) {
+ int pc = codeStream.position;
+ if (constant.booleanValue() == true) {
+ // constant == true
+ if (valueRequired) {
+ if (falseLabel == null) {
+ // implicit falling through the FALSE case
+ if (trueLabel != null) {
+ codeStream.goto_(trueLabel);
+ }
+ }
+ }
+ } else {
+ if (valueRequired) {
+ if (falseLabel != null) {
+ // implicit falling through the TRUE case
+ if (trueLabel == null) {
+ codeStream.goto_(falseLabel);
+ }
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ generateOptimizedConditionalOr(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ valueRequired);
+ }
+
+ /**
+ * Boolean generation for ||
+ */
+ public void generateOptimizedConditionalOr(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Label trueLabel,
+ Label falseLabel,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ Constant condConst;
+ if ((condConst = left.conditionalConstant()) != NotAConstant) {
+ if (condConst.booleanValue() == true) {
+ // <something equivalent to true> || x
+ left.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ if (valueRequired) {
+ if ((bits & OnlyValueRequiredMASK) != 0) {
+ codeStream.iconst_1();
+ } else {
+ if (trueLabel != null) {
+ codeStream.goto_(trueLabel);
+ }
+ }
+ }
+ } else {
+ // <something equivalent to false> || x
+ left.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ if (rightInitStateIndex != -1) {
+ codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex);
+ }
+ if ((bits & OnlyValueRequiredMASK) != 0) {
+ right.generateCode(currentScope, codeStream, valueRequired);
+ } else {
+ right.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ valueRequired);
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ if (mergedInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ mergedInitStateIndex);
+ }
+ return;
+ }
+ if ((condConst = right.conditionalConstant()) != NotAConstant) {
+ if (condConst.booleanValue() == true) {
+ // x || <something equivalent to true>
+ left.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ if (rightInitStateIndex != -1) {
+ codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex);
+ }
+ right.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ if (valueRequired) {
+ if ((bits & OnlyValueRequiredMASK) != 0) {
+ codeStream.iconst_1();
+ } else {
+ if (trueLabel != null) {
+ codeStream.goto_(trueLabel);
+ }
+ }
+ }
+ } else {
+ // x || <something equivalent to false>
+ if ((bits & OnlyValueRequiredMASK) != 0) {
+ left.generateCode(currentScope, codeStream, valueRequired);
+ } else {
+ left.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ valueRequired);
+ }
+ if (rightInitStateIndex != -1) {
+ codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex);
+ }
+ right.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ false);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ if (mergedInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ mergedInitStateIndex);
+ }
+ return;
+ }
+ // default case
+ if (falseLabel == null) {
+ if (trueLabel != null) {
+ // implicit falling through the FALSE case
+ left.generateOptimizedBoolean(currentScope, codeStream, trueLabel, null, true);
+ right.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ null,
+ valueRequired);
+ }
+ } else {
+ // implicit falling through the TRUE case
+ if (trueLabel == null) {
+ Label internalTrueLabel = new Label(codeStream);
+ left.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ internalTrueLabel,
+ null,
+ true);
+ if (rightInitStateIndex != -1) {
+ codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex);
+ }
+ right.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ null,
+ falseLabel,
+ valueRequired);
+ internalTrueLabel.place();
+ } else {
+ // no implicit fall through TRUE/FALSE --> should never occur
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ if (mergedInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ mergedInitStateIndex);
+ }
+ }
+
+ public boolean isCompactableOperation() {
+ return false;
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ if (visitor.visit(this, scope)) {
+ left.traverse(visitor, scope);
+ right.traverse(visitor, scope);
+ }
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/OperatorExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/OperatorExpression.java
new file mode 100644
index 0000000000..788d33a997
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/OperatorExpression.java
@@ -0,0 +1,1867 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+
+public abstract class OperatorExpression
+ extends Expression
+ implements OperatorIds {
+ public static int[][] ResolveTypeTables = new int[NumberOfTables][];
+ static {
+ classInitialize();
+ }
+
+ /**
+ * OperatorExpression constructor comment.
+ */
+ public OperatorExpression() {
+ super();
+ }
+
+ public static final void classInitialize() {
+ ResolveTypeTables[AND] = get_AND();
+ ResolveTypeTables[AND_AND] = get_AND_AND();
+ ResolveTypeTables[DIVIDE] = get_DIVIDE();
+ ResolveTypeTables[EQUAL_EQUAL] = get_EQUAL_EQUAL();
+ ResolveTypeTables[GREATER] = get_GREATER();
+ ResolveTypeTables[GREATER_EQUAL] = get_GREATER_EQUAL();
+ ResolveTypeTables[LEFT_SHIFT] = get_LEFT_SHIFT();
+ ResolveTypeTables[LESS] = get_LESS();
+ ResolveTypeTables[LESS_EQUAL] = get_LESS_EQUAL();
+ ResolveTypeTables[MINUS] = get_MINUS();
+ ResolveTypeTables[MULTIPLY] = get_MULTIPLY();
+ ResolveTypeTables[OR] = get_OR();
+ ResolveTypeTables[OR_OR] = get_OR_OR();
+ ResolveTypeTables[PLUS] = get_PLUS();
+ ResolveTypeTables[REMAINDER] = get_REMAINDER();
+ ResolveTypeTables[RIGHT_SHIFT] = get_RIGHT_SHIFT();
+ ResolveTypeTables[UNSIGNED_RIGHT_SHIFT] = get_UNSIGNED_RIGHT_SHIFT();
+ ResolveTypeTables[XOR] = get_XOR();
+ }
+
+ public static final String generateTableTestCase() {
+ //return a String which is a java method allowing to test
+ //the non zero entries of all tables
+
+ /* slow code */
+
+ /*
+ org.eclipse.jdt.internal.compiler.ast.
+ OperatorExpression.generateTableTestCase();
+ */
+
+ int[] operators =
+ new int[] {
+ AND,
+ AND_AND,
+ DIVIDE,
+ GREATER,
+ GREATER_EQUAL,
+ LEFT_SHIFT,
+ LESS,
+ LESS_EQUAL,
+ MINUS,
+ MULTIPLY,
+ OR,
+ OR_OR,
+ PLUS,
+ REMAINDER,
+ RIGHT_SHIFT,
+ UNSIGNED_RIGHT_SHIFT,
+ XOR };
+
+ class Decode {
+ public final String constant(int code) {
+ switch (code) {
+ case T_boolean :
+ return "true";
+ case T_byte :
+ return "((byte) 3)";
+ case T_char :
+ return "'A'";
+ case T_double :
+ return "300.0d";
+ case T_float :
+ return "100.0f";
+ case T_int :
+ return "1";
+ case T_long :
+ return "7L";
+ case T_String :
+ return "\"hello-world\"";
+ case T_null :
+ return "null";
+ case T_short :
+ return "((short) 5)";
+ case T_Object :
+ return "null";
+ }
+ return "";
+ }
+
+ public final String type(int code) {
+ switch (code) {
+ case T_boolean :
+ return "z";
+ case T_byte :
+ return "b";
+ case T_char :
+ return "c";
+ case T_double :
+ return "d";
+ case T_float :
+ return "f";
+ case T_int :
+ return "i";
+ case T_long :
+ return "l";
+ case T_String :
+ return "str";
+ case T_null :
+ return "null";
+ case T_short :
+ return "s";
+ case T_Object :
+ return "obj";
+ }
+ return "xxx";
+ }
+
+ public final String operator(int operator) {
+ switch (operator) {
+ case EQUAL_EQUAL :
+ return "==";
+ case LESS_EQUAL :
+ return "<=";
+ case GREATER_EQUAL :
+ return ">=";
+ case LEFT_SHIFT :
+ return "<<";
+ case RIGHT_SHIFT :
+ return ">>";
+ case UNSIGNED_RIGHT_SHIFT :
+ return ">>>";
+ case OR_OR :
+ return "||";
+ case AND_AND :
+ return "&&";
+ case PLUS :
+ return "+";
+ case MINUS :
+ return "-";
+ case NOT :
+ return "!";
+ case REMAINDER :
+ return "%";
+ case XOR :
+ return "^";
+ case AND :
+ return "&";
+ case MULTIPLY :
+ return "*";
+ case OR :
+ return "|";
+ case TWIDDLE :
+ return "~";
+ case DIVIDE :
+ return "/";
+ case GREATER :
+ return ">";
+ case LESS :
+ return "<";
+ };
+ return "????";
+ }
+ }
+
+ Decode decode = new Decode();
+ String s;
+ s =
+ "\tpublic static void binaryOperationTablesTestCase(){\n"
+ + "\t\t//TC test : all binary operation (described in tables)\n"
+ + "\t\t//method automatically generated by\n"
+ + "\t\t//org.eclipse.jdt.internal.compiler.ast.OperatorExpression.generateTableTestCase();\n"
+ + "\t\tString str0 ;\t String str\t= "
+ + decode.constant(T_String)
+ + ";\n"
+ + "\t\tint i0 ;\t int i\t= "
+ + decode.constant(T_int)
+ + " ;\n"
+ + "\t\tboolean z0;\t boolean z\t= "
+ + decode.constant(T_boolean)
+ + ";\n"
+ + "\t\tchar c0; \t char c\t= "
+ + decode.constant(T_char)
+ + " ;\n"
+ + "\t\tfloat f0; \t float f\t= "
+ + decode.constant(T_float)
+ + " ;\n"
+ + "\t\tdouble d0;\t double d\t= "
+ + decode.constant(T_double)
+ + " ;\n"
+ + "\t\tbyte b0; \t byte b\t= "
+ + decode.constant(T_byte)
+ + ";\n"
+ + "\t\tshort s0; \t short s\t= "
+ + decode.constant(T_short)
+ + ";\n"
+ + "\t\tlong l0; \t long l\t= "
+ + decode.constant(T_long)
+ + " ;\n"
+ + "\t\tObject obj0; \t Object obj\t= "
+ + decode.constant(T_Object)
+ + " ;\n"
+ + "\n";
+
+ int error = 0;
+ for (int i = 0; i < operators.length; i++) {
+ int operator = operators[i];
+ for (int left = 0; left < 16; left++)
+ for (int right = 0; right < 16; right++) {
+ int result = (ResolveTypeTables[operator][(left << 4) + right]) & 0x0000F;
+ if (result != T_undefined)
+
+ //1/ First regular computation then 2/ comparaison
+ //with a compile time constant (generated by the compiler)
+ // z0 = s >= s;
+ // if ( z0 != (((short) 5) >= ((short) 5)))
+ // System.out.println(155);
+
+ {
+ s += "\t\t" + decode.type(result) + "0" + " = " + decode.type(left);
+ s += " " + decode.operator(operator) + " " + decode.type(right) + ";\n";
+ String begin = result == T_String ? "\t\tif (! " : "\t\tif ( ";
+ String test = result == T_String ? ".equals(" : " != (";
+ s += begin
+ + decode.type(result)
+ + "0"
+ + test
+ + decode.constant(left)
+ + " "
+ + decode.operator(operator)
+ + " "
+ + decode.constant(right)
+ + "))\n";
+ s += "\t\t\tSystem.out.println(" + (++error) + ");\n";
+
+ }
+ }
+ }
+
+ return s += "\n\t\tSystem.out.println(\"binary tables test : done\");}";
+ }
+
+ public static final int[] get_AND() {
+
+ //the code is an int
+ // (cast) left Op (cast) rigth --> result
+ // 0000 0000 0000 0000 0000
+ // <<16 <<12 <<8 <<4
+
+ int[] table = new int[16 * 16];
+
+ // table[(T_undefined<<4)+T_undefined] = T_undefined ;
+ // table[(T_undefined<<4)+T_byte] = T_undefined ;
+ // table[(T_undefined<<4)+T_long] = T_undefined ;
+ // table[(T_undefined<<4)+T_short] = T_undefined ;
+ // table[(T_undefined<<4)+T_void] = T_undefined ;
+ // table[(T_undefined<<4)+T_String] = T_undefined ;
+ // table[(T_undefined<<4)+T_Object] = T_undefined ;
+ // table[(T_undefined<<4)+T_double] = T_undefined ;
+ // table[(T_undefined<<4)+T_float] = T_undefined ;
+ // table[(T_undefined<<4)+T_boolean] = T_undefined ;
+ // table[(T_undefined<<4)+T_char] = T_undefined ;
+ // table[(T_undefined<<4)+T_int] = T_undefined ;
+ // table[(T_undefined<<4)+T_null] = T_undefined ;
+
+ // table[(T_byte<<4)+T_undefined] = T_undefined ;
+ table[(T_byte << 4) + T_byte] = (Byte2Int << 12) + (Byte2Int << 4) + T_int;
+ table[(T_byte << 4) + T_long] = (Byte2Long << 12) + (Long2Long << 4) + T_long;
+ table[(T_byte << 4) + T_short] = (Byte2Int << 12) + (Short2Int << 4) + T_int;
+ // table[(T_byte<<4)+T_void] = T_undefined ;
+ // table[(T_byte<<4)+T_String] = T_undefined ;
+ // table[(T_byte<<4)+T_Object] = T_undefined ;
+ // table[(T_byte<<4)+T_double] = T_undefined ;
+ // table[(T_byte<<4)+T_float] = T_undefined ;
+ // table[(T_byte<<4)+T_boolean] = T_undefined ;
+ table[(T_byte << 4) + T_char] = (Byte2Int << 12) + (Char2Int << 4) + T_int;
+ table[(T_byte << 4) + T_int] = (Byte2Int << 12) + (Int2Int << 4) + T_int;
+ // table[(T_byte<<4)+T_null] = T_undefined ;
+
+ // table[(T_long<<4)+T_undefined] = T_undefined ;
+ table[(T_long << 4) + T_byte] = (Long2Long << 12) + (Byte2Long << 4) + T_long;
+ table[(T_long << 4) + T_long] = (Long2Long << 12) + (Long2Long << 4) + T_long;
+ table[(T_long << 4) + T_short] = (Long2Long << 12) + (Short2Long << 4) + T_long;
+ ;
+ // table[(T_long<<4)+T_void] = T_undefined ;
+ // table[(T_long<<4)+T_String] = T_undefined ;
+ // table[(T_long<<4)+T_Object] = T_undefined ;
+ // table[(T_long<<4)+T_double] = T_undefined ;
+ // table[(T_long<<4)+T_float] = T_undefined ;
+ // table[(T_long<<4)+T_boolean] = T_undefined ;
+ table[(T_long << 4) + T_char] = (Long2Long << 12) + (Char2Long << 4) + T_long;
+ table[(T_long << 4) + T_int] = (Long2Long << 12) + (Int2Long << 4) + T_long;
+ // table[(T_long<<4)+T_null] = T_undefined ;
+
+ // table[(T_short<<4)+T_undefined] = T_undefined ;
+ table[(T_short << 4) + T_byte] = (Short2Int << 12) + (Byte2Int << 4) + T_int;
+ table[(T_short << 4) + T_long] = (Short2Long << 12) + (Long2Long << 4) + T_long;
+ table[(T_short << 4) + T_short] = (Short2Int << 12) + (Short2Int << 4) + T_int;
+ // table[(T_short<<4)+T_void] = T_undefined ;
+ // table[(T_short<<4)+T_String] = T_undefined ;
+ // table[(T_short<<4)+T_Object] = T_undefined ;
+ // table[(T_short<<4)+T_double] = T_undefined ;
+ // table[(T_short<<4)+T_float] = T_undefined ;
+ // table[(T_short<<4)+T_boolean] = T_undefined ;
+ table[(T_short << 4) + T_char] = (Short2Int << 12) + (Char2Int << 4) + T_int;
+ table[(T_short << 4) + T_int] = (Short2Int << 12) + (Int2Int << 4) + T_int;
+ // table[(T_short<<4)+T_null] = T_undefined ;
+
+ // table[(T_void<<4)+T_undefined] = T_undefined ;
+ // table[(T_void<<4)+T_byte] = T_undefined ;
+ // table[(T_void<<4)+T_long] = T_undefined ;
+ // table[(T_void<<4)+T_short] = T_undefined ;
+ // table[(T_void<<4)+T_void] = T_undefined ;
+ // table[(T_void<<4)+T_String] = T_undefined ;
+ // table[(T_void<<4)+T_Object] = T_undefined ;
+ // table[(T_void<<4)+T_double] = T_undefined ;
+ // table[(T_void<<4)+T_float] = T_undefined ;
+ // table[(T_void<<4)+T_boolean] = T_undefined ;
+ // table[(T_void<<4)+T_char] = T_undefined ;
+ // table[(T_void<<4)+T_int] = T_undefined ;
+ // table[(T_void<<4)+T_null] = T_undefined ;
+
+ // table[(T_String<<4)+T_undefined] = T_undefined ;
+ // table[(T_String<<4)+T_byte] = T_undefined ;
+ // table[(T_String<<4)+T_long] = T_undefined ;
+ // table[(T_String<<4)+T_short] = T_undefined ;
+ // table[(T_String<<4)+T_void] = T_undefined ;
+ // table[(T_String<<4)+T_String] = T_undefined ;
+ // table[(T_String<<4)+T_Object] = T_undefined ;
+ // table[(T_String<<4)+T_double] = T_undefined ;
+ // table[(T_String<<4)+T_float] = T_undefined ;
+ // table[(T_String<<4)+T_boolean] = T_undefined ;
+ // table[(T_String<<4)+T_char] = T_undefined ;
+ // table[(T_String<<4)+T_int] = T_undefined ;
+ // table[(T_String<<4)+T_null] = T_undefined ;
+
+ // table[(T_Object<<4)+T_undefined] = T_undefined ;
+ // table[(T_Object<<4)+T_byte] = T_undefined ;
+ // table[(T_Object<<4)+T_long] = T_undefined ;
+ // table[(T_Object<<4)+T_short] = T_undefined ;
+ // table[(T_Object<<4)+T_void] = T_undefined ;
+ // table[(T_Object<<4)+T_String] = T_undefined ;
+ // table[(T_Object<<4)+T_Object] = T_undefined ;
+ // table[(T_Object<<4)+T_double] = T_undefined ;
+ // table[(T_Object<<4)+T_float] = T_undefined ;
+ // table[(T_Object<<4)+T_boolean] = T_undefined ;
+ // table[(T_Object<<4)+T_char] = T_undefined ;
+ // table[(T_Object<<4)+T_int] = T_undefined ;
+ // table[(T_Object<<4)+T_null] = T_undefined ;
+
+ // table[(T_double<<4)+T_undefined] = T_undefined ;
+ // table[(T_double<<4)+T_byte] = T_undefined ;
+ // table[(T_double<<4)+T_long] = T_undefined ;
+ // table[(T_double<<4)+T_short] = T_undefined ;
+ // table[(T_double<<4)+T_void] = T_undefined ;
+ // table[(T_double<<4)+T_String] = T_undefined ;
+ // table[(T_double<<4)+T_Object] = T_undefined ;
+ // table[(T_double<<4)+T_double] = T_undefined ;
+ // table[(T_double<<4)+T_float] = T_undefined ;
+ // table[(T_double<<4)+T_boolean] = T_undefined ;
+ // table[(T_double<<4)+T_char] = T_undefined ;
+ // table[(T_double<<4)+T_int] = T_undefined;
+ // table[(T_double<<4)+T_null] = T_undefined ;
+
+ // table[(T_float<<4)+T_undefined] = T_undefined ;
+ // table[(T_float<<4)+T_byte] = T_undefined ;
+ // table[(T_float<<4)+T_long] = T_undefined ;
+ // table[(T_float<<4)+T_short] = T_undefined ;
+ // table[(T_float<<4)+T_void] = T_undefined ;
+ // table[(T_float<<4)+T_String] = T_undefined ;
+ // table[(T_float<<4)+T_Object] = T_undefined ;
+ // table[(T_float<<4)+T_double] = T_undefined ;
+ // table[(T_float<<4)+T_float] = T_undefined ;
+ // table[(T_float<<4)+T_boolean] = T_undefined ;
+ // table[(T_float<<4)+T_char] = T_undefined ;
+ // table[(T_float<<4)+T_int] = T_undefined ;
+ // table[(T_float<<4)+T_null] = T_undefined ;
+
+ // table[(T_boolean<<4)+T_undefined] = T_undefined ;
+ // table[(T_boolean<<4)+T_byte] = T_undefined ;
+ // table[(T_boolean<<4)+T_long] = T_undefined ;
+ // table[(T_boolean<<4)+T_short] = T_undefined ;
+ // table[(T_boolean<<4)+T_void] = T_undefined ;
+ // table[(T_boolean<<4)+T_String] = T_undefined ;
+ // table[(T_boolean<<4)+T_Object] = T_undefined ;
+ // table[(T_boolean<<4)+T_double] = T_undefined ;
+ // table[(T_boolean<<4)+T_float] = T_undefined ;
+ table[(T_boolean << 4) + T_boolean] =
+ (Boolean2Boolean << 12) + (Boolean2Boolean << 4) + T_boolean;
+ // table[(T_boolean<<4)+T_char] = T_undefined ;
+ // table[(T_boolean<<4)+T_int] = T_undefined ;
+ // table[(T_boolean<<4)+T_null] = T_undefined ;
+
+ // table[(T_char<<4)+T_undefined] = T_undefined ;
+ table[(T_char << 4) + T_byte] = (Char2Int << 12) + (Byte2Int << 4) + T_int;
+ table[(T_char << 4) + T_long] = (Char2Long << 12) + (Long2Long << 4) + T_long;
+ table[(T_char << 4) + T_short] = (Char2Int << 12) + (Short2Int << 4) + T_int;
+ // table[(T_char<<4)+T_void] = T_undefined ;
+ // table[(T_char<<4)+T_String] = T_undefined ;
+ // table[(T_char<<4)+T_Object] = T_undefined ;
+ // table[(T_char<<4)+T_double] = T_undefined ;
+ // table[(T_char<<4)+T_float] = T_undefined ;
+ // table[(T_char<<4)+T_boolean] = T_undefined ;
+ table[(T_char << 4) + T_char] = (Char2Int << 12) + (Char2Int << 4) + T_int;
+ table[(T_char << 4) + T_int] = (Char2Int << 12) + (Int2Int << 4) + T_int;
+ // table[(T_char<<4)+T_null] = T_undefined ;
+
+ // table[(T_int<<4)+T_undefined] = T_undefined ;
+ table[(T_int << 4) + T_byte] = (Int2Int << 12) + (Byte2Int << 4) + T_int;
+ table[(T_int << 4) + T_long] = (Int2Long << 12) + (Long2Long << 4) + T_long;
+ table[(T_int << 4) + T_short] = (Int2Int << 12) + (Short2Int << 4) + T_int;
+ // table[(T_int<<4)+T_void] = T_undefined ;
+ // table[(T_int<<4)+T_String] = T_undefined ;
+ // table[(T_int<<4)+T_Object] = T_undefined ;
+ // table[(T_int<<4)+T_double] = T_undefined ;
+ // table[(T_int<<4)+T_float] = T_undefined ;
+ // table[(T_int<<4)+T_boolean] = T_undefined ;
+ table[(T_int << 4) + T_char] = (Int2Int << 12) + (Char2Int << 4) + T_int;
+ table[(T_int << 4) + T_int] = (Int2Int << 12) + (Int2Int << 4) + T_int;
+ // table[(T_int<<4)+T_null] = T_undefined ;
+
+ // table[(T_null<<4)+T_undefined] = T_undefined ;
+ // table[(T_null<<4)+T_byte] = T_undefined ;
+ // table[(T_null<<4)+T_long] = T_undefined ;
+ // table[(T_null<<4)+T_short] = T_undefined ;
+ // table[(T_null<<4)+T_void] = T_undefined ;
+ // table[(T_null<<4)+T_String] = T_undefined ;
+ // table[(T_null<<4)+T_Object] = T_undefined ;
+ // table[(T_null<<4)+T_double] = T_undefined ;
+ // table[(T_null<<4)+T_float] = T_undefined ;
+ // table[(T_null<<4)+T_boolean] = T_undefined ;
+ // table[(T_null<<4)+T_char] = T_undefined ;
+ // table[(T_null<<4)+T_int] = T_undefined ;
+ // table[(T_null<<4)+T_null] = T_undefined ;
+
+ //and now.....the return.........
+
+ return table;
+ }
+
+ public static final int[] get_AND_AND() {
+
+ //the code is an int
+ // (cast) left Op (cast) rigth --> result
+ // 0000 0000 0000 0000 0000
+ // <<16 <<12 <<8 <<4
+
+ int[] table = new int[16 * 16];
+
+ // table[(T_undefined<<4)+T_undefined] = T_undefined ;
+ // table[(T_undefined<<4)+T_byte] = T_undefined ;
+ // table[(T_undefined<<4)+T_long] = T_undefined ;
+ // table[(T_undefined<<4)+T_short] = T_undefined ;
+ // table[(T_undefined<<4)+T_void] = T_undefined ;
+ // table[(T_undefined<<4)+T_String] = T_undefined ;
+ // table[(T_undefined<<4)+T_Object] = T_undefined ;
+ // table[(T_undefined<<4)+T_double] = T_undefined ;
+ // table[(T_undefined<<4)+T_float] = T_undefined ;
+ // table[(T_undefined<<4)+T_boolean] = T_undefined ;
+ // table[(T_undefined<<4)+T_char] = T_undefined ;
+ // table[(T_undefined<<4)+T_int] = T_undefined ;
+ // table[(T_undefined<<4)+T_null] = T_undefined ;
+
+ // table[(T_byte<<4)+T_undefined] = T_undefined ;
+ // table[(T_byte<<4)+T_byte] = T_undefined ;
+ // table[(T_byte<<4)+T_long] = T_undefined ;
+ // table[(T_byte<<4)+T_short] = T_undefined ;
+ // table[(T_byte<<4)+T_void] = T_undefined ;
+ // table[(T_byte<<4)+T_String] = T_undefined ;
+ // table[(T_byte<<4)+T_Object] = T_undefined ;
+ // table[(T_byte<<4)+T_double] = T_undefined ;
+ // table[(T_byte<<4)+T_float] = T_undefined ;
+ // table[(T_byte<<4)+T_boolean] = T_undefined ;
+ // table[(T_byte<<4)+T_char] = T_undefined ;
+ // table[(T_byte<<4)+T_int] = T_undefined ;
+ // table[(T_byte<<4)+T_null] = T_undefined ;
+
+ // table[(T_long<<4)+T_undefined] = T_undefined ;
+ // table[(T_long<<4)+T_byte] = T_undefined;
+ // table[(T_long<<4)+T_long] = T_undefined ;
+ // table[(T_long<<4)+T_short] = T_undefined ;
+ // table[(T_long<<4)+T_void] = T_undefined ;
+ // table[(T_long<<4)+T_String] = T_undefined ;
+ // table[(T_long<<4)+T_Object] = T_undefined ;
+ // table[(T_long<<4)+T_double] = T_undefined ;
+ // table[(T_long<<4)+T_float] = T_undefined ;
+ // table[(T_long<<4)+T_boolean] = T_undefined ;
+ // table[(T_long<<4)+T_char] = T_undefined ;
+ // table[(T_long<<4)+T_int] = T_undefined ;
+ // table[(T_long<<4)+T_null] = T_undefined ;
+
+ // table[(T_short<<4)+T_undefined] = T_undefined ;
+ // table[(T_short<<4)+T_byte] = T_undefined ;
+ // table[(T_short<<4)+T_long] = T_undefined ;
+ // table[(T_short<<4)+T_short] = T_undefined ;
+ // table[(T_short<<4)+T_void] = T_undefined ;
+ // table[(T_short<<4)+T_String] = T_undefined ;
+ // table[(T_short<<4)+T_Object] = T_undefined ;
+ // table[(T_short<<4)+T_double] = T_undefined ;
+ // table[(T_short<<4)+T_float] = T_undefined ;
+ // table[(T_short<<4)+T_boolean] = T_undefined ;
+ // table[(T_short<<4)+T_char] = T_undefined ;
+ // table[(T_short<<4)+T_int] = T_undefined ;
+ // table[(T_short<<4)+T_null] = T_undefined ;
+
+ // table[(T_void<<4)+T_undefined] = T_undefined ;
+ // table[(T_void<<4)+T_byte] = T_undefined ;
+ // table[(T_void<<4)+T_long] = T_undefined ;
+ // table[(T_void<<4)+T_short] = T_undefined ;
+ // table[(T_void<<4)+T_void] = T_undefined ;
+ // table[(T_void<<4)+T_String] = T_undefined ;
+ // table[(T_void<<4)+T_Object] = T_undefined ;
+ // table[(T_void<<4)+T_double] = T_undefined ;
+ // table[(T_void<<4)+T_float] = T_undefined ;
+ // table[(T_void<<4)+T_boolean] = T_undefined ;
+ // table[(T_void<<4)+T_char] = T_undefined ;
+ // table[(T_void<<4)+T_int] = T_undefined ;
+ // table[(T_void<<4)+T_null] = T_undefined ;
+
+ // table[(T_String<<4)+T_undefined] = T_undefined ;
+ // table[(T_String<<4)+T_byte] = T_undefined ;
+ // table[(T_String<<4)+T_long] = T_undefined ;
+ // table[(T_String<<4)+T_short] = T_undefined ;
+ // table[(T_String<<4)+T_void] = T_undefined ;
+ // table[(T_String<<4)+T_String] = T_undefined ;
+ // table[(T_String<<4)+T_Object] = T_undefined ;
+ // table[(T_String<<4)+T_double] = T_undefined ;
+ // table[(T_String<<4)+T_float] = T_undefined ;
+ // table[(T_String<<4)+T_boolean] = T_undefined ;
+ // table[(T_String<<4)+T_char] = T_undefined ;
+ // table[(T_String<<4)+T_int] = T_undefined ;
+ // table[(T_String<<4)+T_null] = T_undefined ;
+
+ // table[(T_Object<<4)+T_undefined] = T_undefined ;
+ // table[(T_Object<<4)+T_byte] = T_undefined ;
+ // table[(T_Object<<4)+T_long] = T_undefined ;
+ // table[(T_Object<<4)+T_short] = T_undefined ;
+ // table[(T_Object<<4)+T_void] = T_undefined ;
+ // table[(T_Object<<4)+T_String] = T_undefined ;
+ // table[(T_Object<<4)+T_Object] = T_undefined ;
+ // table[(T_Object<<4)+T_double] = T_undefined ;
+ // table[(T_Object<<4)+T_float] = T_undefined ;
+ // table[(T_Object<<4)+T_boolean] = T_undefined ;
+ // table[(T_Object<<4)+T_char] = T_undefined ;
+ // table[(T_Object<<4)+T_int] = T_undefined ;
+ // table[(T_Object<<4)+T_null] = T_undefined ;
+
+ // table[(T_double<<4)+T_undefined] = T_undefined ;
+ // table[(T_double<<4)+T_byte] = T_undefined ;
+ // table[(T_double<<4)+T_long] = T_undefined ;
+ // table[(T_double<<4)+T_short] = T_undefined ;
+ // table[(T_double<<4)+T_void] = T_undefined ;
+ // table[(T_double<<4)+T_String] = T_undefined ;
+ // table[(T_double<<4)+T_Object] = T_undefined ;
+ // table[(T_double<<4)+T_double] = T_undefined ;
+ // table[(T_double<<4)+T_float] = T_undefined ;
+ // table[(T_double<<4)+T_boolean] = T_undefined ;
+ // table[(T_double<<4)+T_char] = T_undefined ;
+ // table[(T_double<<4)+T_int] = T_undefined;
+ // table[(T_double<<4)+T_null] = T_undefined ;
+
+ // table[(T_float<<4)+T_undefined] = T_undefined ;
+ // table[(T_float<<4)+T_byte] = T_undefined ;
+ // table[(T_float<<4)+T_long] = T_undefined ;
+ // table[(T_float<<4)+T_short] = T_undefined ;
+ // table[(T_float<<4)+T_void] = T_undefined ;
+ // table[(T_float<<4)+T_String] = T_undefined ;
+ // table[(T_float<<4)+T_Object] = T_undefined ;
+ // table[(T_float<<4)+T_double] = T_undefined ;
+ // table[(T_float<<4)+T_float] = T_undefined ;
+ // table[(T_float<<4)+T_boolean] = T_undefined ;
+ // table[(T_float<<4)+T_char] = T_undefined ;
+ // table[(T_float<<4)+T_int] = T_undefined ;
+ // table[(T_float<<4)+T_null] = T_undefined ;
+
+ // table[(T_boolean<<4)+T_undefined] = T_undefined ;
+ // table[(T_boolean<<4)+T_byte] = T_undefined ;
+ // table[(T_boolean<<4)+T_long] = T_undefined ;
+ // table[(T_boolean<<4)+T_short] = T_undefined ;
+ // table[(T_boolean<<4)+T_void] = T_undefined ;
+ // table[(T_boolean<<4)+T_String] = T_undefined ;
+ // table[(T_boolean<<4)+T_Object] = T_undefined ;
+ // table[(T_boolean<<4)+T_double] = T_undefined ;
+ // table[(T_boolean<<4)+T_float] = T_undefined ;
+ table[(T_boolean << 4) + T_boolean] =
+ (Boolean2Boolean << 12) + (Boolean2Boolean << 4) + T_boolean;
+ // table[(T_boolean<<4)+T_char] = T_undefined ;
+ // table[(T_boolean<<4)+T_int] = T_undefined ;
+ // table[(T_boolean<<4)+T_null] = T_undefined ;
+
+ // table[(T_char<<4)+T_undefined] = T_undefined ;
+ // table[(T_char<<4)+T_byte] = T_undefined ;
+ // table[(T_char<<4)+T_long] = T_undefined;
+ // table[(T_char<<4)+T_short] = T_undefined ;
+ // table[(T_char<<4)+T_void] = T_undefined ;
+ // table[(T_char<<4)+T_String] = T_undefined ;
+ // table[(T_char<<4)+T_Object] = T_undefined ;
+ // table[(T_char<<4)+T_double] = T_undefined ;
+ // table[(T_char<<4)+T_float] = T_undefined ;
+ // table[(T_char<<4)+T_boolean] = T_undefined ;
+ // table[(T_char<<4)+T_char] = T_undefined ;
+ // table[(T_char<<4)+T_int] = T_undefined ;
+ // table[(T_char<<4)+T_null] = T_undefined ;
+
+ // table[(T_int<<4)+T_undefined] = T_undefined ;
+ // table[(T_int<<4)+T_byte] = T_undefined ;
+ // table[(T_int<<4)+T_long] = T_undefined ;
+ // table[(T_int<<4)+T_short] = T_undefined ;
+ // table[(T_int<<4)+T_void] = T_undefined ;
+ // table[(T_int<<4)+T_String] = T_undefined ;
+ // table[(T_int<<4)+T_Object] = T_undefined ;
+ // table[(T_int<<4)+T_double] = T_undefined ;
+ // table[(T_int<<4)+T_float] = T_undefined ;
+ // table[(T_int<<4)+T_boolean] = T_undefined ;
+ // table[(T_int<<4)+T_char] = T_undefined ;
+ // table[(T_int<<4)+T_int] = T_undefined ;
+ // table[(T_int<<4)+T_null] = T_undefined ;
+
+ // table[(T_null<<4)+T_undefined] = T_undefined ;
+ // table[(T_null<<4)+T_byte] = T_undefined ;
+ // table[(T_null<<4)+T_long] = T_undefined ;
+ // table[(T_null<<4)+T_short] = T_undefined ;
+ // table[(T_null<<4)+T_void] = T_undefined ;
+ // table[(T_null<<4)+T_String] = T_undefined ;
+ // table[(T_null<<4)+T_Object] = T_undefined ;
+ // table[(T_null<<4)+T_double] = T_undefined ;
+ // table[(T_null<<4)+T_float] = T_undefined ;
+ // table[(T_null<<4)+T_boolean] = T_undefined ;
+ // table[(T_null<<4)+T_char] = T_undefined ;
+ // table[(T_null<<4)+T_int] = T_undefined ;
+ // table[(T_null<<4)+T_null] = T_undefined ;
+
+ //and now.....the return.........
+
+ return table;
+ }
+
+ public static final int[] get_DIVIDE() {
+
+ //the code is an int
+ // (cast) left Op (cast) rigth --> result
+ // 0000 0000 0000 0000 0000
+ // <<16 <<12 <<8 <<4
+
+ // int[] table = new int[16*16] ;
+
+ return get_MINUS();
+
+ // return table ;
+ }
+
+ public static final int[] get_EQUAL_EQUAL() {
+
+ //the code is an int
+ // (cast) left Op (cast) rigth --> result
+ // 0000 0000 0000 0000 0000
+ // <<16 <<12 <<8 <<4
+
+ int[] table = new int[16 * 16];
+
+ // table[(T_undefined<<4)+T_undefined] = T_undefined ;
+ // table[(T_undefined<<4)+T_byte] = T_undefined ;
+ // table[(T_undefined<<4)+T_long] = T_undefined ;
+ // table[(T_undefined<<4)+T_short] = T_undefined ;
+ // table[(T_undefined<<4)+T_void] = T_undefined ;
+ // table[(T_undefined<<4)+T_String] = T_undefined ;
+ // table[(T_undefined<<4)+T_Object] = T_undefined ;
+ // table[(T_undefined<<4)+T_double] = T_undefined ;
+ // table[(T_undefined<<4)+T_float] = T_undefined ;
+ // table[(T_undefined<<4)+T_boolean] = T_undefined ;
+ // table[(T_undefined<<4)+T_char] = T_undefined ;
+ // table[(T_undefined<<4)+T_int] = T_undefined ;
+ // table[(T_undefined<<4)+T_null] = T_undefined ;
+
+ // table[(T_byte<<4)+T_undefined] = T_undefined ;
+ table[(T_byte << 4) + T_byte] = (Byte2Int << 12) + (Byte2Int << 4) + T_boolean;
+ table[(T_byte << 4) + T_long] =
+ (Byte2Long << 12) + (Long2Long << 4) + T_boolean;
+ table[(T_byte << 4) + T_short] =
+ (Byte2Int << 12) + (Short2Int << 4) + T_boolean;
+ // table[(T_byte<<4)+T_void] = T_undefined ;
+ // table[(T_byte<<4)+T_String] = T_undefined ;
+ // table[(T_byte<<4)+T_Object] = T_undefined ;
+ table[(T_byte << 4) + T_double] =
+ (Byte2Double << 12) + (Double2Double << 4) + T_boolean;
+ table[(T_byte << 4) + T_float] =
+ (Byte2Float << 12) + (Float2Float << 4) + T_boolean;
+ // table[(T_byte<<4)+T_boolean] = T_undefined ;
+ table[(T_byte << 4) + T_char] = (Byte2Int << 12) + (Char2Int << 4) + T_boolean;
+ table[(T_byte << 4) + T_int] = (Byte2Int << 12) + (Int2Int << 4) + T_boolean;
+ // table[(T_byte<<4)+T_null] = T_undefined ;
+
+ // table[(T_long<<4)+T_undefined] = T_undefined ;
+ table[(T_long << 4) + T_byte] =
+ (Long2Long << 12) + (Byte2Long << 4) + T_boolean;
+ table[(T_long << 4) + T_long] =
+ (Long2Long << 12) + (Long2Long << 4) + T_boolean;
+ table[(T_long << 4) + T_short] =
+ (Long2Long << 12) + (Short2Long << 4) + T_boolean;
+ // table[(T_long<<4)+T_void] = T_undefined ;
+ // table[(T_long<<4)+T_String] = T_undefined ;
+ // table[(T_long<<4)+T_Object] = T_undefined ;
+ table[(T_long << 4) + T_double] =
+ (Long2Double << 12) + (Double2Double << 4) + T_boolean;
+ table[(T_long << 4) + T_float] =
+ (Long2Float << 12) + (Float2Float << 4) + T_boolean;
+ // table[(T_long<<4)+T_boolean] = T_undefined ;
+ table[(T_long << 4) + T_char] =
+ (Long2Long << 12) + (Char2Long << 4) + T_boolean;
+ table[(T_long << 4) + T_int] = (Long2Long << 12) + (Int2Long << 4) + T_boolean;
+ // table[(T_long<<4)+T_null] = T_undefined ;
+
+ // table[(T_short<<4)+T_undefined] = T_undefined ;
+ table[(T_short << 4) + T_byte] =
+ (Short2Int << 12) + (Byte2Int << 4) + T_boolean;
+ table[(T_short << 4) + T_long] =
+ (Short2Long << 12) + (Long2Long << 4) + T_boolean;
+ table[(T_short << 4) + T_short] =
+ (Short2Int << 12) + (Short2Int << 4) + T_boolean;
+ // table[(T_short<<4)+T_void] = T_undefined ;
+ // table[(T_short<<4)+T_String] = T_undefined ;
+ // table[(T_short<<4)+T_Object] = T_undefined ;
+ table[(T_short << 4) + T_double] =
+ (Short2Double << 12) + (Double2Double << 4) + T_boolean;
+ table[(T_short << 4) + T_float] =
+ (Short2Float << 12) + (Float2Float << 4) + T_boolean;
+ // table[(T_short<<4)+T_boolean] = T_undefined ;
+ table[(T_short << 4) + T_char] =
+ (Short2Int << 12) + (Char2Int << 4) + T_boolean;
+ table[(T_short << 4) + T_int] = (Short2Int << 12) + (Int2Int << 4) + T_boolean;
+ // table[(T_short<<4)+T_null] = T_undefined ;
+
+ // table[(T_void<<4)+T_undefined] = T_undefined ;
+ // table[(T_void<<4)+T_byte] = T_undefined ;
+ // table[(T_void<<4)+T_long] = T_undefined ;
+ // table[(T_void<<4)+T_short] = T_undefined ;
+ // table[(T_void<<4)+T_void] = T_undefined ;
+ // table[(T_void<<4)+T_String] = T_undefined ;
+ // table[(T_void<<4)+T_Object] = T_undefined ;
+ // table[(T_void<<4)+T_double] = T_undefined ;
+ // table[(T_void<<4)+T_float] = T_undefined ;
+ // table[(T_void<<4)+T_boolean] = T_undefined ;
+ // table[(T_void<<4)+T_char] = T_undefined ;
+ // table[(T_void<<4)+T_int] = T_undefined ;
+ // table[(T_void<<4)+T_null] = T_undefined ;
+
+ // table[(T_String<<4)+T_undefined] = T_undefined ;
+ // table[(T_String<<4)+T_byte] = T_undefined ;
+ // table[(T_String<<4)+T_long] = T_undefined ;
+ // table[(T_String<<4)+T_short] = T_undefined ;
+ // table[(T_String<<4)+T_void] = T_undefined ;
+ table[(T_String << 4) + T_String] =
+ /*String2Object String2Object*/
+ (T_Object << 16)
+ + (T_String << 12)
+ + (T_Object << 8)
+ + (T_String << 4)
+ + T_boolean;
+ table[(T_String << 4) + T_Object] =
+ /*String2Object Object2Object*/
+ (T_Object << 16)
+ + (T_String << 12)
+ + (T_Object << 8)
+ + (T_Object << 4)
+ + T_boolean;
+ // table[(T_String<<4)+T_double] = T_undefined ;
+ // table[(T_String<<4)+T_float] = T_undefined ;
+ // table[(T_String<<4)+T_boolean] = T_undefined ;
+ // table[(T_String<<4)+T_char] = T_undefined ;
+ // table[(T_String<<4)+T_int] = T_undefined ;
+ table[(T_String << 4) + T_null] = /*Object2String null2Object */
+ (T_Object << 16)
+ + (T_String << 12)
+ + (T_Object << 8)
+ + (T_null << 4)
+ + T_boolean;
+
+ // table[(T_Object<<4)+T_undefined] = T_undefined ;
+ // table[(T_Object<<4)+T_byte] = T_undefined ;
+ // table[(T_Object<<4)+T_long] = T_undefined ;
+ // table[(T_Object<<4)+T_short] = T_undefined ;
+ // table[(T_Object<<4)+T_void] = T_undefined ;
+ table[(T_Object << 4) + T_String] =
+ /*Object2Object String2Object*/
+ (T_Object << 16)
+ + (T_Object << 12)
+ + (T_Object << 8)
+ + (T_String << 4)
+ + T_boolean;
+ table[(T_Object << 4) + T_Object] =
+ /*Object2Object Object2Object*/
+ (T_Object << 16)
+ + (T_Object << 12)
+ + (T_Object << 8)
+ + (T_Object << 4)
+ + T_boolean;
+ // table[(T_Object<<4)+T_double] = T_undefined ;
+ // table[(T_Object<<4)+T_float] = T_undefined ;
+ // table[(T_Object<<4)+T_boolean] = T_undefined ;
+ // table[(T_Object<<4)+T_char] = T_undefined ;
+ // table[(T_Object<<4)+T_int] = T_undefined ;
+ table[(T_Object << 4) + T_null] = /*Object2Object null2Object*/
+ (T_Object << 16)
+ + (T_Object << 12)
+ + (T_Object << 8)
+ + (T_null << 4)
+ + T_boolean;
+
+ // table[(T_double<<4)+T_undefined] = T_undefined ;
+ table[(T_double << 4) + T_byte] =
+ (Double2Double << 12) + (Byte2Double << 4) + T_boolean;
+ table[(T_double << 4) + T_long] =
+ (Double2Double << 12) + (Long2Double << 4) + T_boolean;
+ table[(T_double << 4) + T_short] =
+ (Double2Double << 12) + (Short2Double << 4) + T_boolean;
+ // table[(T_double<<4)+T_void] = T_undefined ;
+ // table[(T_double<<4)+T_String] = T_undefined ;
+ // table[(T_double<<4)+T_Object] = T_undefined ;
+ table[(T_double << 4) + T_double] =
+ (Double2Double << 12) + (Double2Double << 4) + T_boolean;
+ table[(T_double << 4) + T_float] =
+ (Double2Double << 12) + (Float2Double << 4) + T_boolean;
+ // table[(T_double<<4)+T_boolean] = T_undefined ;
+ table[(T_double << 4) + T_char] =
+ (Double2Double << 12) + (Char2Double << 4) + T_boolean;
+ table[(T_double << 4) + T_int] =
+ (Double2Double << 12) + (Int2Double << 4) + T_boolean;
+ // table[(T_double<<4)+T_null] = T_undefined ;
+
+ // table[(T_float<<4)+T_undefined] = T_undefined ;
+ table[(T_float << 4) + T_byte] =
+ (Float2Float << 12) + (Byte2Float << 4) + T_boolean;
+ table[(T_float << 4) + T_long] =
+ (Float2Float << 12) + (Long2Float << 4) + T_boolean;
+ table[(T_float << 4) + T_short] =
+ (Float2Float << 12) + (Short2Float << 4) + T_boolean;
+ // table[(T_float<<4)+T_void] = T_undefined ;
+ // table[(T_float<<4)+T_String] = T_undefined ;
+ // table[(T_float<<4)+T_Object] = T_undefined ;
+ table[(T_float << 4) + T_double] =
+ (Float2Double << 12) + (Double2Double << 4) + T_boolean;
+ table[(T_float << 4) + T_float] =
+ (Float2Float << 12) + (Float2Float << 4) + T_boolean;
+ // table[(T_float<<4)+T_boolean] = T_undefined ;
+ table[(T_float << 4) + T_char] =
+ (Float2Float << 12) + (Char2Float << 4) + T_boolean;
+ table[(T_float << 4) + T_int] =
+ (Float2Float << 12) + (Int2Float << 4) + T_boolean;
+ // table[(T_float<<4)+T_null] = T_undefined ;
+
+ // table[(T_boolean<<4)+T_undefined] = T_undefined ;
+ // table[(T_boolean<<4)+T_byte] = T_undefined ;
+ // table[(T_boolean<<4)+T_long] = T_undefined ;
+ // table[(T_boolean<<4)+T_short] = T_undefined ;
+ // table[(T_boolean<<4)+T_void] = T_undefined ;
+ // table[(T_boolean<<4)+T_String] = T_undefined ;
+ // table[(T_boolean<<4)+T_Object] = T_undefined ;
+ // table[(T_boolean<<4)+T_double] = T_undefined ;
+ // table[(T_boolean<<4)+T_float] = T_undefined ;
+ table[(T_boolean << 4) + T_boolean] =
+ (Boolean2Boolean << 12) + (Boolean2Boolean << 4) + T_boolean;
+ // table[(T_boolean<<4)+T_char] = T_undefined ;
+ // table[(T_boolean<<4)+T_int] = T_undefined ;
+ // table[(T_boolean<<4)+T_null] = T_undefined ;
+
+ // table[(T_char<<4)+T_undefined] = T_undefined ;
+ table[(T_char << 4) + T_byte] = (Char2Int << 12) + (Byte2Int << 4) + T_boolean;
+ table[(T_char << 4) + T_long] =
+ (Char2Long << 12) + (Long2Long << 4) + T_boolean;
+ table[(T_char << 4) + T_short] =
+ (Char2Int << 12) + (Short2Int << 4) + T_boolean;
+ // table[(T_char<<4)+T_void] = T_undefined ;
+ // table[(T_char<<4)+T_String] = T_undefined ;
+ // table[(T_char<<4)+T_Object] = T_undefined ;
+ table[(T_char << 4) + T_double] =
+ (Char2Double << 12) + (Double2Double << 4) + T_boolean;
+ table[(T_char << 4) + T_float] =
+ (Char2Float << 12) + (Float2Float << 4) + T_boolean;
+ // table[(T_char<<4)+T_boolean] = T_undefined ;
+ table[(T_char << 4) + T_char] = (Char2Int << 12) + (Char2Int << 4) + T_boolean;
+ table[(T_char << 4) + T_int] = (Char2Int << 12) + (Int2Int << 4) + T_boolean;
+ // table[(T_char<<4)+T_null] = T_undefined ;
+
+ // table[(T_int<<4)+T_undefined] = T_undefined ;
+ table[(T_int << 4) + T_byte] = (Int2Int << 12) + (Byte2Int << 4) + T_boolean;
+ table[(T_int << 4) + T_long] = (Int2Long << 12) + (Long2Long << 4) + T_boolean;
+ table[(T_int << 4) + T_short] = (Int2Int << 12) + (Short2Int << 4) + T_boolean;
+ // table[(T_int<<4)+T_void] = T_undefined ;
+ // table[(T_int<<4)+T_String] = T_undefined ;
+ // table[(T_int<<4)+T_Object] = T_undefined ;
+ table[(T_int << 4) + T_double] =
+ (Int2Double << 12) + (Double2Double << 4) + T_boolean;
+ table[(T_int << 4) + T_float] =
+ (Int2Float << 12) + (Float2Float << 4) + T_boolean;
+ // table[(T_int<<4)+T_boolean] = T_undefined ;
+ table[(T_int << 4) + T_char] = (Int2Int << 12) + (Char2Int << 4) + T_boolean;
+ table[(T_int << 4) + T_int] = (Int2Int << 12) + (Int2Int << 4) + T_boolean;
+ // table[(T_int<<4)+T_null] = T_undefined ;
+
+ // table[(T_null<<4)+T_undefined] = T_undefined ;
+ // table[(T_null<<4)+T_byte] = T_undefined ;
+ // table[(T_null<<4)+T_long] = T_undefined ;
+ // table[(T_null<<4)+T_short] = T_undefined ;
+ // table[(T_null<<4)+T_void] = T_undefined ;
+ table[(T_null << 4) + T_String] = /*null2Object String2Object*/
+ (T_Object << 16)
+ + (T_null << 12)
+ + (T_Object << 8)
+ + (T_String << 4)
+ + T_boolean;
+ table[(T_null << 4) + T_Object] = /*null2Object Object2Object*/
+ (T_Object << 16)
+ + (T_null << 12)
+ + (T_Object << 8)
+ + (T_Object << 4)
+ + T_boolean;
+ ;
+ // table[(T_null<<4)+T_double] = T_undefined ;
+ // table[(T_null<<4)+T_float] = T_undefined ;
+ // table[(T_null<<4)+T_boolean] = T_undefined ;
+ // table[(T_null<<4)+T_char] = T_undefined ;
+ // table[(T_null<<4)+T_int] = T_undefined ;
+ table[(T_null << 4) + T_null] = /*null2Object null2Object*/
+ (T_Object << 16) + (T_null << 12) + (T_Object << 8) + (T_null << 4) + T_boolean;
+ //and now.....the return.........
+
+ return table;
+ }
+
+ public static final int[] get_GREATER() {
+
+ //the code is an int
+ // (cast) left Op (cast) rigth --> result
+ // 0000 0000 0000 0000 0000
+ // <<16 <<12 <<8 <<4
+
+ // int[] table = new int[16*16] ;
+
+ return get_LESS();
+
+ // return table ;
+ }
+
+ public static final int[] get_GREATER_EQUAL() {
+
+ //the code is an int
+ // (cast) left Op (cast) rigth --> result
+ // 0000 0000 0000 0000 0000
+ // <<16 <<12 <<8 <<4
+
+ // int[] table = new int[16*16] ;
+
+ return get_LESS();
+
+ // return table ;
+ }
+
+ public static final int[] get_LEFT_SHIFT() {
+
+ //the code is an int
+ // (cast) left Op (cast) rigth --> result
+ // 0000 0000 0000 0000 0000
+ // <<16 <<12 <<8 <<4
+
+ int[] table = new int[16 * 16];
+
+ // table[(T_undefined<<4)+T_undefined] = T_undefined ;
+ // table[(T_undefined<<4)+T_byte] = T_undefined ;
+ // table[(T_undefined<<4)+T_long] = T_undefined ;
+ // table[(T_undefined<<4)+T_short] = T_undefined ;
+ // table[(T_undefined<<4)+T_void] = T_undefined ;
+ // table[(T_undefined<<4)+T_String] = T_undefined ;
+ // table[(T_undefined<<4)+T_Object] = T_undefined ;
+ // table[(T_undefined<<4)+T_double] = T_undefined ;
+ // table[(T_undefined<<4)+T_float] = T_undefined ;
+ // table[(T_undefined<<4)+T_boolean] = T_undefined ;
+ // table[(T_undefined<<4)+T_char] = T_undefined ;
+ // table[(T_undefined<<4)+T_int] = T_undefined ;
+ // table[(T_undefined<<4)+T_null] = T_undefined ;
+
+ // table[(T_byte<<4)+T_undefined] = T_undefined ;
+ table[(T_byte << 4) + T_byte] = (Byte2Int << 12) + (Byte2Int << 4) + T_int;
+ table[(T_byte << 4) + T_long] = (Byte2Int << 12) + (Long2Int << 4) + T_int;
+ table[(T_byte << 4) + T_short] = (Byte2Int << 12) + (Short2Int << 4) + T_int;
+ // table[(T_byte<<4)+T_void] = T_undefined ;
+ // table[(T_byte<<4)+T_String] = T_undefined ;
+ // table[(T_byte<<4)+T_Object] = T_undefined ;
+ // table[(T_byte<<4)+T_double] = T_undefined ;
+ // table[(T_byte<<4)+T_float] = T_undefined ;
+ // table[(T_byte<<4)+T_boolean] = T_undefined ;
+ table[(T_byte << 4) + T_char] = (Byte2Int << 12) + (Char2Int << 4) + T_int;
+ table[(T_byte << 4) + T_int] = (Byte2Int << 12) + (Int2Int << 4) + T_int;
+ // table[(T_byte<<4)+T_null] = T_undefined ;
+
+ // table[(T_long<<4)+T_undefined] = T_undefined ;
+ table[(T_long << 4) + T_byte] = (Long2Long << 12) + (Byte2Int << 4) + T_long;
+ table[(T_long << 4) + T_long] = (Long2Long << 12) + (Long2Int << 4) + T_long;
+ table[(T_long << 4) + T_short] = (Long2Long << 12) + (Short2Int << 4) + T_long;
+ // table[(T_long<<4)+T_void] = T_undefined ;
+ // table[(T_long<<4)+T_String] = T_undefined ;
+ // table[(T_long<<4)+T_Object] = T_undefined ;
+ // table[(T_long<<4)+T_double] = T_undefined ;
+ // table[(T_long<<4)+T_float] = T_undefined ;
+ // table[(T_long<<4)+T_boolean] = T_undefined ;
+ table[(T_long << 4) + T_char] = (Long2Long << 12) + (Char2Int << 4) + T_long;
+ table[(T_long << 4) + T_int] = (Long2Long << 12) + (Int2Int << 4) + T_long;
+ // table[(T_long<<4)+T_null] = T_undefined ;
+
+ // table[(T_short<<4)+T_undefined] = T_undefined ;
+ table[(T_short << 4) + T_byte] = (Short2Int << 12) + (Byte2Int << 4) + T_int;
+ table[(T_short << 4) + T_long] = (Short2Int << 12) + (Long2Int << 4) + T_int;
+ table[(T_short << 4) + T_short] = (Short2Int << 12) + (Short2Int << 4) + T_int;
+ // table[(T_short<<4)+T_void] = T_undefined ;
+ // table[(T_short<<4)+T_String] = T_undefined ;
+ // table[(T_short<<4)+T_Object] = T_undefined ;
+ // table[(T_short<<4)+T_double] = T_undefined ;
+ // table[(T_short<<4)+T_float] = T_undefined ;
+ // table[(T_short<<4)+T_boolean] = T_undefined ;
+ table[(T_short << 4) + T_char] = (Short2Int << 12) + (Char2Int << 4) + T_int;
+ table[(T_short << 4) + T_int] = (Short2Int << 12) + (Int2Int << 4) + T_int;
+ // table[(T_short<<4)+T_null] = T_undefined ;
+
+ // table[(T_void<<4)+T_undefined] = T_undefined ;
+ // table[(T_void<<4)+T_byte] = T_undefined ;
+ // table[(T_void<<4)+T_long] = T_undefined ;
+ // table[(T_void<<4)+T_short] = T_undefined ;
+ // table[(T_void<<4)+T_void] = T_undefined ;
+ // table[(T_void<<4)+T_String] = T_undefined ;
+ // table[(T_void<<4)+T_Object] = T_undefined ;
+ // table[(T_void<<4)+T_double] = T_undefined ;
+ // table[(T_void<<4)+T_float] = T_undefined ;
+ // table[(T_void<<4)+T_boolean] = T_undefined ;
+ // table[(T_void<<4)+T_char] = T_undefined ;
+ // table[(T_void<<4)+T_int] = T_undefined ;
+ // table[(T_void<<4)+T_null] = T_undefined ;
+
+ // table[(T_String<<4)+T_undefined] = T_undefined ;
+ // table[(T_String<<4)+T_byte] = T_undefined ;
+ // table[(T_String<<4)+T_long] = T_undefined ;
+ // table[(T_String<<4)+T_short] = T_undefined ;
+ // table[(T_String<<4)+T_void] = T_undefined ;
+ // table[(T_String<<4)+T_String] = T_undefined ;
+ // table[(T_String<<4)+T_Object] = T_undefined ;
+ // table[(T_String<<4)+T_double] = T_undefined ;
+ // table[(T_String<<4)+T_float] = T_undefined ;
+ // table[(T_String<<4)+T_boolean] = T_undefined ;
+ // table[(T_String<<4)+T_char] = T_undefined ;
+ // table[(T_String<<4)+T_int] = T_undefined ;
+ // table[(T_String<<4)+T_null] = T_undefined ;
+
+ // table[(T_Object<<4)+T_undefined] = T_undefined ;
+ // table[(T_Object<<4)+T_byte] = T_undefined ;
+ // table[(T_Object<<4)+T_long] = T_undefined ;
+ // table[(T_Object<<4)+T_short] = T_undefined ;
+ // table[(T_Object<<4)+T_void] = T_undefined ;
+ // table[(T_Object<<4)+T_String] = T_undefined ;
+ // table[(T_Object<<4)+T_Object] = T_undefined ;
+ // table[(T_Object<<4)+T_double] = T_undefined ;
+ // table[(T_Object<<4)+T_float] = T_undefined ;
+ // table[(T_Object<<4)+T_boolean] = T_undefined ;
+ // table[(T_Object<<4)+T_char] = T_undefined ;
+ // table[(T_Object<<4)+T_int] = T_undefined ;
+ // table[(T_Object<<4)+T_null] = T_undefined ;
+
+ // table[(T_double<<4)+T_undefined] = T_undefined ;
+ // table[(T_double<<4)+T_byte] = T_undefined ;
+ // table[(T_double<<4)+T_long] = T_undefined ;
+ // table[(T_double<<4)+T_short] = T_undefined ;
+ // table[(T_double<<4)+T_void] = T_undefined ;
+ // table[(T_double<<4)+T_String] = T_undefined ;
+ // table[(T_double<<4)+T_Object] = T_undefined ;
+ // table[(T_double<<4)+T_double] = T_undefined ;
+ // table[(T_double<<4)+T_float] = T_undefined ;
+ // table[(T_double<<4)+T_boolean] = T_undefined ;
+ // table[(T_double<<4)+T_char] = T_undefined ;
+ // table[(T_double<<4)+T_int] = T_undefined;
+ // table[(T_double<<4)+T_null] = T_undefined ;
+
+ // table[(T_float<<4)+T_undefined] = T_undefined ;
+ // table[(T_float<<4)+T_byte] = T_undefined ;
+ // table[(T_float<<4)+T_long] = T_undefined ;
+ // table[(T_float<<4)+T_short] = T_undefined ;
+ // table[(T_float<<4)+T_void] = T_undefined ;
+ // table[(T_float<<4)+T_String] = T_undefined ;
+ // table[(T_float<<4)+T_Object] = T_undefined ;
+ // table[(T_float<<4)+T_double] = T_undefined ;
+ // table[(T_float<<4)+T_float] = T_undefined ;
+ // table[(T_float<<4)+T_boolean] = T_undefined ;
+ // table[(T_float<<4)+T_char] = T_undefined ;
+ // table[(T_float<<4)+T_int] = T_undefined ;
+ // table[(T_float<<4)+T_null] = T_undefined ;
+
+ // table[(T_boolean<<4)+T_undefined] = T_undefined ;
+ // table[(T_boolean<<4)+T_byte] = T_undefined ;
+ // table[(T_boolean<<4)+T_long] = T_undefined ;
+ // table[(T_boolean<<4)+T_short] = T_undefined ;
+ // table[(T_boolean<<4)+T_void] = T_undefined ;
+ // table[(T_boolean<<4)+T_String] = T_undefined ;
+ // table[(T_boolean<<4)+T_Object] = T_undefined ;
+ // table[(T_boolean<<4)+T_double] = T_undefined ;
+ // table[(T_boolean<<4)+T_float] = T_undefined ;
+ // table[(T_boolean<<4)+T_boolean] = T_undefined ;
+ // table[(T_boolean<<4)+T_char] = T_undefined ;
+ // table[(T_boolean<<4)+T_int] = T_undefined ;
+ // table[(T_boolean<<4)+T_null] = T_undefined ;
+
+ // table[(T_char<<4)+T_undefined] = T_undefined ;
+ table[(T_char << 4) + T_byte] = (Char2Int << 12) + (Byte2Int << 4) + T_int;
+ table[(T_char << 4) + T_long] = (Char2Int << 12) + (Long2Int << 4) + T_int;
+ table[(T_char << 4) + T_short] = (Char2Int << 12) + (Short2Int << 4) + T_int;
+ // table[(T_char<<4)+T_void] = T_undefined ;
+ // table[(T_char<<4)+T_String] = T_undefined ;
+ // table[(T_char<<4)+T_Object] = T_undefined ;
+ // table[(T_char<<4)+T_double] = T_undefined ;
+ // table[(T_char<<4)+T_float] = T_undefined ;
+ // table[(T_char<<4)+T_boolean] = T_undefined ;
+ table[(T_char << 4) + T_char] = (Char2Int << 12) + (Char2Int << 4) + T_int;
+ table[(T_char << 4) + T_int] = (Char2Int << 12) + (Int2Int << 4) + T_int;
+ // table[(T_char<<4)+T_null] = T_undefined ;
+
+ // table[(T_int<<4)+T_undefined] = T_undefined ;
+ table[(T_int << 4) + T_byte] = (Int2Int << 12) + (Byte2Int << 4) + T_int;
+ table[(T_int << 4) + T_long] = (Int2Int << 12) + (Long2Int << 4) + T_int;
+ table[(T_int << 4) + T_short] = (Int2Int << 12) + (Short2Int << 4) + T_int;
+ // table[(T_int<<4)+T_void] = T_undefined ;
+ // table[(T_int<<4)+T_String] = T_undefined ;
+ // table[(T_int<<4)+T_Object] = T_undefined ;
+ // table[(T_int<<4)+T_double] = T_undefined ;
+ // table[(T_int<<4)+T_float] = T_undefined ;
+ // table[(T_int<<4)+T_boolean] = T_undefined ;
+ table[(T_int << 4) + T_char] = (Int2Int << 12) + (Char2Int << 4) + T_int;
+ table[(T_int << 4) + T_int] = (Int2Int << 12) + (Int2Int << 4) + T_int;
+ // table[(T_int<<4)+T_null] = T_undefined ;
+
+ // table[(T_null<<4)+T_undefined] = T_undefined ;
+ // table[(T_null<<4)+T_byte] = T_undefined ;
+ // table[(T_null<<4)+T_long] = T_undefined ;
+ // table[(T_null<<4)+T_short] = T_undefined ;
+ // table[(T_null<<4)+T_void] = T_undefined ;
+ // table[(T_null<<4)+T_String] = T_undefined ;
+ // table[(T_null<<4)+T_Object] = T_undefined ;
+ // table[(T_null<<4)+T_double] = T_undefined ;
+ // table[(T_null<<4)+T_float] = T_undefined ;
+ // table[(T_null<<4)+T_boolean] = T_undefined ;
+ // table[(T_null<<4)+T_char] = T_undefined ;
+ // table[(T_null<<4)+T_int] = T_undefined ;
+ // table[(T_null<<4)+T_null] = T_undefined ;
+
+ //and now.....the return.........
+
+ return table;
+ }
+
+ public static final int[] get_LESS() {
+
+ //the code is an int
+ // (cast) left Op (cast) rigth --> result
+ // 0000 0000 0000 0000 0000
+ // <<16 <<12 <<8 <<4
+
+ int[] table = new int[16 * 16];
+
+ // table[(T_undefined<<4)+T_undefined] = T_undefined ;
+ // table[(T_undefined<<4)+T_byte] = T_undefined ;
+ // table[(T_undefined<<4)+T_long] = T_undefined ;
+ // table[(T_undefined<<4)+T_short] = T_undefined ;
+ // table[(T_undefined<<4)+T_void] = T_undefined ;
+ // table[(T_undefined<<4)+T_String] = T_undefined ;
+ // table[(T_undefined<<4)+T_Object] = T_undefined ;
+ // table[(T_undefined<<4)+T_double] = T_undefined ;
+ // table[(T_undefined<<4)+T_float] = T_undefined ;
+ // table[(T_undefined<<4)+T_boolean] = T_undefined ;
+ // table[(T_undefined<<4)+T_char] = T_undefined ;
+ // table[(T_undefined<<4)+T_int] = T_undefined ;
+ // table[(T_undefined<<4)+T_null] = T_undefined ;
+
+ // table[(T_byte<<4)+T_undefined] = T_undefined ;
+ table[(T_byte << 4) + T_byte] = (Byte2Int << 12) + (Byte2Int << 4) + T_boolean;
+ table[(T_byte << 4) + T_long] =
+ (Byte2Long << 12) + (Long2Long << 4) + T_boolean;
+ table[(T_byte << 4) + T_short] =
+ (Byte2Int << 12) + (Short2Int << 4) + T_boolean;
+ // table[(T_byte<<4)+T_void] = T_undefined ;
+ // table[(T_byte<<4)+T_String] = T_undefined ;
+ // table[(T_byte<<4)+T_Object] = T_undefined ;
+ table[(T_byte << 4) + T_double] =
+ (Byte2Double << 12) + (Double2Double << 4) + T_boolean;
+ table[(T_byte << 4) + T_float] =
+ (Byte2Float << 12) + (Float2Float << 4) + T_boolean;
+ // table[(T_byte<<4)+T_boolean] = T_undefined ;
+ table[(T_byte << 4) + T_char] = (Byte2Int << 12) + (Char2Int << 4) + T_boolean;
+ table[(T_byte << 4) + T_int] = (Byte2Int << 12) + (Int2Int << 4) + T_boolean;
+ // table[(T_byte<<4)+T_null] = T_undefined ;
+
+ // table[(T_long<<4)+T_undefined] = T_undefined ;
+ table[(T_long << 4) + T_byte] =
+ (Long2Long << 12) + (Byte2Long << 4) + T_boolean;
+ table[(T_long << 4) + T_long] =
+ (Long2Long << 12) + (Long2Long << 4) + T_boolean;
+ table[(T_long << 4) + T_short] =
+ (Long2Long << 12) + (Short2Long << 4) + T_boolean;
+ // table[(T_long<<4)+T_void] = T_undefined ;
+ // table[(T_long<<4)+T_String] = T_undefined ;
+ // table[(T_long<<4)+T_Object] = T_undefined ;
+ table[(T_long << 4) + T_double] =
+ (Long2Double << 12) + (Double2Double << 4) + T_boolean;
+ table[(T_long << 4) + T_float] =
+ (Long2Float << 12) + (Float2Float << 4) + T_boolean;
+ // table[(T_long<<4)+T_boolean] = T_undefined ;
+ table[(T_long << 4) + T_char] =
+ (Long2Long << 12) + (Char2Long << 4) + T_boolean;
+ table[(T_long << 4) + T_int] = (Long2Long << 12) + (Int2Long << 4) + T_boolean;
+ // table[(T_long<<4)+T_null] = T_undefined ;
+
+ // table[(T_short<<4)+T_undefined] = T_undefined ;
+ table[(T_short << 4) + T_byte] =
+ (Short2Int << 12) + (Byte2Int << 4) + T_boolean;
+ table[(T_short << 4) + T_long] =
+ (Short2Long << 12) + (Long2Long << 4) + T_boolean;
+ table[(T_short << 4) + T_short] =
+ (Short2Int << 12) + (Short2Int << 4) + T_boolean;
+ // table[(T_short<<4)+T_void] = T_undefined ;
+ // table[(T_short<<4)+T_String] = T_undefined ;
+ // table[(T_short<<4)+T_Object] = T_undefined ;
+ table[(T_short << 4) + T_double] =
+ (Short2Double << 12) + (Double2Double << 4) + T_boolean;
+ table[(T_short << 4) + T_float] =
+ (Short2Float << 12) + (Float2Float << 4) + T_boolean;
+ // table[(T_short<<4)+T_boolean] = T_undefined ;
+ table[(T_short << 4) + T_char] =
+ (Short2Int << 12) + (Char2Int << 4) + T_boolean;
+ table[(T_short << 4) + T_int] = (Short2Int << 12) + (Int2Int << 4) + T_boolean;
+ // table[(T_short<<4)+T_null] = T_undefined ;
+
+ // table[(T_void<<4)+T_undefined] = T_undefined ;
+ // table[(T_void<<4)+T_byte] = T_undefined ;
+ // table[(T_void<<4)+T_long] = T_undefined ;
+ // table[(T_void<<4)+T_short] = T_undefined ;
+ // table[(T_void<<4)+T_void] = T_undefined ;
+ // table[(T_void<<4)+T_String] = T_undefined ;
+ // table[(T_void<<4)+T_Object] = T_undefined ;
+ // table[(T_void<<4)+T_double] = T_undefined ;
+ // table[(T_void<<4)+T_float] = T_undefined ;
+ // table[(T_void<<4)+T_boolean] = T_undefined ;
+ // table[(T_void<<4)+T_char] = T_undefined ;
+ // table[(T_void<<4)+T_int] = T_undefined ;
+ // table[(T_void<<4)+T_null] = T_undefined ;
+
+ // table[(T_String<<4)+T_undefined] = T_undefined ;
+ // table[(T_String<<4)+T_byte] = T_undefined ;
+ // table[(T_String<<4)+T_long] = T_undefined ;
+ // table[(T_String<<4)+T_short] = T_undefined ;
+ // table[(T_String<<4)+T_void] = T_undefined ;
+ // table[(T_String<<4)+T_String] = T_undefined ;
+ // table[(T_String<<4)+T_Object] = T_undefined ;
+ // table[(T_String<<4)+T_double] = T_undefined ;
+ // table[(T_String<<4)+T_float] = T_undefined ;
+ // table[(T_String<<4)+T_boolean] = T_undefined ;
+ // table[(T_String<<4)+T_char] = T_undefined ;
+ // table[(T_String<<4)+T_int] = T_undefined ;
+ // table[(T_String<<4)+T_null] = T_undefined ;
+
+ // table[(T_Object<<4)+T_undefined] = T_undefined ;
+ // table[(T_Object<<4)+T_byte] = T_undefined ;
+ // table[(T_Object<<4)+T_long] = T_undefined ;
+ // table[(T_Object<<4)+T_short] = T_undefined ;
+ // table[(T_Object<<4)+T_void] = T_undefined ;
+ // table[(T_Object<<4)+T_String] = T_undefined ;
+ // table[(T_Object<<4)+T_Object] = T_undefined ;
+ // table[(T_Object<<4)+T_double] = T_undefined ;
+ // table[(T_Object<<4)+T_float] = T_undefined ;
+ // table[(T_Object<<4)+T_boolean] = T_undefined ;
+ // table[(T_Object<<4)+T_char] = T_undefined ;
+ // table[(T_Object<<4)+T_int] = T_undefined ;
+ // table[(T_Object<<4)+T_null] = T_undefined ;
+
+ // table[(T_double<<4)+T_undefined] = T_undefined ;
+ table[(T_double << 4) + T_byte] =
+ (Double2Double << 12) + (Byte2Double << 4) + T_boolean;
+ table[(T_double << 4) + T_long] =
+ (Double2Double << 12) + (Long2Double << 4) + T_boolean;
+ table[(T_double << 4) + T_short] =
+ (Double2Double << 12) + (Short2Double << 4) + T_boolean;
+ // table[(T_double<<4)+T_void] = T_undefined ;
+ // table[(T_double<<4)+T_String] = T_undefined ;
+ // table[(T_double<<4)+T_Object] = T_undefined ;
+ table[(T_double << 4) + T_double] =
+ (Double2Double << 12) + (Double2Double << 4) + T_boolean;
+ table[(T_double << 4) + T_float] =
+ (Double2Double << 12) + (Float2Double << 4) + T_boolean;
+ // table[(T_double<<4)+T_boolean] = T_undefined ;
+ table[(T_double << 4) + T_char] =
+ (Double2Double << 12) + (Char2Double << 4) + T_boolean;
+ table[(T_double << 4) + T_int] =
+ (Double2Double << 12) + (Int2Double << 4) + T_boolean;
+ // table[(T_double<<4)+T_null] = T_undefined ;
+
+ // table[(T_float<<4)+T_undefined] = T_undefined ;
+ table[(T_float << 4) + T_byte] =
+ (Float2Float << 12) + (Byte2Float << 4) + T_boolean;
+ table[(T_float << 4) + T_long] =
+ (Float2Float << 12) + (Long2Float << 4) + T_boolean;
+ table[(T_float << 4) + T_short] =
+ (Float2Float << 12) + (Short2Float << 4) + T_boolean;
+ // table[(T_float<<4)+T_void] = T_undefined ;
+ // table[(T_float<<4)+T_String] = T_undefined ;
+ // table[(T_float<<4)+T_Object] = T_undefined ;
+ table[(T_float << 4) + T_double] =
+ (Float2Double << 12) + (Double2Double << 4) + T_boolean;
+ table[(T_float << 4) + T_float] =
+ (Float2Float << 12) + (Float2Float << 4) + T_boolean;
+ // table[(T_float<<4)+T_boolean] = T_undefined ;
+ table[(T_float << 4) + T_char] =
+ (Float2Float << 12) + (Char2Float << 4) + T_boolean;
+ table[(T_float << 4) + T_int] =
+ (Float2Float << 12) + (Int2Float << 4) + T_boolean;
+ // table[(T_float<<4)+T_null] = T_undefined ;
+
+ // table[(T_boolean<<4)+T_undefined] = T_undefined ;
+ // table[(T_boolean<<4)+T_byte] = T_undefined ;
+ // table[(T_boolean<<4)+T_long] = T_undefined ;
+ // table[(T_boolean<<4)+T_short] = T_undefined ;
+ // table[(T_boolean<<4)+T_void] = T_undefined ;
+ // table[(T_boolean<<4)+T_String] = T_undefined ;
+ // table[(T_boolean<<4)+T_Object] = T_undefined ;
+ // table[(T_boolean<<4)+T_double] = T_undefined ;
+ // table[(T_boolean<<4)+T_float] = T_undefined ;
+ // table[(T_boolean<<4)+T_boolean] = T_undefined ;
+ // table[(T_boolean<<4)+T_char] = T_undefined ;
+ // table[(T_boolean<<4)+T_int] = T_undefined ;
+ // table[(T_boolean<<4)+T_null] = T_undefined ;
+
+ // table[(T_char<<4)+T_undefined] = T_undefined ;
+ table[(T_char << 4) + T_byte] = (Char2Int << 12) + (Byte2Int << 4) + T_boolean;
+ table[(T_char << 4) + T_long] =
+ (Char2Long << 12) + (Long2Long << 4) + T_boolean;
+ table[(T_char << 4) + T_short] =
+ (Char2Int << 12) + (Short2Int << 4) + T_boolean;
+ // table[(T_char<<4)+T_void] = T_undefined ;
+ // table[(T_char<<4)+T_String] = T_undefined ;
+ // table[(T_char<<4)+T_Object] = T_undefined ;
+ table[(T_char << 4) + T_double] =
+ (Char2Double << 12) + (Double2Double << 4) + T_boolean;
+ table[(T_char << 4) + T_float] =
+ (Char2Float << 12) + (Float2Float << 4) + T_boolean;
+ // table[(T_char<<4)+T_boolean] = T_undefined ;
+ table[(T_char << 4) + T_char] = (Char2Int << 12) + (Char2Int << 4) + T_boolean;
+ table[(T_char << 4) + T_int] = (Char2Int << 12) + (Int2Int << 4) + T_boolean;
+ // table[(T_char<<4)+T_null] = T_undefined ;
+
+ // table[(T_int<<4)+T_undefined] = T_undefined ;
+ table[(T_int << 4) + T_byte] = (Int2Int << 12) + (Byte2Int << 4) + T_boolean;
+ table[(T_int << 4) + T_long] = (Int2Long << 12) + (Long2Long << 4) + T_boolean;
+ table[(T_int << 4) + T_short] = (Int2Int << 12) + (Short2Int << 4) + T_boolean;
+ // table[(T_int<<4)+T_void] = T_undefined ;
+ // table[(T_int<<4)+T_String] = T_undefined ;
+ // table[(T_int<<4)+T_Object] = T_undefined ;
+ table[(T_int << 4) + T_double] =
+ (Int2Double << 12) + (Double2Double << 4) + T_boolean;
+ table[(T_int << 4) + T_float] =
+ (Int2Float << 12) + (Float2Float << 4) + T_boolean;
+ // table[(T_int<<4)+T_boolean] = T_undefined ;
+ table[(T_int << 4) + T_char] = (Int2Int << 12) + (Char2Int << 4) + T_boolean;
+ table[(T_int << 4) + T_int] = (Int2Int << 12) + (Int2Int << 4) + T_boolean;
+ // table[(T_int<<4)+T_null] = T_undefined ;
+
+ // table[(T_null<<4)+T_undefined] = T_undefined ;
+ // table[(T_null<<4)+T_byte] = T_undefined ;
+ // table[(T_null<<4)+T_long] = T_undefined ;
+ // table[(T_null<<4)+T_short] = T_undefined ;
+ // table[(T_null<<4)+T_void] = T_undefined ;
+ // table[(T_null<<4)+T_String] = T_undefined ;
+ // table[(T_null<<4)+T_Object] = T_undefined ;
+ // table[(T_null<<4)+T_double] = T_undefined ;
+ // table[(T_null<<4)+T_float] = T_undefined ;
+ // table[(T_null<<4)+T_boolean] = T_undefined ;
+ // table[(T_null<<4)+T_char] = T_undefined ;
+ // table[(T_null<<4)+T_int] = T_undefined ;
+ // table[(T_null<<4)+T_null] = T_undefined ;
+
+ //and now.....the return.........
+
+ return table;
+ }
+
+ public static final int[] get_LESS_EQUAL() {
+
+ //the code is an int
+ // (cast) left Op (cast) rigth --> result
+ // 0000 0000 0000 0000 0000
+ // <<16 <<12 <<8 <<4
+
+ // int[] table = new int[16*16] ;
+
+ return get_LESS();
+
+ // return table ;
+ }
+
+ public static final int[] get_MINUS() {
+
+ //the code is an int
+ // (cast) left Op (cast) rigth --> result
+ // 0000 0000 0000 0000 0000
+ // <<16 <<12 <<8 <<4
+
+ int[] table = new int[16 * 16];
+
+ table = (int[]) get_PLUS().clone();
+
+ table[(T_String << 4) + T_byte] = T_undefined;
+ table[(T_String << 4) + T_long] = T_undefined;
+ table[(T_String << 4) + T_short] = T_undefined;
+ table[(T_String << 4) + T_void] = T_undefined;
+ table[(T_String << 4) + T_String] = T_undefined;
+ table[(T_String << 4) + T_Object] = T_undefined;
+ table[(T_String << 4) + T_double] = T_undefined;
+ table[(T_String << 4) + T_float] = T_undefined;
+ table[(T_String << 4) + T_boolean] = T_undefined;
+ table[(T_String << 4) + T_char] = T_undefined;
+ table[(T_String << 4) + T_int] = T_undefined;
+ table[(T_String << 4) + T_null] = T_undefined;
+
+ table[(T_byte << 4) + T_String] = T_undefined;
+ table[(T_long << 4) + T_String] = T_undefined;
+ table[(T_short << 4) + T_String] = T_undefined;
+ table[(T_void << 4) + T_String] = T_undefined;
+ table[(T_Object << 4) + T_String] = T_undefined;
+ table[(T_double << 4) + T_String] = T_undefined;
+ table[(T_float << 4) + T_String] = T_undefined;
+ table[(T_boolean << 4) + T_String] = T_undefined;
+ table[(T_char << 4) + T_String] = T_undefined;
+ table[(T_int << 4) + T_String] = T_undefined;
+ table[(T_null << 4) + T_String] = T_undefined;
+
+ table[(T_null << 4) + T_null] = T_undefined;
+
+ //and now.....the return.........
+
+ return table;
+ }
+
+ public static final int[] get_MULTIPLY() {
+
+ //the code is an int
+ // (cast) left Op (cast) rigth --> result
+ // 0000 0000 0000 0000 0000
+ // <<16 <<12 <<8 <<4
+
+ // int[] table = new int[16*16] ;
+
+ return get_MINUS();
+
+ // return table ;
+ }
+
+ public static final int[] get_OR() {
+
+ //the code is an int
+ // (cast) left Op (cast) rigth --> result
+ // 0000 0000 0000 0000 0000
+ // <<16 <<12 <<8 <<4
+
+ // int[] table = new int[16*16] ;
+
+ return get_AND();
+
+ // return table ;
+ }
+
+ public static final int[] get_OR_OR() {
+
+ //the code is an int
+ // (cast) left Op (cast) rigth --> result
+ // 0000 0000 0000 0000 0000
+ // <<16 <<12 <<8 <<4
+
+ // int[] table = new int[16*16] ;
+
+ return get_AND_AND();
+
+ // return table ;
+ }
+
+ public static final int[] get_PLUS() {
+
+ //the code is an int
+ // (cast) left Op (cast) rigth --> result
+ // 0000 0000 0000 0000 0000
+ // <<16 <<12 <<8 <<4
+
+ int[] table = new int[16 * 16];
+
+ // table[(T_undefined<<4)+T_undefined] = T_undefined ;
+ // table[(T_undefined<<4)+T_byte] = T_undefined ;
+ // table[(T_undefined<<4)+T_long] = T_undefined ;
+ // table[(T_undefined<<4)+T_short] = T_undefined ;
+ // table[(T_undefined<<4)+T_void] = T_undefined ;
+ // table[(T_undefined<<4)+T_String] = T_undefined ;
+ // table[(T_undefined<<4)+T_Object] = T_undefined ;
+ // table[(T_undefined<<4)+T_double] = T_undefined ;
+ // table[(T_undefined<<4)+T_float] = T_undefined ;
+ // table[(T_undefined<<4)+T_boolean] = T_undefined ;
+ // table[(T_undefined<<4)+T_char] = T_undefined ;
+ // table[(T_undefined<<4)+T_int] = T_undefined ;
+ // table[(T_undefined<<4)+T_null] = T_undefined ;
+
+ // table[(T_byte<<4)+T_undefined] = T_undefined ;
+ table[(T_byte << 4) + T_byte] = (Byte2Int << 12) + (Byte2Int << 4) + T_int;
+ table[(T_byte << 4) + T_long] = (Byte2Long << 12) + (Long2Long << 4) + T_long;
+ table[(T_byte << 4) + T_short] = (Byte2Int << 12) + (Short2Int << 4) + T_int;
+ // table[(T_byte<<4)+T_void] = T_undefined ;
+ table[(T_byte << 4) + T_String] =
+ (Byte2Byte << 12) + (String2String << 4) + T_String;
+ // table[(T_byte<<4)+T_Object] = T_undefined ;
+ table[(T_byte << 4) + T_double] =
+ (Byte2Double << 12) + (Double2Double << 4) + T_double;
+ table[(T_byte << 4) + T_float] =
+ (Byte2Float << 12) + (Float2Float << 4) + T_float;
+ // table[(T_byte<<4)+T_boolean] = T_undefined ;
+ table[(T_byte << 4) + T_char] = (Byte2Int << 12) + (Char2Int << 4) + T_int;
+ table[(T_byte << 4) + T_int] = (Byte2Int << 12) + (Int2Int << 4) + T_int;
+ // table[(T_byte<<4)+T_null] = T_undefined ;
+
+ // table[(T_long<<4)+T_undefined] = T_undefined ;
+ table[(T_long << 4) + T_byte] = (Long2Long << 12) + (Byte2Long << 4) + T_long;
+ table[(T_long << 4) + T_long] = (Long2Long << 12) + (Long2Long << 4) + T_long;
+ table[(T_long << 4) + T_short] = (Long2Long << 12) + (Short2Long << 4) + T_long;
+ // table[(T_long<<4)+T_void] = T_undefined ;
+ table[(T_long << 4) + T_String] =
+ (Long2Long << 12) + (String2String << 4) + T_String;
+ // table[(T_long<<4)+T_Object] = T_undefined ;
+ table[(T_long << 4) + T_double] =
+ (Long2Double << 12) + (Double2Double << 4) + T_double;
+ table[(T_long << 4) + T_float] =
+ (Long2Float << 12) + (Float2Float << 4) + T_float;
+ // table[(T_long<<4)+T_boolean] = T_undefined ;
+ table[(T_long << 4) + T_char] = (Long2Long << 12) + (Char2Long << 4) + T_long;
+ table[(T_long << 4) + T_int] = (Long2Long << 12) + (Int2Long << 4) + T_long;
+ ;
+ // table[(T_long<<4)+T_null] = T_undefined ;
+
+ // table[(T_short<<4)+T_undefined] = T_undefined ;
+ table[(T_short << 4) + T_byte] = (Short2Int << 12) + (Byte2Int << 4) + T_int;
+ table[(T_short << 4) + T_long] = (Short2Long << 12) + (Long2Long << 4) + T_long;
+ table[(T_short << 4) + T_short] = (Short2Int << 12) + (Short2Int << 4) + T_int;
+ // table[(T_short<<4)+T_void] = T_undefined ;
+ table[(T_short << 4) + T_String] =
+ (Short2Short << 12) + (String2String << 4) + T_String;
+ // table[(T_short<<4)+T_Object] = T_undefined ;
+ table[(T_short << 4) + T_double] =
+ (Short2Double << 12) + (Double2Double << 4) + T_double;
+ table[(T_short << 4) + T_float] =
+ (Short2Float << 12) + (Float2Float << 4) + T_float;
+ // table[(T_short<<4)+T_boolean] = T_undefined ;
+ table[(T_short << 4) + T_char] = (Short2Int << 12) + (Char2Int << 4) + T_int;
+ table[(T_short << 4) + T_int] = (Short2Int << 12) + (Int2Int << 4) + T_int;
+ // table[(T_short<<4)+T_null] = T_undefined ;
+
+ // table[(T_void<<4)+T_undefined] = T_undefined ;
+ // table[(T_void<<4)+T_byte] = T_undefined ;
+ // table[(T_void<<4)+T_long] = T_undefined ;
+ // table[(T_void<<4)+T_short] = T_undefined ;
+ // table[(T_void<<4)+T_void] = T_undefined ;
+ // table[(T_void<<4)+T_String] = T_undefined ;
+ // table[(T_void<<4)+T_Object] = T_undefined ;
+ // table[(T_void<<4)+T_double] = T_undefined ;
+ // table[(T_void<<4)+T_float] = T_undefined ;
+ // table[(T_void<<4)+T_boolean] = T_undefined ;
+ // table[(T_void<<4)+T_char] = T_undefined ;
+ // table[(T_void<<4)+T_int] = T_undefined ;
+ // table[(T_void<<4)+T_null] = T_undefined ;
+
+ // table[(T_String<<4)+T_undefined] = T_undefined ;
+ table[(T_String << 4) + T_byte] =
+ (String2String << 12) + (Byte2Byte << 4) + T_String;
+ table[(T_String << 4) + T_long] =
+ (String2String << 12) + (Long2Long << 4) + T_String;
+ table[(T_String << 4) + T_short] =
+ (String2String << 12) + (Short2Short << 4) + T_String;
+ // table[(T_String<<4)+T_void] = T_undefined ;
+ table[(T_String << 4) + T_String] =
+ (String2String << 12) + (String2String << 4) + T_String;
+ table[(T_String << 4) + T_Object] =
+ (String2String << 12) + (T_Object << 8) + (T_Object << 4) + T_String;
+ table[(T_String << 4) + T_double] =
+ (String2String << 12) + (Double2Double << 4) + T_String;
+ table[(T_String << 4) + T_float] =
+ (String2String << 12) + (Float2Float << 4) + T_String;
+ table[(T_String << 4) + T_boolean] =
+ (String2String << 12) + (Boolean2Boolean << 4) + T_String;
+ table[(T_String << 4) + T_char] =
+ (String2String << 12) + (Char2Char << 4) + T_String;
+ table[(T_String << 4) + T_int] =
+ (String2String << 12) + (Int2Int << 4) + T_String;
+ table[(T_String << 4) + T_null] =
+ (String2String << 12) + (T_null << 8) + (T_null << 4) + T_String;
+
+ // table[(T_Object<<4)+T_undefined] = T_undefined ;
+ // table[(T_Object<<4)+T_byte] = T_undefined ;
+ // table[(T_Object<<4)+T_long] = T_undefined ;
+ // table[(T_Object<<4)+T_short] = T_undefined ;
+ // table[(T_Object<<4)+T_void] = T_undefined ;
+ table[(T_Object << 4) + T_String] =
+ (T_Object << 16) + (T_Object << 12) + (String2String << 4) + T_String;
+ // table[(T_Object<<4)+T_Object] = T_undefined ;
+ // table[(T_Object<<4)+T_double] = T_undefined ;
+ // table[(T_Object<<4)+T_float] = T_undefined ;
+ // table[(T_Object<<4)+T_boolean] = T_undefined ;
+ // table[(T_Object<<4)+T_char] = T_undefined ;
+ // table[(T_Object<<4)+T_int] = T_undefined ;
+ // table[(T_Object<<4)+T_null] = T_undefined ;
+
+ // table[(T_double<<4)+T_undefined] = T_undefined ;
+ table[(T_double << 4) + T_byte] =
+ (Double2Double << 12) + (Byte2Double << 4) + T_double;
+ table[(T_double << 4) + T_long] =
+ (Double2Double << 12) + (Long2Double << 4) + T_double;
+ table[(T_double << 4) + T_short] =
+ (Double2Double << 12) + (Short2Double << 4) + T_double;
+ ;
+ // table[(T_double<<4)+T_void] = T_undefined ;
+ table[(T_double << 4) + T_String] =
+ (Double2Double << 12) + (String2String << 4) + T_String;
+ // table[(T_double<<4)+T_Object] = T_undefined ;
+ table[(T_double << 4) + T_double] =
+ (Double2Double << 12) + (Double2Double << 4) + T_double;
+ table[(T_double << 4) + T_float] =
+ (Double2Double << 12) + (Float2Double << 4) + T_double;
+ ;
+ // table[(T_double<<4)+T_boolean] = T_undefined ;
+ table[(T_double << 4) + T_char] =
+ (Double2Double << 12) + (Char2Double << 4) + T_double;
+ ;
+ table[(T_double << 4) + T_int] =
+ (Double2Double << 12) + (Int2Double << 4) + T_double;
+ ;
+ // table[(T_double<<4)+T_null] = T_undefined ;
+
+ // table[(T_float<<4)+T_undefined] = T_undefined ;
+ table[(T_float << 4) + T_byte] =
+ (Float2Float << 12) + (Byte2Float << 4) + T_float;
+ table[(T_float << 4) + T_long] =
+ (Float2Float << 12) + (Long2Float << 4) + T_float;
+ table[(T_float << 4) + T_short] =
+ (Float2Float << 12) + (Short2Float << 4) + T_float;
+ // table[(T_float<<4)+T_void] = T_undefined ;
+ table[(T_float << 4) + T_String] =
+ (Float2Float << 12) + (String2String << 4) + T_String;
+ // table[(T_float<<4)+T_Object] = T_undefined ;
+ table[(T_float << 4) + T_double] =
+ (Float2Double << 12) + (Double2Double << 4) + T_double;
+ table[(T_float << 4) + T_float] =
+ (Float2Float << 12) + (Float2Float << 4) + T_float;
+ // table[(T_float<<4)+T_boolean] = T_undefined ;
+ table[(T_float << 4) + T_char] =
+ (Float2Float << 12) + (Char2Float << 4) + T_float;
+ table[(T_float << 4) + T_int] =
+ (Float2Float << 12) + (Int2Float << 4) + T_float;
+ // table[(T_float<<4)+T_null] = T_undefined ;
+
+ // table[(T_boolean<<4)+T_undefined] = T_undefined ;
+ // table[(T_boolean<<4)+T_byte] = T_undefined ;
+ // table[(T_boolean<<4)+T_long] = T_undefined ;
+ // table[(T_boolean<<4)+T_short] = T_undefined ;
+ // table[(T_boolean<<4)+T_void] = T_undefined ;
+ table[(T_boolean << 4) + T_String] =
+ (Boolean2Boolean << 12) + (String2String << 4) + T_String;
+ // table[(T_boolean<<4)+T_Object] = T_undefined ;
+ // table[(T_boolean<<4)+T_double] = T_undefined ;
+ // table[(T_boolean<<4)+T_float] = T_undefined ;
+ // table[(T_boolean<<4)+T_boolean] = T_undefined ;
+ // table[(T_boolean<<4)+T_char] = T_undefined ;
+ // table[(T_boolean<<4)+T_int] = T_undefined ;
+ // table[(T_boolean<<4)+T_null] = T_undefined ;
+
+ // table[(T_char<<4)+T_undefined] = T_undefined ;
+ table[(T_char << 4) + T_byte] = (Char2Int << 12) + (Byte2Int << 4) + T_int;
+ table[(T_char << 4) + T_long] = (Char2Long << 12) + (Long2Long << 4) + T_long;
+ table[(T_char << 4) + T_short] = (Char2Int << 12) + (Short2Int << 4) + T_int;
+ // table[(T_char<<4)+T_void] = T_undefined ;
+ table[(T_char << 4) + T_String] =
+ (Char2Char << 12) + (String2String << 4) + T_String;
+ // table[(T_char<<4)+T_Object] = T_undefined ;
+ table[(T_char << 4) + T_double] =
+ (Char2Double << 12) + (Double2Double << 4) + T_double;
+ table[(T_char << 4) + T_float] =
+ (Char2Float << 12) + (Float2Float << 4) + T_float;
+ // table[(T_char<<4)+T_boolean] = T_undefined ;
+ table[(T_char << 4) + T_char] = (Char2Int << 12) + (Char2Int << 4) + T_int;
+ ;
+ table[(T_char << 4) + T_int] = (Char2Int << 12) + (Int2Int << 4) + T_int;
+ // table[(T_char<<4)+T_null] = T_undefined ;
+
+ // table[(T_int<<4)+T_undefined] = T_undefined ;
+ table[(T_int << 4) + T_byte] = (Int2Int << 12) + (Byte2Int << 4) + T_int;
+ table[(T_int << 4) + T_long] = (Int2Long << 12) + (Long2Long << 4) + T_long;
+ table[(T_int << 4) + T_short] = (Int2Int << 12) + (Short2Int << 4) + T_int;
+ // table[(T_int<<4)+T_void] = T_undefined ;
+ table[(T_int << 4) + T_String] =
+ (Int2Int << 12) + (String2String << 4) + T_String;
+ // table[(T_int<<4)+T_Object] = T_undefined ;
+ table[(T_int << 4) + T_double] =
+ (Int2Double << 12) + (Double2Double << 4) + T_double;
+ table[(T_int << 4) + T_float] =
+ (Int2Float << 12) + (Float2Float << 4) + T_float;
+ // table[(T_int<<4)+T_boolean] = T_undefined ;
+ table[(T_int << 4) + T_char] = (Int2Int << 12) + (Char2Int << 4) + T_int;
+ table[(T_int << 4) + T_int] = (Int2Int << 12) + (Int2Int << 4) + T_int;
+ // table[(T_int<<4)+T_null] = T_undefined ;
+
+ // table[(T_null<<4)+T_undefined] = T_undefined ;
+ // table[(T_null<<4)+T_byte] = T_undefined ;
+ // table[(T_null<<4)+T_long] = T_undefined ;
+ // table[(T_null<<4)+T_short] = T_undefined ;
+ // table[(T_null<<4)+T_void] = T_undefined ;
+ table[(T_null << 4) + T_String] =
+ (T_null << 16) + (T_null << 12) + (String2String << 4) + T_String;
+ // table[(T_null<<4)+T_Object] = T_undefined ;
+ // table[(T_null<<4)+T_double] = T_undefined ;
+ // table[(T_null<<4)+T_float] = T_undefined ;
+ // table[(T_null<<4)+T_boolean] = T_undefined ;
+ // table[(T_null<<4)+T_char] = T_undefined ;
+ // table[(T_null<<4)+T_int] = T_undefined ;
+ // table[(T_null<<4)+T_null] = (Null2String<<12)+(Null2String<<4)+T_String ;;
+
+ //and now.....the return.........
+
+ return table;
+ }
+
+ public static final int[] get_REMAINDER() {
+
+ //the code is an int
+ // (cast) left Op (cast) rigth --> result
+ // 0000 0000 0000 0000 0000
+ // <<16 <<12 <<8 <<4
+
+ // int[] table = new int[16*16] ;
+
+ return get_MINUS();
+
+ // return table ;
+ }
+
+ public static final int[] get_RIGHT_SHIFT() {
+
+ //the code is an int
+ // (cast) left Op (cast) rigth --> result
+ // 0000 0000 0000 0000 0000
+ // <<16 <<12 <<8 <<4
+
+ // int[] table = new int[16*16] ;
+
+ return get_LEFT_SHIFT();
+
+ // return table ;
+ }
+
+ public static final int[] get_UNSIGNED_RIGHT_SHIFT() {
+
+ //the code is an int
+ // (cast) left Op (cast) rigth --> result
+ // 0000 0000 0000 0000 0000
+ // <<16 <<12 <<8 <<4
+
+ // int[] table = new int[16*16] ;
+
+ return get_LEFT_SHIFT();
+
+ // return table ;
+ }
+
+ public static final int[] get_XOR() {
+
+ //the code is an int
+ // (cast) left Op (cast) rigth --> result
+ // 0000 0000 0000 0000 0000
+ // <<16 <<12 <<8 <<4
+
+ // int[] table = new int[16*16] ;
+
+ return get_AND();
+
+ // return table ;
+ }
+
+ public String operatorToString() {
+ switch ((bits & OperatorMASK) >> OperatorSHIFT) {
+ case EQUAL_EQUAL :
+ return "==";
+ case LESS_EQUAL :
+ return "<=";
+ case GREATER_EQUAL :
+ return ">=";
+ case NOT_EQUAL :
+ return "!=";
+ case LEFT_SHIFT :
+ return "<<";
+ case RIGHT_SHIFT :
+ return ">>";
+ case UNSIGNED_RIGHT_SHIFT :
+ return ">>>";
+ case OR_OR :
+ return "||";
+ case AND_AND :
+ return "&&";
+ case PLUS :
+ return "+";
+ case MINUS :
+ return "-";
+ case NOT :
+ return "!";
+ case REMAINDER :
+ return "%";
+ case XOR :
+ return "^";
+ case AND :
+ return "&";
+ case MULTIPLY :
+ return "*";
+ case OR :
+ return "|";
+ case TWIDDLE :
+ return "~";
+ case DIVIDE :
+ return "/";
+ case GREATER :
+ return ">";
+ case LESS :
+ return "<";
+ case QUESTIONCOLON :
+ return "?:";
+ case EQUAL :
+ return "=";
+ };
+ return "unknown operator";
+ }
+
+ public String toStringExpression() {
+ /* slow code*/
+
+ //subclass redefine toStringExpressionNoParenthesis()
+
+ return "(" + toStringExpressionNoParenthesis() + ")";
+ }
+
+ public String toStringExpressionNoParenthesis() {
+
+ return "...houps...";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/OperatorIds.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/OperatorIds.java
new file mode 100644
index 0000000000..3687897f6b
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/OperatorIds.java
@@ -0,0 +1,33 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+public interface OperatorIds {
+ public static final int AND_AND = 0;
+ public static final int OR_OR = 1;
+ public static final int AND = 2;
+ public static final int OR = 3;
+ public static final int LESS = 4;
+ public static final int LESS_EQUAL = 5;
+ public static final int GREATER = 6;
+ public static final int GREATER_EQUAL = 7;
+ public static final int XOR = 8;
+ public static final int DIVIDE = 9;
+ public static final int LEFT_SHIFT = 10;
+ public static final int NOT = 11;
+ public static final int TWIDDLE = 12;
+ public static final int MINUS = 13;
+ public static final int PLUS = 14;
+ public static final int MULTIPLY = 15;
+ public static final int REMAINDER = 16;
+ public static final int RIGHT_SHIFT = 17;
+ public static final int EQUAL_EQUAL = 18;
+ public static final int UNSIGNED_RIGHT_SHIFT = 19;
+ public static final int NumberOfTables = 20;
+
+ public static final int QUESTIONCOLON = 23;
+
+ public static final int NOT_EQUAL = 29;
+ public static final int EQUAL = 30;
+ public static final int INSTANCEOF = 31;
+ public static final int PLUS_PLUS = 32;
+ public static final int MINUS_MINUS = 33;
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/PostfixExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/PostfixExpression.java
new file mode 100644
index 0000000000..80930764d7
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/PostfixExpression.java
@@ -0,0 +1,71 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class PostfixExpression extends CompoundAssignment {
+
+ public PostfixExpression(Expression l, Expression e, int op, int pos) {
+ super(l, e, op);
+ sourceStart = l.sourceStart;
+ sourceEnd = pos;
+ }
+
+ /**
+ * Code generation for PostfixExpression
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param valueRequired boolean
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+
+ // various scenarii are possible, setting an array reference,
+ // a field reference, a blank final field reference, a field of an enclosing instance or
+ // just a local variable.
+
+ int pc = codeStream.position;
+ lhs.generatePostIncrement(currentScope, codeStream, this, valueRequired);
+ if (valueRequired) {
+ codeStream.generateImplicitConversion(implicitConversion);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public String operatorToString() {
+ switch (operator) {
+ case PLUS :
+ return "++";
+ case MINUS :
+ return "--";
+ }
+ return "unknown operator";
+ }
+
+ public boolean restrainUsageToNumericTypes() {
+ return true;
+ }
+
+ public String toStringExpressionNoParenthesis() {
+ /* slow code*/
+
+ return lhs.toStringExpression() + " " + operatorToString();
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ if (visitor.visit(this, scope)) {
+ lhs.traverse(visitor, scope);
+ }
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/PrefixExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/PrefixExpression.java
new file mode 100644
index 0000000000..ca96caa979
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/PrefixExpression.java
@@ -0,0 +1,52 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class PrefixExpression extends CompoundAssignment {
+ /**
+ * PrefixExpression constructor comment.
+ * @param l org.eclipse.jdt.internal.compiler.ast.Expression
+ * @param r org.eclipse.jdt.internal.compiler.ast.Expression
+ * @param op int
+ */
+ public PrefixExpression(Expression l, Expression e, int op, int pos) {
+ super(l, e, op);
+ sourceStart = pos;
+ sourceEnd = l.sourceEnd;
+ }
+
+ public String operatorToString() {
+ switch (operator) {
+ case PLUS :
+ return "++";
+ case MINUS :
+ return "--";
+ }
+ return "unknown operator";
+ }
+
+ public boolean restrainUsageToNumericTypes() {
+ return true;
+ }
+
+ public String toStringExpressionNoParenthesis() {
+ /* slow code */
+
+ return operatorToString() + " " + lhs.toStringExpression();
+
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ if (visitor.visit(this, scope)) {
+ lhs.traverse(visitor, scope);
+ }
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java
new file mode 100644
index 0000000000..abbc8b2833
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java
@@ -0,0 +1,325 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class QualifiedAllocationExpression extends AllocationExpression {
+ //qualification may be on both side
+ public Expression enclosingInstance;
+ public AnonymousLocalTypeDeclaration anonymousType;
+
+ public QualifiedAllocationExpression() {
+
+ }
+
+ public QualifiedAllocationExpression(AnonymousLocalTypeDeclaration anonymous) {
+ anonymousType = anonymous;
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+
+ // variation on allocation, where can be specified an enclosing instance and an anonymous type
+
+ // analyse the enclosing instance
+ if (enclosingInstance != null) {
+ flowInfo = enclosingInstance.analyseCode(currentScope, flowContext, flowInfo);
+ }
+ // process arguments
+ if (arguments != null) {
+ for (int i = 0, count = arguments.length; i < count; i++) {
+ flowInfo = arguments[i].analyseCode(currentScope, flowContext, flowInfo);
+ }
+ }
+ // record some dependency information for exception types
+ int count;
+ ReferenceBinding[] thrownExceptions;
+ if ((count = (thrownExceptions = binding.thrownExceptions).length) != 0) {
+ // check exception handling
+ flowContext.checkExceptionHandlers(
+ thrownExceptions,
+ this,
+ flowInfo,
+ currentScope);
+ }
+
+ // analyse the anonymous nested type
+ if (anonymousType != null) {
+ flowInfo = anonymousType.analyseCode(currentScope, flowContext, flowInfo);
+ }
+ manageEnclosingInstanceAccessIfNecessary(currentScope);
+ manageSyntheticAccessIfNecessary(currentScope);
+ return flowInfo;
+ }
+
+ public Expression enclosingInstance() {
+ return enclosingInstance;
+ }
+
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ ReferenceBinding allocatedType = binding.declaringClass;
+ if (allocatedType.isLocalType()) {
+ LocalTypeBinding localType = (LocalTypeBinding) allocatedType;
+ localType.constantPoolName(
+ codeStream.classFile.outerMostEnclosingClassFile().computeConstantPoolName(
+ localType));
+ }
+ if (syntheticAccessor == null) {
+ codeStream.new_(allocatedType);
+ if (valueRequired) {
+ codeStream.dup();
+ }
+ // better highlight for allocation: display the type individually
+ codeStream.recordPositionsFrom(pc, type);
+ }
+ // handling innerclass instance allocation
+ if (allocatedType.isNestedType()) {
+ // make sure its name is computed before arguments, since may be necessary for argument emulation
+ codeStream.generateSyntheticArgumentValues(
+ currentScope,
+ allocatedType,
+ enclosingInstance(),
+ this);
+ }
+ // generate the arguments for constructor
+ if (arguments != null) {
+ for (int i = 0, count = arguments.length; i < count; i++) {
+ arguments[i].generateCode(currentScope, codeStream, true);
+ }
+ }
+ // invoke constructor
+ if (syntheticAccessor == null) {
+ codeStream.invokespecial(binding);
+ } else {
+ codeStream.invokestatic(syntheticAccessor);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ if (anonymousType != null) {
+ anonymousType.generateCode(currentScope, codeStream);
+ }
+ }
+
+ public boolean isSuperAccess() {
+ // necessary to lookup super constructor of anonymous type
+ return anonymousType != null;
+ }
+
+ /* Inner emulation consists in either recording a dependency
+ * link only, or performing one level of propagation.
+ *
+ * Dependency mechanism is used whenever dealing with source target
+ * types, since by the time we reach them, we might not yet know their
+ * exact need.
+ */
+ public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
+ ReferenceBinding invocationType, allocatedType;
+
+ // perform some emulation work in case there is some and we are inside a local type only
+ if ((allocatedType = binding.declaringClass).isNestedType()
+ && currentScope.enclosingSourceType().isLocalType()) {
+
+ if (allocatedType.isLocalType()) {
+ ((LocalTypeBinding) allocatedType).addInnerEmulationDependent(
+ currentScope,
+ enclosingInstance != null,
+ false);
+ // request cascade of accesses
+ } else {
+ // locally propagate, since we already now the desired shape for sure
+ currentScope.propagateInnerEmulation(
+ allocatedType,
+ enclosingInstance != null,
+ false);
+ // request cascade of accesses
+ }
+ }
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ if (anonymousType == null && enclosingInstance == null)
+ return super.resolveType(scope);
+ // added for code assist... is not possible with 'normal' code
+
+ // Propagate the type checking to the arguments, and checks if the constructor is defined.
+
+ // ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
+ // ClassInstanceCreationExpression ::= Name '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
+ // ==> by construction, when there is an enclosing instance the typename may NOT be qualified
+ // ==> therefore by construction the type is always a SingleTypeReferenceType instead of being either
+ // sometime a SingleTypeReference and sometime a QualifedTypeReference
+
+ constant = NotAConstant;
+ TypeBinding enclosingInstTb = null;
+ TypeBinding recType;
+ if (anonymousType == null) {
+ //----------------no anonymous class------------------------
+ if ((enclosingInstTb = enclosingInstance.resolveType(scope)) == null)
+ return null;
+ if (enclosingInstTb.isBaseType() | enclosingInstTb.isArrayType()) {
+ scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance(
+ enclosingInstTb,
+ enclosingInstance);
+ return null;
+ }
+ recType =
+ ((SingleTypeReference) type).resolveTypeEnclosing(
+ scope,
+ (ReferenceBinding) enclosingInstTb);
+ // will check for null after args are resolved
+ TypeBinding[] argumentTypes = NoParameters;
+ if (arguments != null) {
+ boolean argHasError = false;
+ int length = arguments.length;
+ argumentTypes = new TypeBinding[length];
+ for (int i = 0; i < length; i++)
+ if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null)
+ argHasError = true;
+ if (argHasError)
+ return null;
+ }
+ if (recType == null)
+ return null;
+ if (!recType.canBeInstantiated()) {
+ scope.problemReporter().cannotInstantiate(type, recType);
+ return null;
+ }
+ if ((binding =
+ scope.getConstructor((ReferenceBinding) recType, argumentTypes, this))
+ .isValidBinding()) {
+ if (isMethodUseDeprecated(binding, scope))
+ scope.problemReporter().deprecatedMethod(binding, this);
+
+ if (arguments != null)
+ for (int i = 0; i < arguments.length; i++)
+ arguments[i].implicitWidening(binding.parameters[i], argumentTypes[i]);
+ } else {
+ if (binding.declaringClass == null)
+ binding.declaringClass = (ReferenceBinding) recType;
+ scope.problemReporter().invalidConstructor(this, binding);
+ return null;
+ }
+
+ // The enclosing instance must be compatible with the innermost enclosing type
+ ReferenceBinding expectedType = binding.declaringClass.enclosingType();
+ if (scope.areTypesCompatible(enclosingInstTb, expectedType))
+ return recType;
+ scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
+ enclosingInstance,
+ enclosingInstTb,
+ expectedType);
+ return null;
+ }
+
+ //--------------there is an anonymous type declaration-----------------
+ if (enclosingInstance != null) {
+ if ((enclosingInstTb = enclosingInstance.resolveType(scope)) == null)
+ return null;
+ if (enclosingInstTb.isBaseType() | enclosingInstTb.isArrayType()) {
+ scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance(
+ enclosingInstTb,
+ enclosingInstance);
+ return null;
+ }
+ }
+ // due to syntax-construction, recType is a ReferenceBinding
+ recType =
+ (enclosingInstance == null)
+ ? type.resolveType(scope)
+ : ((SingleTypeReference) type).resolveTypeEnclosing(
+ scope,
+ (ReferenceBinding) enclosingInstTb);
+ if (recType == null)
+ return null;
+ if (((ReferenceBinding) recType).isFinal()) {
+ scope.problemReporter().anonymousClassCannotExtendFinalClass(type, recType);
+ return null;
+ }
+ TypeBinding[] argumentTypes = NoParameters;
+ if (arguments != null) {
+ int length = arguments.length;
+ argumentTypes = new TypeBinding[length];
+ for (int i = 0; i < length; i++)
+ if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null)
+ return null;
+ }
+
+ // an anonymous class inherits from java.lang.Object when declared "after" an interface
+ ReferenceBinding superBinding =
+ recType.isInterface() ? scope.getJavaLangObject() : (ReferenceBinding) recType;
+ MethodBinding inheritedBinding =
+ scope.getConstructor(superBinding, argumentTypes, this);
+ if (!inheritedBinding.isValidBinding()) {
+ if (inheritedBinding.declaringClass == null)
+ inheritedBinding.declaringClass = superBinding;
+ scope.problemReporter().invalidConstructor(this, inheritedBinding);
+ return null;
+ }
+ if (enclosingInstance != null) {
+ if (!scope
+ .areTypesCompatible(
+ enclosingInstTb,
+ inheritedBinding.declaringClass.enclosingType())) {
+ scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
+ enclosingInstance,
+ enclosingInstTb,
+ inheritedBinding.declaringClass.enclosingType());
+ return null;
+ }
+ }
+
+ // this promotion has to be done somewhere: here or inside the constructor of the
+ // anonymous class. We do it here while the constructor of the inner is then easier.
+ if (arguments != null)
+ for (int i = 0; i < arguments.length; i++)
+ arguments[i].implicitWidening(inheritedBinding.parameters[i], argumentTypes[i]);
+
+ // Update the anonymous inner class : superclass, interface
+ scope.addAnonymousType(anonymousType, (ReferenceBinding) recType);
+ anonymousType.resolve(scope);
+ binding = anonymousType.createsInternalConstructorWithBinding(inheritedBinding);
+ return anonymousType.binding; // 1.2 change
+ }
+
+ public String toStringExpression(int tab) {
+ /*slow code */
+
+ String s = "";
+ if (enclosingInstance != null)
+ s += enclosingInstance.toString() + ".";
+ s += super.toStringExpression(tab);
+ if (anonymousType != null) {
+ s += anonymousType.toString(tab);
+ } //allows to restart just after the } one line under ....
+ return s;
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ if (visitor.visit(this, scope)) {
+ if (enclosingInstance != null)
+ enclosingInstance.traverse(visitor, scope);
+ type.traverse(visitor, scope);
+ if (arguments != null) {
+ int argumentsLength = arguments.length;
+ for (int i = 0; i < argumentsLength; i++)
+ arguments[i].traverse(visitor, scope);
+ }
+ if (anonymousType != null)
+ anonymousType.traverse(visitor, scope);
+ }
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java
new file mode 100644
index 0000000000..f075b17559
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java
@@ -0,0 +1,746 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class QualifiedNameReference extends NameReference {
+ public char[][] tokens;
+ public FieldBinding[] otherBindings;
+ public int indexOfFirstFieldBinding;
+ //points (into tokens) for the first token that corresponds to first FieldBinding
+
+ SyntheticAccessMethodBinding syntheticWriteAccessor;
+ SyntheticAccessMethodBinding[] syntheticReadAccessors;
+ protected FieldBinding lastFieldBinding;
+ public QualifiedNameReference(
+ char[][] sources,
+ int sourceStart,
+ int sourceEnd) {
+ super();
+ tokens = sources;
+ this.sourceStart = sourceStart;
+ this.sourceEnd = sourceEnd;
+ }
+
+ public FlowInfo analyseAssignment(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo,
+ Assignment assignment,
+ boolean isCompound) {
+ if (assignment.expression != null) {
+ flowInfo =
+ assignment
+ .expression
+ .analyseCode(currentScope, flowContext, flowInfo)
+ .unconditionalInits();
+ }
+ // determine the rank until which we now we do not need any actual value for the field access
+ int otherBindingsCount = otherBindings == null ? 0 : otherBindings.length;
+ int indexOfFirstValueRequired = otherBindingsCount;
+ while (indexOfFirstValueRequired > 0) {
+ FieldBinding otherBinding = otherBindings[indexOfFirstValueRequired - 1];
+ if (otherBinding.isStatic())
+ break; // no longer need any value before this point
+ indexOfFirstValueRequired--;
+ }
+
+ FieldBinding lastFieldBinding = null;
+ if ((bits & FIELD) != 0) {
+ // reading from a field
+ // check if final blank field
+ if ((lastFieldBinding = (FieldBinding) binding).isFinal()
+ && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) {
+ if (!flowInfo.isDefinitelyAssigned(lastFieldBinding)) {
+ currentScope.problemReporter().uninitializedBlankFinalField(
+ lastFieldBinding,
+ this);
+ }
+ }
+ } else {
+ if ((bits & LOCAL) != 0) {
+ // first binding is a local variable
+ LocalVariableBinding localBinding;
+ if (!flowInfo
+ .isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
+ currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
+ }
+ if (!flowInfo.isFakeReachable())
+ localBinding.used = true;
+ }
+ }
+ if (indexOfFirstValueRequired == 0) {
+ manageEnclosingInstanceAccessIfNecessary(currentScope);
+ // only for first binding
+ }
+ // all intermediate field accesses are read accesses
+ if (otherBindings != null) {
+ int start = indexOfFirstValueRequired == 0 ? 0 : indexOfFirstValueRequired - 1;
+ for (int i = start; i < otherBindingsCount; i++) {
+ if (lastFieldBinding != null) { // could be null if first was a local variable
+ manageSyntheticReadAccessIfNecessary(currentScope, lastFieldBinding, i);
+ }
+ lastFieldBinding = otherBindings[i];
+ }
+ }
+ if (isCompound) {
+ if (binding == lastFieldBinding
+ && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)
+ && (!flowInfo.isDefinitelyAssigned(lastFieldBinding))) {
+ currentScope.problemReporter().uninitializedBlankFinalField(
+ lastFieldBinding,
+ this);
+ }
+ manageSyntheticReadAccessIfNecessary(
+ currentScope,
+ lastFieldBinding,
+ binding == lastFieldBinding ? 0 : otherBindings.length);
+ }
+ // the last field access is a write access
+ if (lastFieldBinding.isFinal()) {
+ // in a context where it can be assigned?
+ if (currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) {
+ if (flowInfo.isPotentiallyAssigned(lastFieldBinding)) {
+ if (indexOfFirstFieldBinding == 1) {
+ // was an implicit reference to the first field binding
+ currentScope.problemReporter().duplicateInitializationOfBlankFinalField(
+ lastFieldBinding,
+ this);
+ } else {
+ currentScope.problemReporter().cannotAssignToFinalField(lastFieldBinding, this);
+ // attempting to assign a non implicit reference
+ }
+ }
+ flowInfo.markAsDefinitelyAssigned(lastFieldBinding);
+ flowContext.recordSettingFinal(lastFieldBinding, this);
+ } else {
+ currentScope.problemReporter().cannotAssignToFinalField(lastFieldBinding, this);
+ }
+ }
+ // equivalent to valuesRequired[maxOtherBindings]
+ manageSyntheticWriteAccessIfNecessary(currentScope, lastFieldBinding);
+ return flowInfo;
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ return analyseCode(currentScope, flowContext, flowInfo, true);
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo,
+ boolean valueRequired) {
+
+ // determine the rank until which we now we do not need any actual value for the field access
+ int otherBindingsCount = otherBindings == null ? 0 : otherBindings.length;
+ int indexOfFirstValueRequired;
+ if (valueRequired) {
+ indexOfFirstValueRequired = otherBindingsCount;
+ while (indexOfFirstValueRequired > 0) {
+ FieldBinding otherBinding = otherBindings[indexOfFirstValueRequired - 1];
+ if (otherBinding.isStatic())
+ break; // no longer need any value before this point
+ indexOfFirstValueRequired--;
+ }
+ } else {
+ indexOfFirstValueRequired = otherBindingsCount + 1;
+ }
+ switch (bits & RestrictiveFlagMASK) {
+ case FIELD : // reading a field
+ if (indexOfFirstValueRequired == 0) {
+ manageSyntheticReadAccessIfNecessary(currentScope, (FieldBinding) binding, 0);
+ }
+ // check if reading a final blank field
+ FieldBinding fieldBinding;
+ if ((fieldBinding = (FieldBinding) binding).isFinal()
+ && (indexOfFirstFieldBinding == 1)
+ // was an implicit reference to the first field binding
+ && currentScope.allowBlankFinalFieldAssignment(fieldBinding)
+ && (!flowInfo.isDefinitelyAssigned(fieldBinding))) {
+ currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
+ }
+ break;
+ case LOCAL : // reading a local variable
+ LocalVariableBinding localBinding;
+ if (!flowInfo
+ .isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
+ currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
+ }
+ if (!flowInfo.isFakeReachable())
+ localBinding.used = true;
+ }
+ if (indexOfFirstValueRequired == 0) {
+ manageEnclosingInstanceAccessIfNecessary(currentScope);
+ // only for first binding
+ }
+ if (otherBindings != null) {
+ int start = indexOfFirstValueRequired == 0 ? 0 : indexOfFirstValueRequired - 1;
+ for (int i = start; i < otherBindingsCount; i++) {
+ manageSyntheticReadAccessIfNecessary(currentScope, otherBindings[i], i + 1);
+ }
+ }
+ return flowInfo;
+ }
+
+ /**
+ * Check and/or redirect the field access to the delegate receiver if any
+ */
+ public TypeBinding checkFieldAccess(BlockScope scope) {
+ // check for forward references
+ FieldBinding fieldBinding = (FieldBinding) binding;
+ MethodScope methodScope = scope.methodScope();
+ if (methodScope.enclosingSourceType() == fieldBinding.declaringClass
+ && methodScope.fieldDeclarationIndex != methodScope.NotInFieldDecl
+ && fieldBinding.id >= methodScope.fieldDeclarationIndex) {
+ if ((!fieldBinding.isStatic() || methodScope.isStatic)
+ && this.indexOfFirstFieldBinding == 1)
+ scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType());
+ }
+ bits &= ~RestrictiveFlagMASK; // clear bits
+ bits |= FIELD;
+ return getOtherFieldBindings(scope);
+ }
+
+ public void generateAssignment(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Assignment assignment,
+ boolean valueRequired) {
+ generateReadSequence(currentScope, codeStream, true);
+ // the last field access is a write access
+ assignment.expression.generateCode(currentScope, codeStream, true);
+ fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, valueRequired);
+ // equivalent to valuesRequired[maxOtherBindings]
+ if (valueRequired) {
+ codeStream.generateImplicitConversion(assignment.implicitConversion);
+ }
+ }
+
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ if (constant != NotAConstant) {
+ if (valueRequired) {
+ codeStream.generateConstant(constant, implicitConversion);
+ }
+ } else {
+ generateReadSequence(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ if (lastFieldBinding.declaringClass == null) { // array length
+ codeStream.arraylength();
+ codeStream.generateImplicitConversion(implicitConversion);
+ } else {
+ if (lastFieldBinding.constant != NotAConstant) {
+ // inline the last field constant
+ codeStream.generateConstant(lastFieldBinding.constant, implicitConversion);
+ } else {
+ SyntheticAccessMethodBinding accessor =
+ syntheticReadAccessors == null
+ ? null
+ : syntheticReadAccessors[syntheticReadAccessors.length - 1];
+ if (accessor == null) {
+ if (lastFieldBinding.isStatic()) {
+ codeStream.getstatic(lastFieldBinding);
+ } else {
+ codeStream.getfield(lastFieldBinding);
+ }
+ } else {
+ codeStream.invokestatic(accessor);
+ }
+ codeStream.generateImplicitConversion(implicitConversion);
+ }
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public void generateCompoundAssignment(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Expression expression,
+ int operator,
+ int assignmentImplicitConversion,
+ boolean valueRequired) {
+
+ generateReadSequence(currentScope, codeStream, true);
+ SyntheticAccessMethodBinding accessor =
+ syntheticReadAccessors == null
+ ? null
+ : syntheticReadAccessors[syntheticReadAccessors.length - 1];
+
+ if (lastFieldBinding.isStatic()) {
+ if (accessor == null) {
+ codeStream.getstatic(lastFieldBinding);
+ } else {
+ codeStream.invokestatic(accessor);
+ }
+ } else {
+ codeStream.dup();
+ if (accessor == null) {
+ codeStream.getfield(lastFieldBinding);
+ } else {
+ codeStream.invokestatic(accessor);
+ }
+ }
+ // the last field access is a write access
+ // perform the actual compound operation
+ int operationTypeID;
+ if ((operationTypeID = implicitConversion >> 4) == T_String) {
+ codeStream.generateStringAppend(currentScope, null, expression);
+ } else {
+ // promote the array reference to the suitable operation type
+ codeStream.generateImplicitConversion(implicitConversion);
+ // generate the increment value (will by itself be promoted to the operation value)
+ if (expression == IntLiteral.One) { // prefix operation
+ codeStream.generateConstant(expression.constant, implicitConversion);
+ } else {
+ expression.generateCode(currentScope, codeStream, true);
+ }
+ // perform the operation
+ codeStream.sendOperator(operator, operationTypeID);
+ // cast the value back to the array reference type
+ codeStream.generateImplicitConversion(assignmentImplicitConversion);
+ }
+ // actual assignment
+ fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, valueRequired);
+ // equivalent to valuesRequired[maxOtherBindings]
+ }
+
+ public void generatePostIncrement(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ CompoundAssignment postIncrement,
+ boolean valueRequired) {
+ generateReadSequence(currentScope, codeStream, true);
+ SyntheticAccessMethodBinding accessor =
+ syntheticReadAccessors == null
+ ? null
+ : syntheticReadAccessors[syntheticReadAccessors.length - 1];
+
+ if (lastFieldBinding.isStatic()) {
+ if (accessor == null) {
+ codeStream.getstatic(lastFieldBinding);
+ } else {
+ codeStream.invokestatic(accessor);
+ }
+ } else {
+ codeStream.dup();
+ if (accessor == null) {
+ codeStream.getfield(lastFieldBinding);
+ } else {
+ codeStream.invokestatic(accessor);
+ }
+ }
+ // duplicate the old field value
+ if (valueRequired) {
+ if (lastFieldBinding.isStatic()) {
+ if ((lastFieldBinding.type == LongBinding)
+ || (lastFieldBinding.type == DoubleBinding)) {
+ codeStream.dup2();
+ } else {
+ codeStream.dup();
+ }
+ } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value]
+ if ((lastFieldBinding.type == LongBinding)
+ || (lastFieldBinding.type == DoubleBinding)) {
+ codeStream.dup2_x1();
+ } else {
+ codeStream.dup_x1();
+ }
+ }
+ }
+ codeStream.generateConstant(
+ postIncrement.expression.constant,
+ implicitConversion);
+ codeStream.sendOperator(postIncrement.operator, lastFieldBinding.type.id);
+ codeStream.generateImplicitConversion(
+ postIncrement.assignmentImplicitConversion);
+
+ fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, false);
+ }
+
+ /*
+ * Generate code for all bindings (local and fields) excluding the last one, which may then be generated code
+ * for a read or write access.
+ */
+ public void generateReadSequence(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+
+ // determine the rank until which we now we do not need any actual value for the field access
+ int otherBindingsCount = otherBindings == null ? 0 : otherBindings.length;
+ int indexOfFirstValueRequired;
+ if (valueRequired) {
+ indexOfFirstValueRequired = otherBindingsCount;
+ while (indexOfFirstValueRequired > 0) {
+ FieldBinding otherBinding = otherBindings[indexOfFirstValueRequired - 1];
+ if (otherBinding.isStatic() || otherBinding.constant != NotAConstant)
+ break; // no longer need any value before this point
+ indexOfFirstValueRequired--;
+ }
+ } else {
+ indexOfFirstValueRequired = otherBindingsCount + 1;
+ }
+ if (indexOfFirstValueRequired == 0) {
+ switch (bits & RestrictiveFlagMASK) {
+ case FIELD :
+ lastFieldBinding = (FieldBinding) binding;
+
+ // if first field is actually constant, we can inline it
+ if (lastFieldBinding.constant != NotAConstant) {
+ codeStream.generateConstant(lastFieldBinding.constant, 0);
+ // no implicit conversion
+ lastFieldBinding = null; // will not generate it again
+ break;
+ }
+ if (!lastFieldBinding.isStatic()) {
+ if ((bits & DepthMASK) != 0) {
+ Object[] emulationPath =
+ currentScope.getExactEmulationPath(
+ currentScope.enclosingSourceType().enclosingTypeAt(
+ (bits & DepthMASK) >> DepthSHIFT));
+ if (emulationPath == null) {
+ // internal error, per construction we should have found it
+ currentScope.problemReporter().needImplementation();
+ } else {
+ codeStream.generateOuterAccess(emulationPath, this, currentScope);
+ }
+ } else {
+ generateReceiver(codeStream);
+ }
+ }
+ break;
+ case LOCAL : // reading the first local variable
+ lastFieldBinding = null;
+ LocalVariableBinding localBinding = (LocalVariableBinding) binding;
+
+ // regular local variable read
+ if (localBinding.constant != NotAConstant) {
+ codeStream.generateConstant(localBinding.constant, 0);
+ // no implicit conversion
+ } else {
+ // outer local?
+ if ((bits & DepthMASK) != 0) {
+ // outer local can be reached either through a synthetic arg or a synthetic field
+ VariableBinding[] path = currentScope.getEmulationPath(localBinding);
+ if (path == null) {
+ // emulation was not possible (should not happen per construction)
+ currentScope.problemReporter().needImplementation();
+ } else {
+ codeStream.generateOuterAccess(path, this, currentScope);
+ }
+ } else {
+ codeStream.load(localBinding);
+ }
+ }
+ }
+ } else {
+ lastFieldBinding = null;
+ }
+ // all intermediate field accesses are read accesses
+ // only the last field binding is a write access
+ if (otherBindings != null) {
+ int start = indexOfFirstValueRequired == 0 ? 0 : indexOfFirstValueRequired - 1;
+ for (int i = start; i < otherBindingsCount; i++) {
+ if (lastFieldBinding != null) {
+ MethodBinding accessor =
+ syntheticReadAccessors == null ? null : syntheticReadAccessors[i];
+ if (accessor == null)
+ if (lastFieldBinding.isStatic())
+ codeStream.getstatic(lastFieldBinding);
+ else
+ codeStream.getfield(lastFieldBinding);
+ else
+ codeStream.invokestatic(accessor);
+ }
+ lastFieldBinding = otherBindings[i];
+ }
+ }
+ }
+
+ public void generateReceiver(CodeStream codeStream) {
+ codeStream.aload_0();
+ }
+
+ public TypeBinding getOtherFieldBindings(BlockScope scope) {
+ // At this point restrictiveFlag may ONLY have two potential value : FIELD LOCAL (i.e cast <<(VariableBinding) binding>> is valid)
+
+ if ((bits & FIELD) != 0) {
+ if (!((FieldBinding) binding).isStatic()) {
+ //must check for the static status....
+ if (indexOfFirstFieldBinding == 1) {
+ //the field is the first token of the qualified reference....
+ if (scope.methodScope().isStatic) {
+ scope.problemReporter().staticFieldAccessToNonStaticVariable(
+ this,
+ (FieldBinding) binding);
+ return null;
+ }
+ } else { //accessing to a field using a type as "receiver" is allowed only with static field
+ scope.problemReporter().staticFieldAccessToNonStaticVariable(
+ this,
+ (FieldBinding) binding);
+ return null;
+ }
+ }
+ if (isFieldUseDeprecated((FieldBinding) binding, scope))
+ scope.problemReporter().deprecatedField((FieldBinding) binding, this);
+
+ // if the binding declaring class is not visible, need special action
+ // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
+ FieldBinding fieldBinding = (FieldBinding) binding;
+ if (fieldBinding.declaringClass != null
+ && fieldBinding.constant == NotAConstant
+ && !fieldBinding.declaringClass.canBeSeenBy(scope))
+ binding = new FieldBinding(fieldBinding, scope.enclosingSourceType());
+ }
+
+ TypeBinding type = ((VariableBinding) binding).type;
+ int index = indexOfFirstFieldBinding;
+ int length = tokens.length;
+ if (index == length) { // restrictiveFlag == FIELD
+ constant =
+ FieldReference.getConstantFor((FieldBinding) binding, false, this, index - 1);
+ return type;
+ }
+
+ // allocation of the fieldBindings array and its respective constants
+ int otherBindingsLength = length - index;
+ otherBindings = new FieldBinding[otherBindingsLength];
+
+ // fill the first constant (the one of the binding)
+ constant =
+ ((bits & FIELD) != 0)
+ ? FieldReference.getConstantFor((FieldBinding) binding, false, this, index - 1)
+ : ((VariableBinding) binding).constant;
+
+ // iteration on each field
+ while (index < length) {
+ char[] token = tokens[index];
+ if (type == null)
+ return null; // could not resolve type prior to this point
+ FieldBinding field = scope.getField(type, token, this);
+ int place = index - indexOfFirstFieldBinding;
+ otherBindings[place] = field;
+ if (field.isValidBinding()) {
+ if (isFieldUseDeprecated(field, scope))
+ scope.problemReporter().deprecatedField(field, this);
+ Constant someConstant =
+ FieldReference.getConstantFor(field, false, this, place);
+ // constant propagation can only be performed as long as the previous one is a constant too.
+ if (constant != NotAConstant) {
+ constant = someConstant;
+ }
+ // if the binding declaring class is not visible, need special action
+ // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
+ if (field.declaringClass != type
+ && field.declaringClass != null // array.length
+ && field.constant == NotAConstant
+ && !field.declaringClass.canBeSeenBy(scope))
+ otherBindings[place] = new FieldBinding(field, (ReferenceBinding) type);
+ type = field.type;
+ index++;
+ } else {
+ constant = NotAConstant; //don't fill other constants slots...
+ scope.problemReporter().invalidField(this, field, index, type);
+ return null;
+ }
+ }
+ return (otherBindings[otherBindingsLength - 1]).type;
+ }
+
+ public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
+ //If inlinable field, forget the access emulation, the code gen will directly target it
+ if (((bits & DepthMASK) == 0) || (constant != NotAConstant)) {
+ return;
+ }
+ switch (bits & RestrictiveFlagMASK) {
+ case FIELD :
+ FieldBinding fieldBinding;
+ if ((fieldBinding = (FieldBinding) binding).isStatic()
+ || (fieldBinding.constant != NotAConstant))
+ return;
+ ReferenceBinding compatibleType = currentScope.enclosingSourceType();
+ // the declaringClass of the target binding must be compatible with the enclosing
+ // type at <depth> levels outside
+ for (int i = 0, depth = (bits & DepthMASK) >> DepthSHIFT; i < depth; i++) {
+ compatibleType = compatibleType.enclosingType();
+ }
+ currentScope.emulateOuterAccess(compatibleType, false);
+ // request cascade of accesses
+ break;
+ case LOCAL :
+ currentScope.emulateOuterAccess((LocalVariableBinding) binding);
+ }
+ }
+
+ public void manageSyntheticReadAccessIfNecessary(
+ BlockScope currentScope,
+ FieldBinding fieldBinding,
+ int index) {
+ // index == 0 denotes the first fieldBinding, index > 0 denotes one of the 'otherBindings'
+
+ if (fieldBinding.constant != NotAConstant)
+ return;
+ if (fieldBinding.isPrivate()) { // private access
+ if (fieldBinding.declaringClass != currentScope.enclosingSourceType()) {
+ if (syntheticReadAccessors == null) {
+ if (otherBindings == null)
+ syntheticReadAccessors = new SyntheticAccessMethodBinding[1];
+ else
+ syntheticReadAccessors =
+ new SyntheticAccessMethodBinding[otherBindings.length + 1];
+ }
+ syntheticReadAccessors[index] = fieldBinding.getSyntheticReadAccess();
+ currentScope.problemReporter().needToEmulateFieldReadAccess(fieldBinding, this);
+ }
+ return;
+ }
+ if (fieldBinding.isProtected()
+ // implicit protected access (only for first one)
+ && index == 0
+ && (bits & DepthMASK) != 0
+ && (fieldBinding.declaringClass.getPackage()
+ != currentScope.enclosingSourceType().getPackage())) {
+ if (syntheticReadAccessors == null) {
+ if (otherBindings == null)
+ syntheticReadAccessors = new SyntheticAccessMethodBinding[1];
+ else
+ syntheticReadAccessors =
+ new SyntheticAccessMethodBinding[otherBindings.length + 1];
+ }
+ syntheticReadAccessors[index] =
+ (
+ (SourceTypeBinding) currentScope.enclosingSourceType().enclosingTypeAt(
+ (bits & DepthMASK) >> DepthSHIFT)).addSyntheticMethod(
+ fieldBinding,
+ true);
+ currentScope.problemReporter().needToEmulateFieldReadAccess(fieldBinding, this);
+ }
+ }
+
+ /*
+ * No need to emulate access to protected fields since not implicitly accessed
+ */
+ public void manageSyntheticWriteAccessIfNecessary(
+ BlockScope currentScope,
+ FieldBinding fieldBinding) {
+ if (fieldBinding.isPrivate()
+ && fieldBinding.declaringClass != currentScope.enclosingSourceType()) {
+ syntheticWriteAccessor = fieldBinding.getSyntheticWriteAccess();
+ currentScope.problemReporter().needToEmulateFieldWriteAccess(
+ fieldBinding,
+ this);
+ }
+ }
+
+ /**
+ * Normal field binding did not work, try to bind to a field of the delegate receiver.
+ */
+ public TypeBinding reportError(BlockScope scope) {
+ if (binding instanceof ProblemFieldBinding) {
+ scope.problemReporter().invalidField(this, (FieldBinding) binding);
+ } else
+ if (binding instanceof ProblemReferenceBinding) {
+ scope.problemReporter().invalidType(this, (TypeBinding) binding);
+ } else {
+ scope.problemReporter().unresolvableReference(this, binding);
+ }
+ return null;
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ // field and/or local are done before type lookups
+
+ // the only available value for the restrictiveFlag BEFORE
+ // the TC is Flag_Type Flag_LocalField and Flag_TypeLocalField
+
+ constant = Constant.NotAConstant;
+ if ((binding = scope.getBinding(tokens, bits & RestrictiveFlagMASK, this))
+ .isValidBinding()) {
+ switch (bits & RestrictiveFlagMASK) {
+ case VARIABLE : //============only variable===========
+ case TYPE | VARIABLE :
+ if (binding instanceof LocalVariableBinding) {
+ if (!((LocalVariableBinding) binding).isFinal() && ((bits & DepthMASK) != 0))
+ scope.problemReporter().cannotReferToNonFinalOuterLocal(
+ (LocalVariableBinding) binding,
+ this);
+ bits &= ~RestrictiveFlagMASK; // clear bits
+ bits |= LOCAL;
+ return getOtherFieldBindings(scope);
+ }
+ if (binding instanceof FieldBinding) {
+ // check for forward references
+ FieldBinding fieldBinding = (FieldBinding) binding;
+ MethodScope methodScope = scope.methodScope();
+ if (methodScope.enclosingSourceType() == fieldBinding.declaringClass
+ && methodScope.fieldDeclarationIndex != methodScope.NotInFieldDecl
+ && fieldBinding.id >= methodScope.fieldDeclarationIndex) {
+ if ((!fieldBinding.isStatic() || methodScope.isStatic)
+ && this.indexOfFirstFieldBinding == 1)
+ scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType());
+ }
+ bits &= ~RestrictiveFlagMASK; // clear bits
+ bits |= FIELD;
+ return getOtherFieldBindings(scope);
+ }
+
+ // thus it was a type
+ bits &= ~RestrictiveFlagMASK; // clear bits
+ bits |= TYPE;
+ case TYPE : //=============only type ==============
+ //deprecated test
+ if (isTypeUseDeprecated((TypeBinding) binding, scope))
+ scope.problemReporter().deprecatedType((TypeBinding) binding, this);
+ return (TypeBinding) binding;
+ }
+ }
+
+ //========error cases===============
+ return this.reportError(scope);
+ }
+
+ public void setFieldIndex(int index) {
+
+ indexOfFirstFieldBinding = index;
+ }
+
+ public String toStringExpression() {
+ /* slow speed */
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < tokens.length; i++) {
+ buffer.append(tokens[i]);
+ if (i < (tokens.length - 1)) {
+ buffer.append(".");
+ }
+ }
+ return buffer.toString();
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ visitor.visit(this, scope);
+ visitor.endVisit(this, scope);
+ }
+
+ public String unboundReferenceErrorName() {
+
+ return new String(tokens[0]);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedSuperReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedSuperReference.java
new file mode 100644
index 0000000000..d5eea4fc66
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedSuperReference.java
@@ -0,0 +1,56 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class QualifiedSuperReference extends QualifiedThisReference {
+ public QualifiedSuperReference(TypeReference name, int pos, int sourceEnd) {
+ super(name, pos, sourceEnd);
+ }
+
+ public boolean isSuper() {
+
+ return true;
+ }
+
+ public boolean isThis() {
+
+ return false;
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+
+ super.resolveType(scope);
+ if (currentCompatibleType == null)
+ return null; // error case
+
+ if (scope.isJavaLangObject(currentCompatibleType)) {
+ scope.problemReporter().cannotUseSuperInJavaLangObject(this);
+ return null;
+ }
+ return currentCompatibleType.superclass();
+ }
+
+ public String toStringExpression() {
+ /* slow code */
+
+ return qualification.toString(0) + ".super";
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ if (visitor.visit(this, blockScope)) {
+ qualification.traverse(visitor, blockScope);
+ }
+ visitor.endVisit(this, blockScope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java
new file mode 100644
index 0000000000..266880e615
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java
@@ -0,0 +1,163 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class QualifiedThisReference extends ThisReference {
+ public TypeReference qualification;
+
+ ReferenceBinding currentCompatibleType;
+ public QualifiedThisReference(TypeReference name, int pos, int sourceEnd) {
+ qualification = name;
+ this.sourceEnd = sourceEnd;
+ this.sourceStart = name.sourceStart;
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ manageEnclosingInstanceAccessIfNecessary(currentScope);
+ return flowInfo;
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo,
+ boolean valueRequired) {
+ if (valueRequired) {
+ manageEnclosingInstanceAccessIfNecessary(currentScope);
+ }
+ return flowInfo;
+ }
+
+ protected boolean checkAccess(
+ MethodScope methodScope,
+ TypeBinding targetType) {
+ // this/super cannot be used in constructor call
+ if (methodScope.isConstructorCall) {
+ methodScope.problemReporter().fieldsOrThisBeforeConstructorInvocation(this);
+ return false;
+ }
+
+ // static may not refer to this/super
+ if (methodScope.isStatic) {
+ methodScope.problemReporter().incorrectEnclosingInstanceReference(
+ this,
+ targetType);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Code generation for QualifiedThisReference
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param valueRequired boolean
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ if (valueRequired) {
+ if ((bits & DepthMASK) != 0) {
+ Object[] emulationPath =
+ currentScope.getExactEmulationPath(currentCompatibleType);
+ if (emulationPath == null) {
+ // internal error, per construction we should have found it
+ currentScope.problemReporter().needImplementation();
+ } else {
+ codeStream.generateOuterAccess(emulationPath, this, currentScope);
+ }
+ } else {
+ // nothing particular after all
+ codeStream.aload_0();
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
+ currentScope.emulateOuterAccess(
+ (SourceTypeBinding) currentCompatibleType,
+ false);
+ // request cascade of accesses
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ constant = NotAConstant;
+ TypeBinding qualificationTb = qualification.resolveType(scope);
+ if (qualificationTb == null)
+ return null;
+
+ // the qualification MUST exactly match some enclosing type name
+ // Its possible to qualify 'this' by the name of the current class
+ int depth = 0;
+ currentCompatibleType = scope.referenceType().binding;
+ while (currentCompatibleType != null
+ && currentCompatibleType != qualificationTb) {
+ depth++;
+ currentCompatibleType =
+ currentCompatibleType.isStatic() ? null : currentCompatibleType.enclosingType();
+ }
+ bits |= (depth & 0xFF) << DepthSHIFT; // encoded depth into 8 bits
+
+ if (currentCompatibleType == null) {
+ scope.problemReporter().incorrectEnclosingInstanceReference(
+ this,
+ qualificationTb);
+ return null;
+ }
+
+ // Ensure one cannot write code like: B() { super(B.this); }
+ if (depth == 0) {
+ if (!checkAccess(scope.methodScope(), qualificationTb))
+ return null;
+ } else {
+ // Could also be targeting an enclosing instance inside a super constructor invocation
+ // class X {
+ // public X(int i) {
+ // this(new Object() { Object obj = X.this; });
+ // }
+ // }
+
+ MethodScope methodScope = scope.methodScope();
+ while (methodScope != null) {
+ if (methodScope.enclosingSourceType() == currentCompatibleType) {
+ if (!this.checkAccess(methodScope, qualificationTb))
+ return null;
+ break;
+ }
+ methodScope = methodScope.parent.methodScope();
+ }
+ }
+ return qualificationTb;
+ }
+
+ public String toStringExpression() {
+ /* slow code */
+
+ return qualification.toString(0) + ".this";
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ if (visitor.visit(this, blockScope)) {
+ qualification.traverse(visitor, blockScope);
+ }
+ visitor.endVisit(this, blockScope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java
new file mode 100644
index 0000000000..e1563beb88
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java
@@ -0,0 +1,66 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class QualifiedTypeReference extends TypeReference {
+ public char[][] tokens;
+ public long[] sourcePositions;
+ public QualifiedTypeReference(char[][] sources, long[] poss) {
+ tokens = sources;
+ sourcePositions = poss;
+ sourceStart = (int) (sourcePositions[0] >>> 32);
+ sourceEnd =
+ (int) (sourcePositions[sourcePositions.length - 1] & 0x00000000FFFFFFFFL);
+ }
+
+ public QualifiedTypeReference(char[][] sources, TypeBinding tb, long[] poss) {
+ this(sources, poss);
+ binding = tb;
+ }
+
+ public TypeReference copyDims(int dim) {
+ //return a type reference copy of me with some dimensions
+ //warning : the new type ref has a null binding
+
+ return new ArrayQualifiedTypeReference(tokens, null, dim, sourcePositions);
+ }
+
+ public TypeBinding getTypeBinding(Scope scope) {
+ if (binding != null)
+ return binding;
+ return scope.getType(tokens);
+ }
+
+ public char[][] getTypeName() {
+
+ return tokens;
+ }
+
+ public String toStringExpression(int tab) {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < tokens.length; i++) {
+ buffer.append(tokens[i]);
+ if (i < (tokens.length - 1)) {
+ buffer.append(".");
+ }
+ }
+ return buffer.toString();
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ visitor.visit(this, scope);
+ visitor.endVisit(this, scope);
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, ClassScope scope) {
+ visitor.visit(this, scope);
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java
new file mode 100644
index 0000000000..c827ca2ea3
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java
@@ -0,0 +1,112 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+public abstract class Reference extends Expression {
+ /**
+ * BaseLevelReference constructor comment.
+ */
+ public Reference() {
+ super();
+ }
+
+ public FlowInfo analyseAssignment(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo,
+ Assignment assignment,
+ boolean isCompound) {
+ throw new ShouldNotImplement("Assignment variable should provide an implementation for flow analysis");
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ return flowInfo;
+ }
+
+ public FieldBinding fieldBinding() {
+ //this method should be sent ONLY after a check against isFieldReference()
+ //check its use doing senders.........
+
+ return null;
+ }
+
+ public void fieldStore(
+ CodeStream codeStream,
+ FieldBinding fieldBinding,
+ MethodBinding syntheticWriteAccessor,
+ boolean valueRequired) {
+
+ if (fieldBinding.isStatic()) {
+ if (valueRequired) {
+ if ((fieldBinding.type == LongBinding)
+ || (fieldBinding.type == DoubleBinding)) {
+ codeStream.dup2();
+ } else {
+ codeStream.dup();
+ }
+ }
+ if (syntheticWriteAccessor == null) {
+ codeStream.putstatic(fieldBinding);
+ } else {
+ codeStream.invokestatic(syntheticWriteAccessor);
+ }
+ } else { // Stack: [owner][new field value] ---> [new field value][owner][new field value]
+ if (valueRequired) {
+ if ((fieldBinding.type == LongBinding)
+ || (fieldBinding.type == DoubleBinding)) {
+ codeStream.dup2_x1();
+ } else {
+ codeStream.dup_x1();
+ }
+ }
+ if (syntheticWriteAccessor == null) {
+ codeStream.putfield(fieldBinding);
+ } else {
+ codeStream.invokestatic(syntheticWriteAccessor);
+ }
+ }
+ }
+
+ public void generateAssignment(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Assignment assignment,
+ boolean valueRequired) {
+ throw new ShouldNotImplement("Compound pre assignments should provide an implementation for code generation");
+ }
+
+ public void generateCompoundAssignment(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Expression expression,
+ int operator,
+ int assignmentImplicitConversion,
+ boolean valueRequired) {
+ throw new ShouldNotImplement("Compound assignment variable should provide an implementation for code generation");
+ }
+
+ public void generatePostIncrement(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ CompoundAssignment postIncrement,
+ boolean valueRequired) {
+ throw new ShouldNotImplement("Post increment variable should provide an implementation for code generation");
+ }
+
+ public boolean isFieldReference() {
+
+ return false;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java
new file mode 100644
index 0000000000..ad0a6584cd
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java
@@ -0,0 +1,281 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class ReturnStatement extends Statement {
+ public Expression expression;
+
+ public TypeBinding expressionType;
+ public boolean isSynchronized;
+ public AstNode[] subroutines;
+ public LocalVariableBinding saveValueVariable;
+
+ public ReturnStatement(Expression expr, int s, int e) {
+ sourceStart = s;
+ sourceEnd = e;
+ expression = expr;
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+
+ // here requires to generate a sequence of finally blocks invocations depending corresponding
+ // to each of the traversed try statements, so that execution will terminate properly.
+
+ // lookup the label, this should answer the returnContext
+
+ if (expression != null) {
+ flowInfo = expression.analyseCode(currentScope, flowContext, flowInfo);
+ }
+ // compute the return sequence (running the finally blocks)
+ FlowContext targetContext;
+ FlowContext traversedContext = flowContext;
+ int subIndex = 0, maxSub = 5;
+ boolean saveValueNeeded = false;
+ while (true) {
+ AstNode sub;
+ if ((sub = traversedContext.subRoutine()) != null) {
+ if (subroutines == null) {
+ subroutines = new AstNode[maxSub];
+ }
+ if (subIndex == maxSub) {
+ System.arraycopy(
+ subroutines,
+ 0,
+ (subroutines = new AstNode[maxSub *= 2]),
+ 0,
+ subIndex);
+ // grow
+ }
+ subroutines[subIndex++] = sub;
+ if (sub.cannotReturn()) {
+ saveValueNeeded = false;
+ break;
+ }
+ }
+ AstNode node;
+ if ((node = traversedContext.associatedNode)
+ instanceof SynchronizedStatement) {
+ isSynchronized = true;
+ } else {
+ if ((expression != null) && (node instanceof TryStatement)) {
+ saveValueNeeded = true;
+ } else {
+ if (traversedContext instanceof InitializationFlowContext) {
+ currentScope.problemReporter().cannotReturnInInitializer(this);
+ return FlowInfo.DeadEnd;
+ }
+ }
+ }
+ FlowContext parentContext;
+ if ((parentContext = traversedContext.parent) == null) { // top-context
+ break;
+ } else {
+ traversedContext = parentContext;
+ }
+ }
+ // resize subroutines
+ if ((subroutines != null) && (subIndex != maxSub)) {
+ System.arraycopy(
+ subroutines,
+ 0,
+ (subroutines = new AstNode[subIndex]),
+ 0,
+ subIndex);
+ }
+ // the top returning context may want to remember the initialization at this
+ // point for dealing with blank final fields.
+ traversedContext.recordReturnFrom(flowInfo.unconditionalInits());
+
+ // no need to save a constant value
+ if ((expression != null) && (expression.constant != NotAConstant)) {
+ saveValueNeeded = false;
+ }
+ // secret local variable for return value (note that this can only occur in a real method)
+ if (saveValueNeeded) {
+ prepareSaveValueLocation(currentScope);
+ } else {
+ MethodScope methodScope;
+ if ((!isSynchronized) && (expressionType == BooleanBinding)) {
+ expression.bits |= ValueForReturnMASK;
+ }
+ }
+ return FlowInfo.DeadEnd;
+ }
+
+ /**
+ * Retrun statement code generation
+ *
+ * generate the finallyInvocationSequence.
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ */
+ public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+ if ((bits & IsReachableMASK) == 0) {
+ return;
+ }
+ int pc = codeStream.position;
+ // generate the expression
+ if ((expression != null) && (expression.constant == NotAConstant)) {
+ expression.generateCode(currentScope, codeStream, needValue());
+ // no value needed if non-returning subroutine
+ generateStoreSaveValueIfNecessary(currentScope, codeStream);
+ }
+
+ // generation of code responsible for invoking the finally blocks in sequence
+ if (subroutines != null) {
+ for (int i = 0, max = subroutines.length; i < max; i++) {
+ AstNode sub;
+ if ((sub = subroutines[i]) instanceof SynchronizedStatement) {
+ codeStream.load(((SynchronizedStatement) sub).synchroVariable);
+ codeStream.monitorexit();
+ } else {
+ TryStatement trySub = (TryStatement) sub;
+ if (trySub.subRoutineCannotReturn) {
+ codeStream.goto_(trySub.subRoutineStartLabel);
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ } else {
+ codeStream.jsr(trySub.subRoutineStartLabel);
+ }
+ }
+ }
+ }
+ if (saveValueVariable != null)
+ codeStream.load(saveValueVariable);
+
+ if ((expression != null) && (expression.constant != NotAConstant)) {
+ codeStream.generateConstant(expression.constant, expression.implicitConversion);
+ generateStoreSaveValueIfNecessary(currentScope, codeStream);
+ }
+ // output the suitable return bytecode or wrap the value inside a descriptor for doits
+ this.generateReturnBytecode(currentScope, codeStream);
+
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ /**
+ * Dump the suitable return bytecode for a return statement
+ *
+ */
+ public void generateReturnBytecode(
+ BlockScope currentScope,
+ CodeStream codeStream) {
+
+ if (expression == null) {
+ codeStream.return_();
+ } else {
+ switch (expression.implicitConversion >> 4) {
+ case T_boolean :
+ case T_int :
+ codeStream.ireturn();
+ break;
+ case T_float :
+ codeStream.freturn();
+ break;
+ case T_long :
+ codeStream.lreturn();
+ break;
+ case T_double :
+ codeStream.dreturn();
+ break;
+ default :
+ codeStream.areturn();
+ }
+ }
+ }
+
+ public void generateStoreSaveValueIfNecessary(
+ BlockScope currentScope,
+ CodeStream codeStream) {
+
+ if (saveValueVariable != null)
+ codeStream.store(saveValueVariable, false);
+ }
+
+ public boolean needValue() {
+ return (subroutines == null) || (saveValueVariable != null) || isSynchronized;
+ }
+
+ public void prepareSaveValueLocation(BlockScope currentScope) {
+
+ saveValueVariable =
+ (
+ (AbstractMethodDeclaration) currentScope
+ .methodScope()
+ .referenceContext)
+ .secretReturnValue;
+ saveValueVariable.used = true;
+ }
+
+ public void resolve(BlockScope scope) {
+ MethodScope methodScope = scope.methodScope();
+ TypeBinding methodType =
+ (methodScope.referenceContext instanceof AbstractMethodDeclaration)
+ ? ((AbstractMethodDeclaration) methodScope.referenceContext).binding.returnType
+ : VoidBinding;
+ if (methodType == VoidBinding) {
+ // the expression should be null
+ if (expression == null)
+ return;
+ if ((expressionType = expression.resolveType(scope)) != null)
+ scope.problemReporter().attemptToReturnNonVoidExpression(this, expressionType);
+ return;
+ }
+ if (expression == null) {
+ scope.problemReporter().shouldReturn(methodType, this);
+ return;
+ }
+ if ((expressionType = expression.resolveType(scope)) == null)
+ return;
+
+ if (expression
+ .isConstantValueOfTypeAssignableToType(expressionType, methodType)) {
+ // dealing with constant
+ expression.implicitWidening(methodType, expressionType);
+ return;
+ }
+ if (expressionType == VoidBinding) {
+ scope.problemReporter().attemptToReturnVoidValue(this);
+ return;
+ }
+ if (scope.areTypesCompatible(expressionType, methodType)) {
+ expression.implicitWidening(methodType, expressionType);
+ return;
+ }
+ scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
+ expression,
+ expressionType,
+ methodType);
+ }
+
+ public String toString(int tab) {
+ /* slow code */
+
+ String s = tabString(tab);
+ s = s + "return ";
+ if (expression != null)
+ s = s + expression.toStringExpression();
+ return s;
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ if (visitor.visit(this, scope)) {
+ if (expression != null)
+ expression.traverse(visitor, scope);
+ }
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java
new file mode 100644
index 0000000000..8f4948d588
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java
@@ -0,0 +1,799 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class SingleNameReference extends NameReference implements OperatorIds {
+ public char[] token;
+
+ public MethodBinding[] syntheticAccessors;
+ // [0]=read accessor [1]=write accessor
+ public static final int READ = 0;
+ public static final int WRITE = 1;
+ public SingleNameReference(char[] source, long pos) {
+ super();
+ token = source;
+ sourceStart = (int) (pos >>> 32);
+ sourceEnd = (int) pos;
+ }
+
+ public FlowInfo analyseAssignment(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo,
+ Assignment assignment,
+ boolean isCompound) {
+
+ // compound assignment extra work
+ if (isCompound) { // check the variable part is initialized if blank final
+ switch (bits & RestrictiveFlagMASK) {
+ case FIELD : // reading a field
+ FieldBinding fieldBinding;
+ if ((fieldBinding = (FieldBinding) binding).isFinal()
+ && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
+ if (!flowInfo.isDefinitelyAssigned(fieldBinding)) {
+ currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
+ // we could improve error msg here telling "cannot use compound assignment on final blank field"
+ }
+ }
+ manageSyntheticReadAccessIfNecessary(currentScope);
+ break;
+ case LOCAL : // reading a local variable
+ // check if assigning a final blank field
+ LocalVariableBinding localBinding;
+ if (!flowInfo
+ .isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
+ currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
+ // we could improve error msg here telling "cannot use compound assignment on final local variable"
+ }
+ if (!flowInfo.isFakeReachable())
+ localBinding.used = true;
+ }
+ }
+ if (assignment.expression != null) {
+ flowInfo =
+ assignment
+ .expression
+ .analyseCode(currentScope, flowContext, flowInfo)
+ .unconditionalInits();
+ }
+ switch (bits & RestrictiveFlagMASK) {
+ case FIELD : // assigning to a field
+ manageSyntheticWriteAccessIfNecessary(currentScope);
+
+ // check if assigning a final field
+ FieldBinding fieldBinding;
+ if ((fieldBinding = (FieldBinding) binding).isFinal()) {
+ // inside a context where allowed
+ if (currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
+ if (flowInfo.isPotentiallyAssigned(fieldBinding)) {
+ currentScope.problemReporter().duplicateInitializationOfBlankFinalField(
+ fieldBinding,
+ this);
+ }
+ flowInfo.markAsDefinitelyAssigned(fieldBinding);
+ flowContext.recordSettingFinal(fieldBinding, this);
+ } else {
+ currentScope.problemReporter().cannotAssignToFinalField(fieldBinding, this);
+ }
+ }
+ break;
+ case LOCAL : // assigning to a local variable
+ LocalVariableBinding localBinding = (LocalVariableBinding) binding;
+ if (!flowInfo.isDefinitelyAssigned(localBinding)) {
+ // for local variable debug attributes
+ bits |= FirstAssignmentToLocalMASK;
+ } else {
+ bits &= ~FirstAssignmentToLocalMASK;
+ }
+ if (localBinding.isFinal()) {
+ if ((bits & DepthMASK) == 0) {
+ if (flowInfo.isPotentiallyAssigned(localBinding)) {
+ currentScope.problemReporter().duplicateInitializationOfFinalLocal(
+ localBinding,
+ this);
+ }
+ flowContext.recordSettingFinal(localBinding, this);
+ } else {
+ currentScope.problemReporter().cannotAssignToFinalOuterLocal(
+ localBinding,
+ this);
+ }
+ }
+ flowInfo.markAsDefinitelyAssigned(localBinding);
+ }
+ manageEnclosingInstanceAccessIfNecessary(currentScope);
+ return flowInfo;
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ return analyseCode(currentScope, flowContext, flowInfo, true);
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo,
+ boolean valueRequired) {
+ switch (bits & RestrictiveFlagMASK) {
+ case FIELD : // reading a field
+ if (valueRequired) {
+ manageSyntheticReadAccessIfNecessary(currentScope);
+ }
+ // check if reading a final blank field
+ FieldBinding fieldBinding;
+ if ((fieldBinding = (FieldBinding) binding).isFinal()
+ && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
+ if (!flowInfo.isDefinitelyAssigned(fieldBinding)) {
+ currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
+ }
+ }
+ break;
+ case LOCAL : // reading a local variable
+ LocalVariableBinding localBinding;
+ if (!flowInfo
+ .isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
+ currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
+ }
+ if (!flowInfo.isFakeReachable())
+ localBinding.used = true;
+ }
+ if (valueRequired) {
+ manageEnclosingInstanceAccessIfNecessary(currentScope);
+ }
+ return flowInfo;
+ }
+
+ public TypeBinding checkFieldAccess(BlockScope scope) {
+
+ FieldBinding fieldBinding = (FieldBinding) binding;
+
+ bits &= ~RestrictiveFlagMASK; // clear bits
+ bits |= FIELD;
+ if (!((FieldBinding) binding).isStatic()) {
+ // must check for the static status....
+ if (scope.methodScope().isStatic) {
+ scope.problemReporter().staticFieldAccessToNonStaticVariable(
+ this,
+ fieldBinding);
+ constant = NotAConstant;
+ return null;
+ }
+ }
+ constant = FieldReference.getConstantFor(fieldBinding, true, this, 0);
+ if (isFieldUseDeprecated(fieldBinding, scope))
+ scope.problemReporter().deprecatedField(fieldBinding, this);
+ // if the binding declaring class is not visible, need special action
+ // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
+ if (fieldBinding.declaringClass != null
+ && fieldBinding.constant == NotAConstant
+ && !fieldBinding.declaringClass.canBeSeenBy(scope))
+ binding = new FieldBinding(fieldBinding, scope.enclosingSourceType());
+
+ //===============================================
+ //cycle are forbidden ONLY within the same class...why ?????? (poor javac....)
+ //Cycle can be done using cross class ref but not direct into a same class reference ????
+ //class A { static int k = B.k+1;}
+ //class B { static int k = A.k+2;}
+ //The k-cycle in this example is valid.
+
+ //class C { static int k = k + 1 ;}
+ //here it is forbidden ! ????
+ //but the next one is valid !!!
+ //class C { static int k = C.k + 1;}
+
+ //notice that the next one is also valid ?!?!
+ //class A { static int k = foo().k+1 ; static A foo(){return new A();}}
+
+ //for all these reasons, the next piece of code is only here and not
+ //commun for all FieldRef and QualifiedNameRef....(i.e. in the getField(..) API.....
+
+ //instance field may refer to forward static field, like in
+ //int i = staticI;
+ //static int staticI = 2 ;
+
+ MethodScope ms = scope.methodScope();
+ if (ms.enclosingSourceType() == fieldBinding.declaringClass
+ && ms.fieldDeclarationIndex != ms.NotInFieldDecl
+ && fieldBinding.id >= ms.fieldDeclarationIndex) {
+ //if the field is static and ms is not .... then it is valid
+ if (!fieldBinding.isStatic() || ms.isStatic)
+ scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType());
+ }
+ //====================================================
+
+ return fieldBinding.type;
+
+ }
+
+ public void generateAssignment(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Assignment assignment,
+ boolean valueRequired) {
+
+ // optimizing assignment like: i = i + 1 or i = 1 + i
+ if (assignment.expression.isCompactableOperation()) {
+ BinaryExpression operation = (BinaryExpression) assignment.expression;
+ SingleNameReference variableReference;
+ if ((operation.left instanceof SingleNameReference)
+ && ((variableReference = (SingleNameReference) operation.left).binding
+ == binding)) {
+ // i = i + value, then use the variable on the right hand side, since it has the correct implicit conversion
+ variableReference.generateCompoundAssignment(
+ currentScope,
+ codeStream,
+ syntheticAccessors == null ? null : syntheticAccessors[WRITE],
+ operation.right,
+ (operation.bits & OperatorMASK) >> OperatorSHIFT,
+ operation.left.implicitConversion /*should be equivalent to no conversion*/,
+ valueRequired);
+ return;
+ }
+ int operator = (operation.bits & OperatorMASK) >> OperatorSHIFT;
+ if ((operation.right instanceof SingleNameReference)
+ && ((operator == PLUS)
+ || (operator == MULTIPLY)) // only commutative operations
+ && ((variableReference = (SingleNameReference) operation.right).binding
+ == binding)
+ && (operation.left.constant != NotAConstant)
+ // exclude non constant expressions, since could have side-effect
+ && ((operation.implicitConversion >> 4) != T_String)) {
+ // exclude string concatenation which would occur backwards
+ // i = value + i, then use the variable on the right hand side, since it has the correct implicit conversion
+ variableReference.generateCompoundAssignment(
+ currentScope,
+ codeStream,
+ syntheticAccessors == null ? null : syntheticAccessors[WRITE],
+ operation.left,
+ operator,
+ operation.right.implicitConversion /*should be equivalent to no conversion*/,
+ valueRequired);
+ return;
+ }
+ }
+ switch (bits & RestrictiveFlagMASK) {
+ case FIELD : // assigning to a field
+ FieldBinding fieldBinding;
+ if (!(fieldBinding = (FieldBinding) binding).isStatic()) { // need a receiver?
+ if ((bits & DepthMASK) != 0) {
+ Object[] emulationPath =
+ currentScope.getExactEmulationPath(
+ currentScope.enclosingSourceType().enclosingTypeAt(
+ (bits & DepthMASK) >> DepthSHIFT));
+ if (emulationPath == null) {
+ // internal error, per construction we should have found it
+ currentScope.problemReporter().needImplementation();
+ } else {
+ codeStream.generateOuterAccess(emulationPath, this, currentScope);
+ }
+ } else {
+ this.generateReceiver(codeStream);
+ }
+ }
+ assignment.expression.generateCode(currentScope, codeStream, true);
+ fieldStore(
+ codeStream,
+ fieldBinding,
+ syntheticAccessors == null ? null : syntheticAccessors[WRITE],
+ valueRequired);
+ if (valueRequired) {
+ codeStream.generateImplicitConversion(assignment.implicitConversion);
+ }
+ return;
+ case LOCAL : // assigning to a local variable
+ LocalVariableBinding localBinding = (LocalVariableBinding) binding;
+ if (localBinding.resolvedPosition != -1) {
+ assignment.expression.generateCode(currentScope, codeStream, true);
+ } else {
+ if (assignment.expression.constant != NotAConstant) {
+ // assigning an unused local to a constant value = no actual assignment is necessary
+ if (valueRequired) {
+ codeStream.generateConstant(
+ assignment.expression.constant,
+ assignment.implicitConversion);
+ }
+ } else {
+ assignment.expression.generateCode(currentScope, codeStream, true);
+ /* Even though the value may not be required, we force it to be produced, and discard it later
+ on if it was actually not necessary, so as to provide the same behavior as JDK1.2beta3. */
+ if (valueRequired) {
+ codeStream.generateImplicitConversion(assignment.implicitConversion);
+ // implicit conversion
+ } else {
+ if ((localBinding.type == LongBinding)
+ || (localBinding.type == DoubleBinding)) {
+ codeStream.pop2();
+ } else {
+ codeStream.pop();
+ }
+ }
+ }
+ return;
+ }
+ // normal local assignment (since cannot store in outer local which are final locations)
+ codeStream.store(localBinding, valueRequired);
+ if ((bits & FirstAssignmentToLocalMASK) != 0) {
+ // for local variable debug attributes
+ localBinding.recordInitializationStartPC(codeStream.position);
+ }
+ // implicit conversion
+ if (valueRequired) {
+ codeStream.generateImplicitConversion(assignment.implicitConversion);
+ }
+ }
+ }
+
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ if (constant != NotAConstant) {
+ if (valueRequired) {
+ codeStream.generateConstant(constant, implicitConversion);
+ }
+ } else {
+ switch (bits & RestrictiveFlagMASK) {
+ case FIELD : // reading a field
+ FieldBinding fieldBinding;
+ if (valueRequired) {
+ if ((fieldBinding = (FieldBinding) binding).constant == NotAConstant) {
+ // directly use inlined value for constant fields
+ boolean isStatic;
+ if (!(isStatic = fieldBinding.isStatic())) {
+ if ((bits & DepthMASK) != 0) {
+ Object[] emulationPath =
+ currentScope.getExactEmulationPath(
+ currentScope.enclosingSourceType().enclosingTypeAt(
+ (bits & DepthMASK) >> DepthSHIFT));
+ if (emulationPath == null) {
+ // internal error, per construction we should have found it
+ currentScope.problemReporter().needImplementation();
+ } else {
+ codeStream.generateOuterAccess(emulationPath, this, currentScope);
+ }
+ } else {
+ generateReceiver(codeStream);
+ }
+ }
+ // managing private access
+ if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
+ if (isStatic) {
+ codeStream.getstatic(fieldBinding);
+ } else {
+ codeStream.getfield(fieldBinding);
+ }
+ } else {
+ codeStream.invokestatic(syntheticAccessors[READ]);
+ }
+ codeStream.generateImplicitConversion(implicitConversion);
+ } else { // directly use the inlined value
+ codeStream.generateConstant(fieldBinding.constant, implicitConversion);
+ }
+ }
+ break;
+ case LOCAL : // reading a local
+ LocalVariableBinding localBinding = (LocalVariableBinding) binding;
+ if (valueRequired) {
+ // outer local?
+ if ((bits & DepthMASK) != 0) {
+ // outer local can be reached either through a synthetic arg or a synthetic field
+ VariableBinding[] path = currentScope.getEmulationPath(localBinding);
+ if (path == null) {
+ // emulation was not possible (should not happen per construction)
+ currentScope.problemReporter().needImplementation();
+ } else {
+ codeStream.generateOuterAccess(path, this, currentScope);
+ }
+ } else {
+ // regular local variable read
+ codeStream.load(localBinding);
+ }
+ codeStream.generateImplicitConversion(implicitConversion);
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ /*
+ * Regular API for compound assignment, relies on the fact that there is only one reference to the
+ * variable, which carries both synthetic read/write accessors.
+ * The APIs with an extra argument is used whenever there are two references to the same variable which
+ * are optimized in one access: e.g "a = a + 1" optimized into "a++".
+ */
+ public void generateCompoundAssignment(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Expression expression,
+ int operator,
+ int assignmentImplicitConversion,
+ boolean valueRequired) {
+
+ this.generateCompoundAssignment(
+ currentScope,
+ codeStream,
+ syntheticAccessors == null ? null : syntheticAccessors[WRITE],
+ expression,
+ operator,
+ assignmentImplicitConversion,
+ valueRequired);
+ }
+
+ /*
+ * The APIs with an extra argument is used whenever there are two references to the same variable which
+ * are optimized in one access: e.g "a = a + 1" optimized into "a++".
+ */
+ public void generateCompoundAssignment(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ MethodBinding writeAccessor,
+ Expression expression,
+ int operator,
+ int assignmentImplicitConversion,
+ boolean valueRequired) {
+ switch (bits & RestrictiveFlagMASK) {
+ case FIELD : // assigning to a field
+ FieldBinding fieldBinding;
+ if ((fieldBinding = (FieldBinding) binding).isStatic()) {
+ if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
+ codeStream.getstatic(fieldBinding);
+ } else {
+ codeStream.invokestatic(syntheticAccessors[READ]);
+ }
+ } else {
+ if ((bits & DepthMASK) != 0) {
+ Object[] emulationPath =
+ currentScope.getExactEmulationPath(
+ currentScope.enclosingSourceType().enclosingTypeAt(
+ (bits & DepthMASK) >> DepthSHIFT));
+ if (emulationPath == null) {
+ // internal error, per construction we should have found it
+ currentScope.problemReporter().needImplementation();
+ } else {
+ codeStream.generateOuterAccess(emulationPath, this, currentScope);
+ }
+ } else {
+ codeStream.aload_0();
+ }
+ codeStream.dup();
+ if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
+ codeStream.getfield(fieldBinding);
+ } else {
+ codeStream.invokestatic(syntheticAccessors[READ]);
+ }
+ }
+ break;
+ case LOCAL : // assigning to a local variable (cannot assign to outer local)
+ LocalVariableBinding localBinding = (LocalVariableBinding) binding;
+ Constant assignConstant;
+ int increment;
+ // using incr bytecode if possible
+ switch (localBinding.type.id) {
+ case T_String :
+ codeStream.generateStringAppend(currentScope, this, expression);
+ if (valueRequired) {
+ codeStream.dup();
+ }
+ codeStream.store(localBinding, false);
+ return;
+ case T_int :
+ if (((assignConstant = expression.constant) != NotAConstant)
+ && ((increment = assignConstant.intValue()) == (short) increment)) {
+ // 16 bits value
+ switch (operator) {
+ case PLUS :
+ codeStream.iinc(localBinding.resolvedPosition, increment);
+ if (valueRequired) {
+ codeStream.load(localBinding);
+ }
+ return;
+ case MINUS :
+ codeStream.iinc(localBinding.resolvedPosition, -increment);
+ if (valueRequired) {
+ codeStream.load(localBinding);
+ }
+ return;
+ }
+ }
+ default :
+ codeStream.load(localBinding);
+ }
+ }
+ // perform the actual compound operation
+ int operationTypeID;
+ if ((operationTypeID = implicitConversion >> 4) == T_String) {
+ codeStream.generateStringAppend(currentScope, null, expression);
+ } else {
+ // promote the array reference to the suitable operation type
+ codeStream.generateImplicitConversion(implicitConversion);
+ // generate the increment value (will by itself be promoted to the operation value)
+ if (expression == IntLiteral.One) { // prefix operation
+ codeStream.generateConstant(expression.constant, implicitConversion);
+ } else {
+ expression.generateCode(currentScope, codeStream, true);
+ }
+ // perform the operation
+ codeStream.sendOperator(operator, operationTypeID);
+ // cast the value back to the array reference type
+ codeStream.generateImplicitConversion(assignmentImplicitConversion);
+ }
+ // store the result back into the variable
+ switch (bits & RestrictiveFlagMASK) {
+ case FIELD : // assigning to a field
+ fieldStore(codeStream, (FieldBinding) binding, writeAccessor, valueRequired);
+ return;
+ case LOCAL : // assigning to a local variable
+ LocalVariableBinding localBinding = (LocalVariableBinding) binding;
+ if (valueRequired) {
+ if ((localBinding.type == LongBinding)
+ || (localBinding.type == DoubleBinding)) {
+ codeStream.dup2();
+ } else {
+ codeStream.dup();
+ }
+ }
+ codeStream.store(localBinding, false);
+ }
+ }
+
+ public void generatePostIncrement(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ CompoundAssignment postIncrement,
+ boolean valueRequired) {
+ switch (bits & RestrictiveFlagMASK) {
+ case FIELD : // assigning to a field
+ FieldBinding fieldBinding;
+ if ((fieldBinding = (FieldBinding) binding).isStatic()) {
+ if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
+ codeStream.getstatic(fieldBinding);
+ } else {
+ codeStream.invokestatic(syntheticAccessors[READ]);
+ }
+ } else {
+ if ((bits & DepthMASK) != 0) {
+ Object[] emulationPath =
+ currentScope.getExactEmulationPath(
+ currentScope.enclosingSourceType().enclosingTypeAt(
+ (bits & DepthMASK) >> DepthSHIFT));
+ if (emulationPath == null) {
+ // internal error, per construction we should have found it
+ currentScope.problemReporter().needImplementation();
+ } else {
+ codeStream.generateOuterAccess(emulationPath, this, currentScope);
+ }
+ } else {
+ codeStream.aload_0();
+ }
+ codeStream.dup();
+ if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
+ codeStream.getfield(fieldBinding);
+ } else {
+ codeStream.invokestatic(syntheticAccessors[READ]);
+ }
+ }
+ if (valueRequired) {
+ if (fieldBinding.isStatic()) {
+ if ((fieldBinding.type == LongBinding)
+ || (fieldBinding.type == DoubleBinding)) {
+ codeStream.dup2();
+ } else {
+ codeStream.dup();
+ }
+ } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value]
+ if ((fieldBinding.type == LongBinding)
+ || (fieldBinding.type == DoubleBinding)) {
+ codeStream.dup2_x1();
+ } else {
+ codeStream.dup_x1();
+ }
+ }
+ }
+ codeStream.generateConstant(
+ postIncrement.expression.constant,
+ implicitConversion);
+ codeStream.sendOperator(postIncrement.operator, fieldBinding.type.id);
+ codeStream.generateImplicitConversion(
+ postIncrement.assignmentImplicitConversion);
+ fieldStore(
+ codeStream,
+ fieldBinding,
+ syntheticAccessors == null ? null : syntheticAccessors[WRITE],
+ false);
+ return;
+ case LOCAL : // assigning to a local variable
+ LocalVariableBinding localBinding = (LocalVariableBinding) binding;
+ // using incr bytecode if possible
+ if (localBinding.type == IntBinding) {
+ if (valueRequired) {
+ codeStream.load(localBinding);
+ }
+ if (postIncrement.operator == PLUS) {
+ codeStream.iinc(localBinding.resolvedPosition, 1);
+ } else {
+ codeStream.iinc(localBinding.resolvedPosition, -1);
+ }
+ } else {
+ codeStream.load(localBinding);
+ if (valueRequired) {
+ if ((localBinding.type == LongBinding)
+ || (localBinding.type == DoubleBinding)) {
+ codeStream.dup2();
+ } else {
+ codeStream.dup();
+ }
+ }
+ codeStream.generateConstant(
+ postIncrement.expression.constant,
+ implicitConversion);
+ codeStream.sendOperator(postIncrement.operator, localBinding.type.id);
+ codeStream.generateImplicitConversion(
+ postIncrement.assignmentImplicitConversion);
+
+ codeStream.store(localBinding, false);
+ }
+ }
+ }
+
+ public void generateReceiver(CodeStream codeStream) {
+ codeStream.aload_0();
+ }
+
+ public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
+
+ //If inlinable field, forget the access emulation, the code gen will directly target it
+ if (((bits & DepthMASK) == 0) || (constant != NotAConstant))
+ return;
+
+ switch (bits & RestrictiveFlagMASK) {
+ case FIELD :
+ FieldBinding fieldBinding;
+ if ((fieldBinding = (FieldBinding) binding).isStatic()
+ || (fieldBinding.constant != NotAConstant))
+ return;
+ ReferenceBinding compatibleType = currentScope.enclosingSourceType();
+ // the declaringClass of the target binding must be compatible with the enclosing
+ // type at <depth> levels outside
+ for (int i = 0, depth = (bits & DepthMASK) >> DepthSHIFT; i < depth; i++) {
+ compatibleType = compatibleType.enclosingType();
+ }
+ currentScope.emulateOuterAccess(compatibleType, false);
+ // request cascade of accesses
+ break;
+ case LOCAL :
+ currentScope.emulateOuterAccess((LocalVariableBinding) binding);
+ }
+ }
+
+ public void manageSyntheticReadAccessIfNecessary(BlockScope currentScope) {
+
+ //If inlinable field, forget the access emulation, the code gen will directly target it
+ if (constant != NotAConstant)
+ return;
+
+ if ((bits & FIELD) != 0) {
+ FieldBinding fieldBinding = (FieldBinding) binding;
+ if (((bits & DepthMASK) != 0)
+ && (fieldBinding.isPrivate() // private access
+ || (fieldBinding.isProtected() // implicit protected access
+ && fieldBinding.declaringClass.getPackage()
+ != currentScope.enclosingSourceType().getPackage()))) {
+ if (syntheticAccessors == null)
+ syntheticAccessors = new MethodBinding[2];
+ syntheticAccessors[READ] =
+ (
+ (SourceTypeBinding) currentScope.enclosingSourceType().enclosingTypeAt(
+ (bits & DepthMASK) >> DepthSHIFT)).addSyntheticMethod(
+ fieldBinding,
+ true);
+ currentScope.problemReporter().needToEmulateFieldReadAccess(fieldBinding, this);
+ }
+ }
+ }
+
+ public void manageSyntheticWriteAccessIfNecessary(BlockScope currentScope) {
+
+ if ((bits & FIELD) != 0) {
+ FieldBinding fieldBinding = (FieldBinding) binding;
+ if (((bits & DepthMASK) != 0)
+ && (fieldBinding.isPrivate() // private access
+ || (fieldBinding.isProtected() // implicit protected access
+ && fieldBinding.declaringClass.getPackage()
+ != currentScope.enclosingSourceType().getPackage()))) {
+ if (syntheticAccessors == null)
+ syntheticAccessors = new MethodBinding[2];
+ syntheticAccessors[WRITE] =
+ (
+ (SourceTypeBinding) currentScope.enclosingSourceType().enclosingTypeAt(
+ (bits & DepthMASK) >> DepthSHIFT)).addSyntheticMethod(
+ fieldBinding,
+ false);
+ currentScope.problemReporter().needToEmulateFieldWriteAccess(
+ fieldBinding,
+ this);
+ }
+ }
+ }
+
+ public TypeBinding reportError(BlockScope scope) {
+ //=====error cases=======
+ constant = Constant.NotAConstant;
+ if (binding instanceof ProblemFieldBinding) {
+ scope.problemReporter().invalidField(this, (FieldBinding) binding);
+ } else
+ if (binding instanceof ProblemReferenceBinding) {
+ scope.problemReporter().invalidType(this, (TypeBinding) binding);
+ } else {
+ scope.problemReporter().unresolvableReference(this, binding);
+ }
+ return null;
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ // for code gen, harm the restrictiveFlag
+
+ if ((binding = scope.getBinding(token, bits & RestrictiveFlagMASK, this))
+ .isValidBinding()) {
+ switch (bits & RestrictiveFlagMASK) {
+ case VARIABLE : // =========only variable============
+ case VARIABLE | TYPE : //====both variable and type============
+ if (binding instanceof VariableBinding) {
+ VariableBinding vb = (VariableBinding) binding;
+ if (binding instanceof LocalVariableBinding) {
+ bits &= ~RestrictiveFlagMASK; // clear bits
+ bits |= LOCAL;
+ constant = vb.constant;
+ if ((!vb.isFinal()) && ((bits & DepthMASK) != 0))
+ scope.problemReporter().cannotReferToNonFinalOuterLocal(
+ (LocalVariableBinding) vb,
+ this);
+ return vb.type;
+ }
+ // a field
+ return checkFieldAccess(scope);
+ }
+
+ // thus it was a type
+ bits &= ~RestrictiveFlagMASK; // clear bits
+ bits |= TYPE;
+ case TYPE : //========only type==============
+ constant = Constant.NotAConstant;
+ //deprecated test
+ if (isTypeUseDeprecated((TypeBinding) binding, scope))
+ scope.problemReporter().deprecatedType((TypeBinding) binding, this);
+ return (TypeBinding) binding;
+ }
+ }
+
+ // error scenarii
+ return this.reportError(scope);
+ }
+
+ public String toStringExpression() {
+
+ return new String(token);
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ visitor.visit(this, scope);
+ visitor.endVisit(this, scope);
+ }
+
+ public String unboundReferenceErrorName() {
+
+ return new String(token);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java
new file mode 100644
index 0000000000..d3abb9345d
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java
@@ -0,0 +1,74 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class SingleTypeReference extends TypeReference {
+ public char[] token;
+
+ public SingleTypeReference(char[] source, long pos) {
+ token = source;
+ sourceStart = (int) (pos >>> 32);
+ sourceEnd = (int) (pos & 0x00000000FFFFFFFFL);
+
+ }
+
+ public SingleTypeReference(char[] source, TypeBinding tb, long pos) {
+ this(source, pos);
+ binding = tb;
+ }
+
+ public TypeReference copyDims(int dim) {
+ //return a type reference copy of me with some dimensions
+ //warning : the new type ref has a null binding
+
+ return new ArrayTypeReference(
+ token,
+ null,
+ dim,
+ (((long) sourceStart) << 32) + sourceEnd);
+ }
+
+ public TypeBinding getTypeBinding(Scope scope) {
+ if (binding != null)
+ return binding;
+ return scope.getType(token);
+ }
+
+ public char[][] getTypeName() {
+ return new char[][] { token };
+ }
+
+ public TypeBinding resolveTypeEnclosing(
+ BlockScope scope,
+ ReferenceBinding enclosingType) {
+ ReferenceBinding memberTb = scope.getMemberType(token, enclosingType);
+ if (!memberTb.isValidBinding()) {
+ scope.problemReporter().invalidEnclosingType(this, memberTb, enclosingType);
+ return null;
+ }
+ if (isTypeUseDeprecated(memberTb, scope))
+ scope.problemReporter().deprecatedType(memberTb, this);
+ return binding = memberTb;
+ }
+
+ public String toStringExpression(int tab) {
+ return new String(token);
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ visitor.visit(this, scope);
+ visitor.endVisit(this, scope);
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, ClassScope scope) {
+ visitor.visit(this, scope);
+ visitor.endVisit(this, scope);
+ }
+
+}
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
new file mode 100644
index 0000000000..4d8b142dfd
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
@@ -0,0 +1,123 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+public abstract class Statement extends AstNode {
+ // storage for internal flags (32 bits)
+ public int bits = IsReachableMASK; // reachable by default
+
+ // for operators only
+ // Reach . . . . . . . . . . . . . . . . . O O O O O O V VrR R R R
+ public static final int ReturnTypeIDMASK = 15; // 4 lower bits for operators
+ public static final int ValueForReturnMASK = 16; // for binary expressions
+ public static final int OnlyValueRequiredMASK = 32; // for binary expressions
+ public static final int OperatorSHIFT = 6;
+ public static final int OperatorMASK = 63 << OperatorSHIFT;
+
+ // for name references only
+ // Reach . . . . . . . . . . . . . . . . D D D D D D D D VrF R R R
+ public static final int RestrictiveFlagMASK = 7;
+ // 3 lower bits for name references
+ public static final int FirstAssignmentToLocalMASK = 8;
+ // for single name references
+ public static final int DepthSHIFT = 5;
+ public static final int DepthMASK = 0xFF << DepthSHIFT;
+ // 8 bits for actual depth value (max. 255)
+
+ // for statements only
+ public static final int IsReachableMASK = 0x80000000; // highest bit
+
+ /*
+ public final static int BitMask1= 0x1; // decimal 1
+ public final static int BitMask2= 0x2; // decimal 2
+ public final static int BitMask3= 0x4; // decimal 4
+ public final static int BitMask4= 0x8; // decimal 8
+ public final static int BitMask5= 0x10; // decimal 16
+ public final static int BitMask6= 0x20; // decimal 32
+ public final static int BitMask7= 0x40; // decimal 64
+ public final static int BitMask8= 0x80; // decimal 128
+ public final static int BitMask9= 0x100; // decimal 256
+ public final static int BitMask10= 0x200; // decimal 512
+ public final static int BitMask11= 0x400; // decimal 1024
+ public final static int BitMask12= 0x800; // decimal 2048
+ public final static int BitMask13= 0x1000; // decimal 4096
+ public final static int BitMask14= 0x2000; // decimal 8192
+ public final static int BitMask15= 0x4000; // decimal 16384
+ public final static int BitMask16= 0x8000; // decimal 32768
+ public final static int BitMask17= 0x10000; // decimal 65536
+ public final static int BitMask18= 0x20000; // decimal 131072
+ public final static int BitMask19= 0x40000; // decimal 262144
+ public final static int BitMask20= 0x80000; // decimal 524288
+ public final static int BitMask21= 0x100000; // decimal 1048576
+ public final static int BitMask22= 0x200000; // decimal 2097152
+ public final static int BitMask23= 0x400000; // decimal 4194304
+ public final static int BitMask24= 0x800000; // decimal 8388608
+ public final static int BitMask25= 0x1000000; // decimal 16777216
+ public final static int BitMask26= 0x2000000; // decimal 33554432
+ public final static int BitMask27= 0x4000000; // decimal 67108864
+ public final static int BitMask28= 0x8000000; // decimal 134217728
+ public final static int BitMask29= 0x10000000; // decimal 268435456
+ public final static int BitMask30= 0x20000000; // decimal 536870912
+ public final static int BitMask31= 0x40000000; // decimal 1073741824
+ public final static int BitMask32= 0x80000000; // decimal 2147483648
+ */
+ /**
+ * Statement constructor comment.
+ */
+ public Statement() {
+ super();
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ return flowInfo;
+ }
+
+ public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+ throw new ShouldNotImplement("Missing statement code generation implementation");
+ }
+
+ public boolean isEmptyBlock() {
+ return false;
+ }
+
+ public boolean isValidJavaStatement() {
+ //the use of this method should be avoid in most cases
+ //and is here mostly for documentation purpose.....
+ //while the parser is responsable for creating
+ //welled formed expression statement, which results
+ //in the fact that java-non-semantic-expression-used-as-statement
+ //should not be parsable...thus not being built.
+ //It sounds like the java grammar as help the compiler job in removing
+ //-by construction- some statement that would have no effect....
+ //(for example all expression that may do side-effects are valid statement
+ // -this is an appromative idea.....-)
+
+ return true;
+ }
+
+ public void resolve(BlockScope scope) {
+ }
+
+ public Constant resolveCase(
+ BlockScope scope,
+ TypeBinding testType,
+ SwitchStatement switchStatement) {
+ // statement within a switch that are not case are treated as normal statement....
+
+ resolve(scope);
+ return null;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/StringLiteral.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/StringLiteral.java
new file mode 100644
index 0000000000..bf67c9792c
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/StringLiteral.java
@@ -0,0 +1,112 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class StringLiteral extends Literal {
+ char[] source;
+
+ public StringLiteral(char[] token, int s, int e) {
+ this(s, e);
+ source = token;
+ }
+
+ public StringLiteral(int s, int e) {
+ super(s, e);
+ }
+
+ public void computeConstant() {
+
+ constant = Constant.fromValue(String.valueOf(source));
+ }
+
+ public ExtendedStringLiteral extendWith(CharLiteral lit) {
+ //add the lit source to mine, just as if it was mine
+
+ return new ExtendedStringLiteral(this, lit);
+ }
+
+ public ExtendedStringLiteral extendWith(StringLiteral lit) {
+ //add the lit source to mine, just as if it was mine
+
+ return new ExtendedStringLiteral(this, lit);
+ }
+
+ /**
+ * Code generation for string literal
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param valueRequired boolean
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ if (valueRequired)
+ codeStream.ldc(constant.stringValue());
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public TypeBinding literalType(BlockScope scope) {
+ return scope.getJavaLangString();
+ }
+
+ /**
+ * source method comment.
+ */
+ public char[] source() {
+ return source;
+ }
+
+ public String toStringExpression() {
+
+ // handle some special char.....
+ StringBuffer result = new StringBuffer("\"");
+ for (int i = 0; i < source.length; i++) {
+ switch (source[i]) {
+ case '\b' :
+ result.append("\\b");
+ break;
+ case '\t' :
+ result.append("\\t");
+ break;
+ case '\n' :
+ result.append("\\n");
+ break;
+ case '\f' :
+ result.append("\\f");
+ break;
+ case '\r' :
+ result.append("\\r");
+ break;
+ case '\"' :
+ result.append("\\\"");
+ break;
+ case '\'' :
+ result.append("\\'");
+ break;
+ case '\\' : //take care not to display the escape as a potential real char
+ result.append("\\\\");
+ break;
+ default :
+ result.append(source[i]);
+ }
+ }
+ result.append("\"");
+ return result.toString();
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ visitor.visit(this, scope);
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SuperReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SuperReference.java
new file mode 100644
index 0000000000..80eb92f8a9
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SuperReference.java
@@ -0,0 +1,66 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class SuperReference extends ThisReference {
+ public static final SuperReference Super = new SuperReference();
+
+ /**
+ * SuperReference constructor comment.
+ */
+ public SuperReference() {
+ super();
+ }
+
+ public SuperReference(int pos, int sourceEnd) {
+ super();
+ sourceStart = pos;
+ this.sourceEnd = sourceEnd;
+ }
+
+ public static ExplicitConstructorCall implicitSuperConstructorCall() {
+ return new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper);
+ }
+
+ public boolean isSuper() {
+
+ return true;
+ }
+
+ public boolean isThis() {
+
+ return false;
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ constant = NotAConstant;
+ if (!checkAccess(scope.methodScope()))
+ return null;
+ SourceTypeBinding enclosingTb = scope.enclosingSourceType();
+ if (scope.isJavaLangObject(enclosingTb)) {
+ scope.problemReporter().cannotUseSuperInJavaLangObject(this);
+ return null;
+ }
+ return enclosingTb.superclass;
+ }
+
+ public String toStringExpression() {
+
+ return "super";
+
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ visitor.visit(this, blockScope);
+ visitor.endVisit(this, blockScope);
+ }
+
+}
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
new file mode 100644
index 0000000000..a7d44e7f0f
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
@@ -0,0 +1,293 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class SwitchStatement extends Statement {
+ public Expression testExpression;
+ public Statement[] statements;
+ public BlockScope scope;
+ public int explicitDeclarations;
+ public Label breakLabel;
+ public Case[] cases;
+ public DefaultCase defaultCase;
+ public int caseCount = 0;
+
+ // for local variables table attributes
+ int preSwitchInitStateIndex = -1;
+ int mergedInitStateIndex = -1;
+ /**
+ * SwitchStatement constructor comment.
+ */
+ public SwitchStatement() {
+ super();
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ flowInfo = testExpression.analyseCode(currentScope, flowContext, flowInfo);
+ SwitchFlowContext switchContext =
+ new SwitchFlowContext(flowContext, this, (breakLabel = new Label()));
+
+ // analyse the block by considering specially the case/default statements (need to bind them
+ // to the entry point)
+ FlowInfo caseInits = FlowInfo.DeadEnd;
+ // in case of statements before the first case
+ preSwitchInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(flowInfo);
+ int caseIndex = 0;
+ if (statements != null) {
+ for (int i = 0, max = statements.length; i < max; i++) {
+ Statement statement = statements[i];
+ if ((caseIndex < caseCount)
+ && (statement == cases[caseIndex])) {
+ // statements[i] is a case or a default case
+ caseIndex++;
+ caseInits = caseInits.mergedWith(flowInfo.copy().unconditionalInits());
+ } else {
+ if (statement == defaultCase) {
+ caseInits = caseInits.mergedWith(flowInfo.copy().unconditionalInits());
+ }
+ }
+ if (!caseInits.complainIfUnreachable(statement, scope)) {
+ caseInits = statement.analyseCode(scope, switchContext, caseInits);
+ }
+ }
+ }
+
+ // if no default case, then record it may jump over the block directly to the end
+ if (defaultCase == null) {
+ // only retain the potential initializations
+ flowInfo.addPotentialInitializationsFrom(
+ caseInits.mergedWith(switchContext.initsOnBreak));
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(flowInfo);
+ return flowInfo;
+ }
+
+ // merge all branches inits
+ FlowInfo mergedInfo = caseInits.mergedWith(switchContext.initsOnBreak);
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(mergedInfo);
+ return mergedInfo;
+ }
+
+ /**
+ * Switch code generation
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ */
+ public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+ int[] sortedIndexes = new int[caseCount];
+ int[] localKeysCopy;
+ if ((bits & IsReachableMASK) == 0) {
+ return;
+ }
+ int pc = codeStream.position;
+
+ // prepare the labels and constants
+ breakLabel.codeStream = codeStream;
+ CaseLabel[] caseLabels = new CaseLabel[caseCount];
+ int[] constants = new int[caseCount];
+ boolean needSwitch = caseCount != 0;
+ for (int i = 0; i < caseCount; i++) {
+ constants[i] = cases[i].constantExpression.constant.intValue();
+ cases[i].targetLabel = (caseLabels[i] = new CaseLabel(codeStream));
+ }
+
+ // we sort the keys to be able to generate the code for tableswitch or lookupswitch
+ for (int i = 0; i < caseCount; i++) {
+ sortedIndexes[i] = i;
+ }
+ System.arraycopy(
+ constants,
+ 0,
+ (localKeysCopy = new int[caseCount]),
+ 0,
+ caseCount);
+ CodeStream.sort(localKeysCopy, 0, caseCount - 1, sortedIndexes);
+ CaseLabel defaultLabel = new CaseLabel(codeStream);
+ if (defaultCase != null) {
+ defaultCase.targetLabel = defaultLabel;
+ }
+ // generate expression testes
+ testExpression.generateCode(currentScope, codeStream, needSwitch);
+
+ // generate the appropriate switch table
+ if (needSwitch) {
+ int max = localKeysCopy[caseCount - 1];
+ int min = localKeysCopy[0];
+ if ((long) (caseCount * 2.5) > ((long) max - (long) min)) {
+ codeStream.tableswitch(
+ defaultLabel,
+ min,
+ max,
+ constants,
+ sortedIndexes,
+ caseLabels);
+ } else {
+ codeStream.lookupswitch(defaultLabel, constants, sortedIndexes, caseLabels);
+ }
+ codeStream.updateLastRecordedEndPC(codeStream.position);
+ }
+ // generate the switch block statements
+ int caseIndex = 0;
+ if (statements != null) {
+ for (int i = 0, maxCases = statements.length; i < maxCases; i++) {
+ Statement statement = statements[i];
+ if ((caseIndex < caseCount)
+ && (statement == cases[caseIndex])) { // statements[i] is a case
+ if (preSwitchInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ preSwitchInitStateIndex);
+ caseIndex++;
+ }
+ } else {
+ if (statement == defaultCase) { // statements[i] is a case or a default case
+ if (preSwitchInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ preSwitchInitStateIndex);
+ }
+ }
+ }
+ statement.generateCode(scope, codeStream);
+ }
+ }
+ // place the trailing labels (for break and default case)
+ breakLabel.place();
+ if (defaultCase == null) {
+ defaultLabel.place();
+ }
+ // May loose some local variable initializations : affecting the local variable attributes
+ if (mergedInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ mergedInitStateIndex);
+ codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex);
+ }
+ if (scope != currentScope) {
+ codeStream.exitUserScope(scope);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public void resolve(BlockScope upperScope) {
+ TypeBinding testType = testExpression.resolveType(upperScope);
+ if (testType == null)
+ return;
+ testExpression.implicitWidening(testType, testType);
+ if (!(testExpression
+ .isConstantValueOfTypeAssignableToType(testType, IntBinding))) {
+ if (!upperScope.areTypesCompatible(testType, IntBinding)) {
+ upperScope.problemReporter().incorrectSwitchType(testExpression, testType);
+ return;
+ }
+ }
+ if (statements != null) {
+ scope = explicitDeclarations == 0 ? upperScope : new BlockScope(upperScope);
+ int length;
+ // collection of cases is too big but we will only iterate until caseCount
+ cases = new Case[length = statements.length];
+ int[] casesValues = new int[length];
+ int counter = 0;
+ for (int i = 0; i < length; i++) {
+ Constant cst;
+ if ((cst = statements[i].resolveCase(scope, testType, this)) != null) {
+ //----check for duplicate case statement------------
+ if (cst != NotAConstant) {
+ // a case with a welled typed constant, so intValue() is valid
+ int key = cst.intValue();
+ for (int j = 0; j < counter; j++) {
+ if (casesValues[j] == key) {
+ scope.problemReporter().duplicateCase((Case) statements[i], cst);
+ }
+ }
+ casesValues[counter++] = key;
+ }
+ }
+ }
+ }
+ }
+
+ public String toString(int tab) {
+ /* slow code */
+
+ String inFront, s = tabString(tab);
+ inFront = s;
+ s = s + "switch (" + testExpression.toStringExpression() + ") ";
+ if (statements == null) {
+ s = s + "{}";
+ return s;
+ } else
+ s = s + "{";
+
+ s =
+ s
+ + (explicitDeclarations != 0
+ ? "// ---scope needed for "
+ + String.valueOf(explicitDeclarations)
+ + " locals------------ \n"
+ : "// ---NO scope needed------ \n");
+
+ int i = 0;
+ String tabulation = " ";
+ try {
+ while (true) {
+ //use instanceof in order not to polluate classes with behavior only needed for printing purpose.
+ if (statements[i] instanceof Expression)
+ s = s + "\n" + inFront + tabulation;
+ if (statements[i] instanceof Break)
+ s = s + statements[i].toString(0);
+ else
+ s = s + "\n" + statements[i].toString(tab + 2);
+ //=============
+ if ((statements[i] instanceof Case)
+ || (statements[i] instanceof DefaultCase)) {
+ i++;
+ while (!((statements[i] instanceof Case)
+ || (statements[i] instanceof DefaultCase))) {
+ if ((statements[i] instanceof Expression) || (statements[i] instanceof Break))
+ s = s + statements[i].toString(0) + " ; ";
+ else
+ s = s + "\n" + statements[i].toString(tab + 6) + " ; ";
+ i++;
+ }
+ } else {
+ s = s + " ;";
+ i++;
+ }
+ }
+ } catch (IndexOutOfBoundsException e) {
+ };
+ s = s + "}";
+ return s;
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ if (visitor.visit(this, blockScope)) {
+ testExpression.traverse(visitor, scope);
+ if (statements != null) {
+ int statementsLength = statements.length;
+ for (int i = 0; i < statementsLength; i++)
+ statements[i].traverse(visitor, scope);
+ }
+ }
+ visitor.endVisit(this, blockScope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java
new file mode 100644
index 0000000000..e3132bbc26
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java
@@ -0,0 +1,160 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class SynchronizedStatement extends Statement {
+ public Expression expression;
+ public Block block;
+ public BlockScope scope;
+
+ boolean blockExit;
+ public LocalVariableBinding synchroVariable;
+ static final char[] SecretLocalDeclarationName = " syncValue".toCharArray();
+
+ public SynchronizedStatement(
+ Expression expression,
+ Block statement,
+ int s,
+ int e) {
+ this.expression = expression;
+ this.block = statement;
+ sourceEnd = e;
+ sourceStart = s;
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+
+ // mark the synthetic variable as being used
+ synchroVariable.used = true;
+
+ // simple propagation to subnodes
+ flowInfo =
+ block.analyseCode(
+ scope,
+ new InsideSubRoutineFlowContext(flowContext, this),
+ expression.analyseCode(scope, flowContext, flowInfo));
+
+ // optimizing code gen
+ if ((flowInfo == FlowInfo.DeadEnd) || flowInfo.isFakeReachable()) {
+ blockExit = true;
+ }
+ return flowInfo;
+ }
+
+ /**
+ * Synchronized statement code generation
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ */
+ public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+ if ((bits & IsReachableMASK) == 0) {
+ return;
+ }
+ int pc = codeStream.position;
+
+ // generate the synchronization expression
+ expression.generateCode(scope, codeStream, true);
+ if (block.isEmptyBlock()) {
+ if ((synchroVariable.type == LongBinding)
+ || (synchroVariable.type == DoubleBinding)) {
+ codeStream.dup2();
+ } else {
+ codeStream.dup();
+ }
+ // only take the lock
+ codeStream.monitorenter();
+ codeStream.monitorexit();
+ } else {
+ // enter the monitor
+ codeStream.store(synchroVariable, true);
+ codeStream.monitorenter();
+
+ // generate the body of the synchronized block
+ ExceptionLabel anyExceptionHandler = new ExceptionLabel(codeStream, null);
+ //'null' denotes any kind of exception
+ block.generateCode(scope, codeStream);
+ anyExceptionHandler.placeEnd();
+ Label endLabel = new Label(codeStream);
+ if (!blockExit) {
+ codeStream.load(synchroVariable);
+ codeStream.monitorexit();
+ codeStream.goto_(endLabel);
+ }
+ // generate the body of the exception handler
+ anyExceptionHandler.place();
+ codeStream.incrStackSize(1);
+ codeStream.load(synchroVariable);
+ codeStream.monitorexit();
+ codeStream.athrow();
+ if (!blockExit) {
+ endLabel.place();
+ }
+ }
+ if (scope != currentScope) {
+ codeStream.exitUserScope(scope);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public void resolve(BlockScope upperScope) {
+
+ // special scope for secret locals optimization.
+ scope = new BlockScope(upperScope);
+ TypeBinding type = expression.resolveType(scope);
+ if (type == null)
+ return;
+ switch (type.id) {
+ case (T_boolean) :
+ case (T_char) :
+ case (T_float) :
+ case (T_double) :
+ case (T_byte) :
+ case (T_short) :
+ case (T_int) :
+ case (T_long) :
+ scope.problemReporter().invalidTypeToSynchronize(expression, type);
+ break;
+ case (T_null) :
+ scope.problemReporter().invalidNullToSynchronize(expression);
+ break;
+ }
+ //continue even on errors in order to have the TC done into the statements
+ synchroVariable = new LocalVariableBinding(SecretLocalDeclarationName, type, 0);
+ scope.addLocalVariable(synchroVariable);
+ synchroVariable.constant = NotAConstant; // not inlinable
+ expression.implicitWidening(type, type);
+ block.resolveUsing(scope);
+ }
+
+ public String toString(int tab) {
+ /* slow code */
+
+ String s = tabString(tab);
+ s = s + "synchronized (" + expression.toStringExpression() + ")";
+ s = s + "\n" + block.toString(tab + 1);
+ return s;
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ if (visitor.visit(this, blockScope)) {
+ expression.traverse(visitor, scope);
+ block.traverse(visitor, scope);
+ }
+ visitor.endVisit(this, blockScope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThisReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThisReference.java
new file mode 100644
index 0000000000..d37a0d9493
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThisReference.java
@@ -0,0 +1,80 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class ThisReference extends Reference {
+
+ public static final ThisReference ThisImplicit = new ThisReference();
+
+ /**
+ * ThisReference constructor comment.
+ */
+ public ThisReference() {
+ super();
+ }
+
+ public ThisReference(int s, int sourceEnd) {
+ this();
+ this.sourceStart = s;
+ this.sourceEnd = sourceEnd;
+ }
+
+ protected boolean checkAccess(MethodScope methodScope) {
+ // this/super cannot be used in constructor call
+ if (methodScope.isConstructorCall) {
+ methodScope.problemReporter().fieldsOrThisBeforeConstructorInvocation(this);
+ return false;
+ }
+
+ // static may not refer to this/super
+ if (methodScope.isStatic) {
+ methodScope.problemReporter().errorThisSuperInStatic(this);
+ return false;
+ }
+ return true;
+ }
+
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ if (valueRequired)
+ codeStream.aload_0();
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public boolean isThis() {
+
+ return true;
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ // implicit this
+ constant = NotAConstant;
+ if (this != ThisImplicit && !checkAccess(scope.methodScope()))
+ return null;
+ return scope.enclosingSourceType();
+ }
+
+ public String toStringExpression() {
+
+ if (this == ThisImplicit)
+ return "";
+ return "this";
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ visitor.visit(this, blockScope);
+ visitor.endVisit(this, blockScope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java
new file mode 100644
index 0000000000..684576e144
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java
@@ -0,0 +1,81 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class ThrowStatement extends Statement {
+ public Expression exception;
+ public TypeBinding exceptionType;
+ public ThrowStatement(Expression exception, int startPosition) {
+ this.exception = exception;
+ this.sourceStart = startPosition;
+ this.sourceEnd = exception.sourceEnd;
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+
+ // need to check that exception thrown is actually caught somewhere
+
+ exception.analyseCode(currentScope, flowContext, flowInfo);
+ flowContext.checkExceptionHandlers(exceptionType, this, flowInfo, currentScope);
+ return FlowInfo.DeadEnd;
+ }
+
+ /**
+ * Throw code generation
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ */
+ public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+
+ if ((bits & IsReachableMASK) == 0) {
+ return;
+ }
+ int pc = codeStream.position;
+ exception.generateCode(currentScope, codeStream, true);
+ codeStream.athrow();
+ codeStream.recordPositionsFrom(pc, this);
+
+ }
+
+ public void resolve(BlockScope scope) {
+ exceptionType =
+ exception.resolveTypeExpecting(scope, scope.getJavaLangThrowable());
+ if (exceptionType == NullBinding)
+ scope.problemReporter().cannotThrowNull(this);
+ exception.implicitWidening(exceptionType, exceptionType);
+ }
+
+ /* SHOULDN'T IT RATHER DO -
+ scope.checkThrowable(exceptionType = expression.resolveType(scope));
+ */
+ public String toString(int tab) {
+ /* slow code */
+
+ String s = tabString(tab);
+ s = s + "throw ";
+ s = s + exception.toStringExpression();
+ return s;
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ if (visitor.visit(this, blockScope)) {
+ exception.traverse(visitor, blockScope);
+ }
+ visitor.endVisit(this, blockScope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TrueLiteral.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TrueLiteral.java
new file mode 100644
index 0000000000..2d5d102ccf
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TrueLiteral.java
@@ -0,0 +1,78 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class TrueLiteral extends MagicLiteral {
+ static final char[] source = { 't', 'r', 'u', 'e' };
+ public TrueLiteral(int s, int e) {
+ super(s, e);
+ }
+
+ public void computeConstant() {
+
+ constant = Constant.fromValue(true);
+ }
+
+ /**
+ * Code generation for the true literal
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param valueRequired boolean
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ if (valueRequired)
+ codeStream.iconst_1();
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public void generateOptimizedBoolean(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Label trueLabel,
+ Label falseLabel,
+ boolean valueRequired) {
+
+ // trueLabel being not nil means that we will not fall through into the TRUE case
+
+ int pc = codeStream.position;
+ // constant == true
+ if (valueRequired) {
+ if (falseLabel == null) {
+ // implicit falling through the FALSE case
+ if (trueLabel != null) {
+ codeStream.goto_(trueLabel);
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public TypeBinding literalType(BlockScope scope) {
+ return BooleanBinding;
+ }
+
+ /**
+ *
+ */
+ public char[] source() {
+ return source;
+ }
+
+ public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+ visitor.visit(this, scope);
+ visitor.endVisit(this, scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java
new file mode 100644
index 0000000000..61da8ea0e4
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java
@@ -0,0 +1,482 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+public class TryStatement extends Statement {
+ public Block tryBlock;
+ public Block[] catchBlocks;
+ public Argument[] catchArguments;
+ public Block finallyBlock;
+
+ BlockScope scope;
+
+ public boolean subRoutineCannotReturn = true;
+ // should rename into subRoutineComplete to be set to false by default
+
+ ReferenceBinding[] caughtExceptionTypes;
+ boolean tryBlockExit;
+ boolean[] catchExits;
+ public int[] preserveExceptionHandler;
+
+ Label subRoutineStartLabel;
+ LocalVariableBinding anyExceptionVariable, returnAddressVariable;
+
+ final static char[] SecretReturnName = " returnAddress".toCharArray();
+ final static char[] SecretAnyHandlerName = " anyExceptionHandler".toCharArray();
+
+ // for local variables table attributes
+ int preTryInitStateIndex = -1;
+ int mergedInitStateIndex = -1;
+ /**
+ * TryStatement constructor comment.
+ */
+ public TryStatement() {
+ super();
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+
+ // Consider the try block and catch block so as to compute the intersection of initializations and
+ // the minimum exit relative depth amongst all of them. Then consider the subroutine, and append its
+ // initialization to the try/catch ones, if the subroutine completes normally. If the subroutine does not
+ // complete, then only keep this result for the rest of the analysis
+
+ // process the finally block (subroutine) - create a context for the subroutine
+
+ preTryInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(flowInfo);
+
+ if (anyExceptionVariable != null) {
+ anyExceptionVariable.used = true;
+ }
+ if (returnAddressVariable != null) {
+ returnAddressVariable.used = true;
+ }
+ FlowContext insideSubContext;
+ FinallyFlowContext finallyContext;
+ UnconditionalFlowInfo subInfo;
+ if (subRoutineStartLabel == null) {
+ insideSubContext = flowContext;
+ finallyContext = null;
+ subInfo = null;
+ } else {
+ insideSubContext = new InsideSubRoutineFlowContext(flowContext, this);
+ subInfo =
+ finallyBlock
+ .analyseCode(
+ currentScope,
+ finallyContext = new FinallyFlowContext(flowContext, finallyBlock),
+ flowInfo.copy())
+ .unconditionalInits();
+ if (!((subInfo == FlowInfo.DeadEnd) || subInfo.isFakeReachable())) {
+ subRoutineCannotReturn = false;
+ }
+ }
+
+ // process the try block in a context handling the local exceptions.
+ ExceptionHandlingFlowContext handlingContext =
+ new ExceptionHandlingFlowContext(
+ insideSubContext,
+ tryBlock,
+ caughtExceptionTypes,
+ scope,
+ flowInfo.unconditionalInits());
+ FlowInfo tryInfo;
+ if (tryBlock.statements == null) {
+ tryInfo = flowInfo;
+ tryBlockExit = false;
+ } else {
+ tryInfo = tryBlock.analyseCode(currentScope, handlingContext, flowInfo.copy());
+ tryBlockExit = (tryInfo == FlowInfo.DeadEnd) || tryInfo.isFakeReachable();
+ }
+
+ // check unreachable catch blocks
+ handlingContext.complainIfUnusedExceptionHandlers(catchBlocks, scope, this);
+
+ // process the catch blocks - computing the minimal exit depth amongst try/catch
+ if (catchArguments != null) {
+ int catchCount;
+ catchExits = new boolean[catchCount = catchBlocks.length];
+ for (int i = 0; i < catchCount; i++) {
+ // keep track of the inits that could potentially have led to this exception handler (for final assignments diagnosis)
+ ///*
+ FlowInfo catchInfo =
+ flowInfo
+ .copy()
+ .unconditionalInits()
+ .addPotentialInitializationsFrom(
+ handlingContext.initsOnException(caughtExceptionTypes[i]).unconditionalInits())
+ .addPotentialInitializationsFrom(tryInfo.unconditionalInits());
+ //*/
+ // SMART ANALYSIS (see 1FBPLCY)
+ //FlowInfo catchInfo = handlingContext.initsOnException(caughtExceptionTypes[i]);
+
+ // catch var is always set
+ catchInfo.markAsDefinitelyAssigned(catchArguments[i].binding);
+ /*
+ "If we are about to consider an unchecked exception handler, potential inits may have occured inside
+ the try block that need to be detected , e.g.
+ try { x = 1; throwSomething();} catch(Exception e){ x = 2} "
+ "(uncheckedExceptionTypes notNil and: [uncheckedExceptionTypes at: index])
+ ifTrue: [catchInits addPotentialInitializationsFrom: tryInits]."
+ */
+ if (tryBlock.statements == null) {
+ catchInfo.markAsFakeReachable(true);
+ }
+ catchInfo =
+ catchBlocks[i].analyseCode(currentScope, insideSubContext, catchInfo);
+ catchExits[i] =
+ ((catchInfo == FlowInfo.DeadEnd) || catchInfo.isFakeReachable());
+ tryInfo = tryInfo.mergedWith(catchInfo.unconditionalInits());
+ }
+ }
+ if (subRoutineStartLabel == null) {
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(tryInfo);
+ return tryInfo;
+ }
+
+ // we also need to check potential multiple assignments of final variables inside the finally block
+ finallyContext.complainOnRedundantFinalAssignments(tryInfo, currentScope);
+ if (subInfo == FlowInfo.DeadEnd) {
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(subInfo);
+ return subInfo;
+ } else {
+ FlowInfo mergedInfo = tryInfo.addInitializationsFrom(subInfo);
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(mergedInfo);
+ return mergedInfo;
+ }
+ }
+
+ public boolean cannotReturn() {
+ return subRoutineCannotReturn;
+ }
+
+ /**
+ * Try statement code generation
+ *
+ */
+ public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+ if ((bits & IsReachableMASK) == 0) {
+ return;
+ }
+ if (tryBlock.isEmptyBlock()) {
+ if (subRoutineStartLabel != null) {
+ // since not passing the finallyScope, the block generation will exitUserScope(finallyScope)
+ finallyBlock.generateCode(scope, codeStream);
+ }
+ // May loose some local variable initializations : affecting the local variable attributes
+ if (mergedInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ mergedInitStateIndex);
+ }
+ // no local bytecode produced so no need for position remembering
+ return;
+ }
+ int pc = codeStream.position;
+ Label endLabel = new Label(codeStream);
+ boolean requiresNaturalJsr = false;
+
+ // preparing exception labels
+ int maxCatches;
+ ExceptionLabel[] exceptionLabels =
+ new ExceptionLabel[maxCatches =
+ catchArguments == null ? 0 : catchArguments.length];
+ for (int i = 0; i < maxCatches; i++) {
+ boolean preserveCurrentHandler =
+ (preserveExceptionHandler[i
+ / ExceptionHandlingFlowContext.BitCacheSize]
+ & (1 << (i % ExceptionHandlingFlowContext.BitCacheSize)))
+ != 0;
+ if (preserveCurrentHandler) {
+ exceptionLabels[i] =
+ new ExceptionLabel(
+ codeStream,
+ (ReferenceBinding) catchArguments[i].binding.type);
+ }
+ }
+ ExceptionLabel anyExceptionLabel = null;
+ if (subRoutineStartLabel != null) {
+ subRoutineStartLabel.codeStream = codeStream;
+ anyExceptionLabel = new ExceptionLabel(codeStream, null);
+ }
+ // generate the try block
+ tryBlock.generateCode(scope, codeStream);
+ boolean tryBlockHasSomeCode = codeStream.position != pc;
+ // flag telling if some bytecodes were issued inside the try block
+
+ // natural exit: only if necessary
+ boolean nonReturningSubRoutine =
+ (subRoutineStartLabel != null) && subRoutineCannotReturn;
+ if ((!tryBlockExit) && tryBlockHasSomeCode) {
+ int position = codeStream.position;
+ if (nonReturningSubRoutine) {
+ codeStream.goto_(subRoutineStartLabel);
+ } else {
+ requiresNaturalJsr = true;
+ codeStream.goto_(endLabel);
+ }
+ codeStream.updateLastRecordedEndPC(position);
+ //goto is tagged as part of the try block
+ }
+ // place end positions of user-defined exception labels
+ if (tryBlockHasSomeCode) {
+ for (int i = 0; i < maxCatches; i++) {
+ boolean preserveCurrentHandler =
+ (preserveExceptionHandler[i
+ / ExceptionHandlingFlowContext.BitCacheSize]
+ & (1 << (i % ExceptionHandlingFlowContext.BitCacheSize)))
+ != 0;
+ if (preserveCurrentHandler) {
+ exceptionLabels[i].placeEnd();
+ }
+ }
+ /* generate sequence of handler, all starting by storing the TOS (exception
+ thrown) into their own catch variables, the one specified in the source
+ that must denote the handled exception.
+ */
+ if (catchArguments == null) {
+ if (anyExceptionLabel != null) {
+ anyExceptionLabel.placeEnd();
+ }
+ } else {
+ for (int i = 0; i < maxCatches; i++) {
+ boolean preserveCurrentHandler =
+ (preserveExceptionHandler[i
+ / ExceptionHandlingFlowContext.BitCacheSize]
+ & (1 << (i % ExceptionHandlingFlowContext.BitCacheSize)))
+ != 0;
+ if (preserveCurrentHandler) {
+ // May loose some local variable initializations : affecting the local variable attributes
+ if (preTryInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ preTryInitStateIndex);
+ }
+ exceptionLabels[i].place();
+ codeStream.incrStackSize(1);
+ // optimizing the case where the exception variable is not actually used
+ LocalVariableBinding catchVar;
+ int varPC = codeStream.position;
+ if ((catchVar = catchArguments[i].binding).resolvedPosition != -1) {
+ codeStream.store(catchVar, false);
+ catchVar.recordInitializationStartPC(codeStream.position);
+ codeStream.addVisibleLocalVariable(catchVar);
+ } else {
+ codeStream.pop();
+ }
+ codeStream.recordPositionsFrom(varPC, catchArguments[i]);
+ // Keep track of the pcs at diverging point for computing the local attribute
+ // since not passing the catchScope, the block generation will exitUserScope(catchScope)
+ catchBlocks[i].generateCode(scope, codeStream);
+ }
+ if (i == maxCatches - 1) {
+ if (anyExceptionLabel != null) {
+ anyExceptionLabel.placeEnd();
+ }
+ if (subRoutineStartLabel != null) {
+ if (!catchExits[i] && preserveCurrentHandler) {
+ requiresNaturalJsr = true;
+ codeStream.goto_(endLabel);
+ }
+ }
+ } else {
+ if (!catchExits[i] && preserveCurrentHandler) {
+ if (nonReturningSubRoutine) {
+ codeStream.goto_(subRoutineStartLabel);
+ } else {
+ requiresNaturalJsr = true;
+ codeStream.goto_(endLabel);
+ }
+ }
+ }
+ }
+ }
+ // addition of a special handler so as to ensure that any uncaught exception (or exception thrown
+ // inside catch blocks) will run the finally block
+ int finallySequenceStartPC = codeStream.position;
+ if (subRoutineStartLabel != null) {
+ // the additional handler is doing: jsr finallyBlock and rethrow TOS-exception
+ anyExceptionLabel.place();
+
+ if (preTryInitStateIndex != -1) {
+ // reset initialization state, as for a normal catch block
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ preTryInitStateIndex);
+ }
+
+ codeStream.incrStackSize(1);
+ if (nonReturningSubRoutine) {
+ codeStream.pop();
+ // "if subroutine cannot return, no need to jsr/jump to subroutine since it will be entered in sequence
+ } else {
+ codeStream.store(anyExceptionVariable, false);
+ codeStream.jsr(subRoutineStartLabel);
+ codeStream.load(anyExceptionVariable);
+ codeStream.athrow();
+ }
+ }
+ // end of catch sequence, place label that will correspond to the finally block beginning, or end of statement
+ endLabel.place();
+ if (subRoutineStartLabel != null) {
+ if (nonReturningSubRoutine) {
+ requiresNaturalJsr = false;
+ }
+ Label veryEndLabel = new Label(codeStream);
+ if (requiresNaturalJsr) {
+ codeStream.jsr(subRoutineStartLabel);
+ codeStream.goto_(veryEndLabel);
+ }
+ subRoutineStartLabel.place();
+ if (!nonReturningSubRoutine) {
+ codeStream.incrStackSize(1);
+ codeStream.store(returnAddressVariable, false);
+ }
+ codeStream.recordPositionsFrom(finallySequenceStartPC, finallyBlock);
+ // entire sequence for finally is associated to finally block
+ finallyBlock.generateCode(scope, codeStream);
+ if (!nonReturningSubRoutine) {
+ int position = codeStream.position;
+ codeStream.ret(returnAddressVariable.resolvedPosition);
+ codeStream.updateLastRecordedEndPC(position);
+ // the ret bytecode is part of the subroutine
+ }
+ if (requiresNaturalJsr) {
+ veryEndLabel.place();
+ }
+ }
+ } else {
+ // try block had no effect, only generate the body of the finally block if any
+ if (subRoutineStartLabel != null) {
+ finallyBlock.generateCode(scope, codeStream);
+ }
+ }
+ // May loose some local variable initializations : affecting the local variable attributes
+ if (mergedInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ mergedInitStateIndex);
+ codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public void resolve(BlockScope upperScope) {
+
+ // special scope for secret locals optimization.
+ scope = new BlockScope(upperScope);
+ if (finallyBlock != null
+ && finallyBlock.statements != null) {
+ // provision for returning and forcing the finally block to run
+ returnAddressVariable =
+ new LocalVariableBinding(SecretReturnName, upperScope.getJavaLangObject(), 0);
+ // the type does not matter as long as its not a normal base type
+ scope.addLocalVariable(returnAddressVariable);
+ returnAddressVariable.constant = NotAConstant; // not inlinable
+ subRoutineStartLabel = new Label();
+
+ BlockScope finallyScope = new BlockScope(scope);
+ anyExceptionVariable =
+ new LocalVariableBinding(SecretAnyHandlerName, scope.getJavaLangThrowable(), 0);
+ finallyScope.addLocalVariable(anyExceptionVariable);
+ anyExceptionVariable.constant = NotAConstant; // not inlinable
+ finallyBlock.resolveUsing(finallyScope);
+ }
+ tryBlock.resolve(scope);
+
+ // arguments type are checked against JavaLangThrowable in resolveForCatch(..)
+ if (catchBlocks != null) {
+ int length = catchArguments.length;
+ TypeBinding[] argumentTypes = new TypeBinding[length];
+ for (int i = 0; i < length; i++) {
+ BlockScope catchScope = new BlockScope(scope);
+ // side effect on catchScope in resolveForCatch(..)
+ if ((argumentTypes[i] = catchArguments[i].resolveForCatch(catchScope)) == null)
+ return;
+ catchBlocks[i].resolveUsing(catchScope);
+ }
+
+ // Verify that the catch clause are ordered in the right way:
+ // more specialized first.
+ caughtExceptionTypes = new ReferenceBinding[length];
+ for (int i = 0; i < length; i++) {
+ caughtExceptionTypes[i] = (ReferenceBinding) argumentTypes[i];
+ for (int j = 0; j < i; j++) {
+ if (scope.areTypesCompatible(caughtExceptionTypes[i], argumentTypes[j])) {
+ scope.problemReporter().wrongSequenceOfExceptionTypesError(this, i, j);
+ return;
+ }
+ }
+ }
+ } else {
+ caughtExceptionTypes = new ReferenceBinding[0];
+ }
+ }
+
+ public String toString(int tab) {
+ /* slow code */
+
+ String s = tabString(tab);
+ //try
+ s = s + "try ";
+ if (tryBlock == Block.None)
+ s = s + "{}";
+ else
+ s = s + "\n" + tryBlock.toString(tab + 1);
+
+ //catches
+ if (catchBlocks != null)
+ for (int i = 0; i < catchBlocks.length; i++)
+ s =
+ s
+ + "\n"
+ + tabString(tab)
+ + "catch ("
+ + catchArguments[i].toString(0)
+ + ") "
+ + catchBlocks[i].toString(tab + 1);
+ //finally
+ if (finallyBlock != null) {
+ if (finallyBlock == Block.None)
+ s = s + "\n" + tabString(tab) + "finally {}";
+ else
+ s = s + "\n" + tabString(tab) + "finally\n" + finallyBlock.toString(tab + 1);
+ }
+
+ return s;
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ if (visitor.visit(this, blockScope)) {
+ tryBlock.traverse(visitor, scope);
+ if (catchArguments != null) {
+ for (int i = 0, max = catchBlocks.length; i < max; i++) {
+ catchArguments[i].traverse(visitor, scope);
+ catchBlocks[i].traverse(visitor, scope);
+ }
+ }
+ if (finallyBlock != null)
+ finallyBlock.traverse(visitor, scope);
+ }
+ visitor.endVisit(this, blockScope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java
new file mode 100644
index 0000000000..bcf4c63792
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java
@@ -0,0 +1,1065 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.parser.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class TypeDeclaration
+ extends Statement
+ implements ProblemSeverities, ReferenceContext {
+ public int modifiers;
+ public int modifiersSourceStart;
+ public char[] name;
+ public TypeReference superclass;
+ public TypeReference[] superInterfaces;
+ public FieldDeclaration[] fields;
+ public AbstractMethodDeclaration[] methods;
+ public MemberTypeDeclaration[] memberTypes;
+ public SourceTypeBinding binding;
+ public ClassScope scope;
+ public MethodScope initializerScope;
+ public MethodScope staticInitializerScope;
+ public boolean ignoreFurtherInvestigation = false;
+ public int maxFieldCount;
+ public int declarationSourceStart;
+ public int declarationSourceEnd;
+ public int bodyStart;
+ /*
+ * We cause the compilation task to abort to a given extent.
+ */
+ public void abort(int abortLevel) {
+
+ if (scope == null) {
+ throw new AbortCompilation(); // cannot do better
+ }
+
+ CompilationResult compilationResult =
+ scope.referenceCompilationUnit().compilationResult;
+
+ switch (abortLevel) {
+ case AbortCompilation :
+ throw new AbortCompilation(compilationResult);
+ case AbortCompilationUnit :
+ throw new AbortCompilationUnit(compilationResult);
+ case AbortMethod :
+ throw new AbortMethod(compilationResult);
+ default :
+ throw new AbortType(compilationResult);
+ }
+ }
+
+ /**
+ * This method is responsible for adding a <clinit> method declaration to the type method collections.
+ * Note that this implementation is inserting it in first place (as VAJ or javac), and that this
+ * impacts the behavior of the method ConstantPool.resetForClinit(int. int), in so far as
+ * the latter will have to reset the constant pool state accordingly (if it was added first, it does
+ * not need to preserve some of the method specific cached entries since this will be the first method).
+ * inserts the clinit method declaration in the first position.
+ *
+ * @see org.eclipse.jdt.internal.compiler.codegen.ConstantPool.resetForClinit(int, int)
+ */
+ public final void addClinit() {
+ //see comment on needClassInitMethod
+
+ if (needClassInitMethod()) {
+ int length;
+ AbstractMethodDeclaration[] methods;
+ if ((methods = this.methods) == null) {
+ length = 0;
+ methods = new AbstractMethodDeclaration[1];
+ } else {
+ length = methods.length;
+ System.arraycopy(
+ methods,
+ 0,
+ (methods = new AbstractMethodDeclaration[length + 1]),
+ 1,
+ length);
+ }
+ Clinit clinit = new Clinit();
+ methods[0] = clinit;
+ // clinit is added in first location, so as to minimize the use of ldcw (big consumer of constant inits)
+ clinit.declarationSourceStart = clinit.sourceStart = sourceStart;
+ clinit.declarationSourceEnd = clinit.sourceEnd = sourceEnd;
+ this.methods = methods;
+ }
+ }
+
+ /**
+ * Flow analysis for a local innertype
+ *
+ */
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ if (ignoreFurtherInvestigation)
+ return flowInfo;
+ try {
+ // remember local types binding for innerclass emulation propagation
+ currentScope.referenceCompilationUnit().record((LocalTypeBinding) binding);
+
+ InitializationFlowContext initializerContext =
+ new InitializationFlowContext(null, this, initializerScope);
+ // propagate down the max field count
+ updateMaxFieldCount();
+ FlowInfo fieldInfo = flowInfo.copy();
+ // so as not to propagate changes outside this type
+ if (fields != null) {
+ for (int i = 0, count = fields.length; i < count; i++) {
+ fieldInfo =
+ fields[i].analyseCode(initializerScope, initializerContext, fieldInfo);
+ if (fieldInfo == FlowInfo.DeadEnd) {
+ // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable
+ // branch, since the previous initializer already got the blame.
+ initializerScope.problemReporter().initializerMustCompleteNormally(fields[i]);
+ fieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true);
+ }
+ }
+ }
+ if (memberTypes != null) {
+ for (int i = 0, count = memberTypes.length; i < count; i++) {
+ memberTypes[i].analyseCode(scope, flowContext, fieldInfo.copy());
+ }
+ }
+ if (methods != null) {
+ int recursionBalance = 0; // check constructor recursions
+ for (int i = 0, count = methods.length; i < count; i++) {
+ AbstractMethodDeclaration method = methods[i];
+ if (method.ignoreFurtherInvestigation)
+ continue;
+ if (method.isConstructor()) { // constructor
+ ConstructorDeclaration constructor = (ConstructorDeclaration) method;
+ constructor.analyseCode(scope, initializerContext, fieldInfo.copy());
+ // compute the recursive invocation balance:
+ // how many thisReferences vs. superReferences to constructors
+ int refCount;
+ if ((refCount = constructor.referenceCount) > 0) {
+ if ((constructor.constructorCall == null)
+ || constructor.constructorCall.isSuperAccess()
+ || !constructor.constructorCall.binding.isValidBinding()) {
+ recursionBalance -= refCount;
+ constructor.referenceCount = -1;
+ // for error reporting propagation
+ } else {
+ recursionBalance += refCount;
+ }
+ }
+ } else { // regular method
+ method.analyseCode(scope, null, flowInfo.copy());
+ }
+ }
+ if (recursionBalance > 0) {
+ // there is one or more cycle(s) amongst constructor invocations
+ scope.problemReporter().recursiveConstructorInvocation(this);
+ }
+ }
+ } catch (AbortType e) {
+ this.ignoreFurtherInvestigation = true;
+ }
+ return flowInfo;
+ }
+
+ /**
+ * Flow analysis for a member innertype
+ *
+ */
+ public void analyseCode(ClassScope classScope1) {
+ if (ignoreFurtherInvestigation)
+ return;
+ try {
+ // propagate down the max field count
+ updateMaxFieldCount();
+ FlowInfo flowInfo = FlowInfo.initial(maxFieldCount); // start fresh init info
+ InitializationFlowContext initializerContext =
+ new InitializationFlowContext(null, this, initializerScope);
+ InitializationFlowContext staticInitializerContext =
+ new InitializationFlowContext(null, this, staticInitializerScope);
+ FlowInfo nonStaticFieldInfo = flowInfo.copy(),
+ staticFieldInfo = flowInfo.copy();
+ if (fields != null) {
+ for (int i = 0, count = fields.length; i < count; i++) {
+ if (fields[i].isStatic()) {
+ staticFieldInfo =
+ fields[i].analyseCode(
+ staticInitializerScope,
+ staticInitializerContext,
+ staticFieldInfo);
+ // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable
+ // branch, since the previous initializer already got the blame.
+ if (staticFieldInfo == FlowInfo.DeadEnd) {
+ staticInitializerScope.problemReporter().initializerMustCompleteNormally(
+ fields[i]);
+ staticFieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true);
+ }
+ } else {
+ nonStaticFieldInfo =
+ fields[i].analyseCode(initializerScope, initializerContext, nonStaticFieldInfo);
+ // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable
+ // branch, since the previous initializer already got the blame.
+ if (nonStaticFieldInfo == FlowInfo.DeadEnd) {
+ initializerScope.problemReporter().initializerMustCompleteNormally(fields[i]);
+ nonStaticFieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true);
+ }
+ }
+ }
+ }
+ if (memberTypes != null) {
+ for (int i = 0, count = memberTypes.length; i < count; i++) {
+ memberTypes[i].analyseCode(scope);
+ }
+ }
+ if (methods != null) {
+ int recursionBalance = 0; // check constructor recursions
+ for (int i = 0, count = methods.length; i < count; i++) {
+ AbstractMethodDeclaration method = methods[i];
+ if (method.ignoreFurtherInvestigation)
+ continue;
+ if (method.isInitializationMethod()) {
+ if (method.isStatic()) { // <clinit>
+ ((Clinit) method).analyseCode(scope, staticInitializerContext, staticFieldInfo);
+ } else { // constructor
+ ConstructorDeclaration constructor = (ConstructorDeclaration) method;
+ constructor.analyseCode(scope, initializerContext, nonStaticFieldInfo.copy());
+ // compute the recursive invocation balance:
+ // how many thisReferences vs. superReferences to constructors
+ int refCount;
+ if ((refCount = constructor.referenceCount) > 0) {
+ if ((constructor.constructorCall == null)
+ || constructor.constructorCall.isSuperAccess()
+ || !constructor.constructorCall.binding.isValidBinding()) {
+ recursionBalance -= refCount;
+ constructor.referenceCount = -1; // for error reporting propagation
+ } else {
+ recursionBalance += refCount;
+ }
+ }
+ }
+ } else { // regular method
+ method.analyseCode(scope, null, FlowInfo.initial(maxFieldCount));
+ }
+ }
+ if (recursionBalance > 0) {
+ // there is one or more cycle(s) amongst constructor invocations
+ scope.problemReporter().recursiveConstructorInvocation(this);
+ }
+ }
+ } catch (AbortType e) {
+ this.ignoreFurtherInvestigation = true;
+ };
+ }
+
+ /**
+ * Flow analysis for a local member innertype
+ *
+ */
+ public void analyseCode(
+ ClassScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ if (ignoreFurtherInvestigation)
+ return;
+ try {
+ // remember local types binding for innerclass emulation propagation
+ currentScope.referenceCompilationUnit().record((LocalTypeBinding) binding);
+
+ /* force to emulation of access to direct enclosing instance: only for local members.
+ * By using the initializer scope, we actually only request an argument emulation, the
+ * field is not added until actually used. However we will force allocations to be qualified
+ * with an enclosing instance.
+ */
+ initializerScope.emulateOuterAccess(
+ (SourceTypeBinding) binding.enclosingType(),
+ false);
+
+ InitializationFlowContext initializerContext =
+ new InitializationFlowContext(null, this, initializerScope);
+ // propagate down the max field count
+ updateMaxFieldCount();
+ FlowInfo fieldInfo = flowInfo.copy();
+ // so as not to propagate changes outside this type
+ if (fields != null) {
+ for (int i = 0, count = fields.length; i < count; i++) {
+ if (!fields[i].isStatic()) {
+ fieldInfo =
+ fields[i].analyseCode(initializerScope, initializerContext, fieldInfo);
+ if (fieldInfo == FlowInfo.DeadEnd) {
+ // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable
+ // branch, since the previous initializer already got the blame.
+ initializerScope.problemReporter().initializerMustCompleteNormally(fields[i]);
+ fieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true);
+ }
+ }
+ }
+ }
+ if (memberTypes != null) {
+ for (int i = 0, count = memberTypes.length; i < count; i++) {
+ memberTypes[i].analyseCode(scope, flowContext, fieldInfo.copy());
+ }
+ }
+ if (methods != null) {
+ int recursionBalance = 0; // check constructor recursions
+ for (int i = 0, count = methods.length; i < count; i++) {
+ AbstractMethodDeclaration method = methods[i];
+ if (method.ignoreFurtherInvestigation)
+ continue;
+ if (method.isConstructor()) { // constructor
+ ConstructorDeclaration constructor = (ConstructorDeclaration) method;
+ constructor.analyseCode(scope, initializerContext, fieldInfo.copy());
+ // compute the recursive invocation balance:
+ // how many thisReferences vs. superReferences to constructors
+ int refCount;
+ if ((refCount = constructor.referenceCount) > 0) {
+ if ((constructor.constructorCall == null)
+ || constructor.constructorCall.isSuperAccess()
+ || !constructor.constructorCall.binding.isValidBinding()) {
+ recursionBalance -= refCount;
+ constructor.referenceCount = -1; // for error reporting propagation
+ } else {
+ recursionBalance += refCount;
+ }
+ }
+ } else { // regular method
+ method.analyseCode(scope, null, flowInfo.copy());
+ }
+ }
+ if (recursionBalance > 0) {
+ // there is one or more cycle(s) amongst constructor invocations
+ scope.problemReporter().recursiveConstructorInvocation(this);
+ }
+ }
+ } catch (AbortType e) {
+ this.ignoreFurtherInvestigation = true;
+ };
+ }
+
+ /**
+ * Flow analysis for a package member type
+ *
+ */
+ public void analyseCode(CompilationUnitScope unitScope) {
+ if (ignoreFurtherInvestigation)
+ return;
+ try {
+ FlowInfo flowInfo = FlowInfo.initial(maxFieldCount); // start fresh init info
+ InitializationFlowContext initializerContext =
+ new InitializationFlowContext(null, this, initializerScope);
+ InitializationFlowContext staticInitializerContext =
+ new InitializationFlowContext(null, this, staticInitializerScope);
+ FlowInfo nonStaticFieldInfo = flowInfo.copy(),
+ staticFieldInfo = flowInfo.copy();
+ if (fields != null) {
+ for (int i = 0, count = fields.length; i < count; i++) {
+ if (fields[i].isStatic()) {
+ staticFieldInfo =
+ fields[i].analyseCode(
+ staticInitializerScope,
+ staticInitializerContext,
+ staticFieldInfo);
+ // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable
+ // branch, since the previous initializer already got the blame.
+ if (staticFieldInfo == FlowInfo.DeadEnd) {
+ staticInitializerScope.problemReporter().initializerMustCompleteNormally(
+ fields[i]);
+ staticFieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true);
+ }
+ } else {
+ nonStaticFieldInfo =
+ fields[i].analyseCode(initializerScope, initializerContext, nonStaticFieldInfo);
+ // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable
+ // branch, since the previous initializer already got the blame.
+ if (nonStaticFieldInfo == FlowInfo.DeadEnd) {
+ initializerScope.problemReporter().initializerMustCompleteNormally(fields[i]);
+ nonStaticFieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true);
+ }
+ }
+ }
+ }
+ if (memberTypes != null) {
+ for (int i = 0, count = memberTypes.length; i < count; i++) {
+ memberTypes[i].analyseCode(scope);
+ }
+ }
+ if (methods != null) {
+ int recursionBalance = 0; // check constructor recursions
+ for (int i = 0, count = methods.length; i < count; i++) {
+ AbstractMethodDeclaration method = methods[i];
+ if (method.ignoreFurtherInvestigation)
+ continue;
+ if (method.isInitializationMethod()) {
+ if (method.isStatic()) { // <clinit>
+ ((Clinit) method).analyseCode(scope, staticInitializerContext, staticFieldInfo);
+ } else { // constructor
+ ConstructorDeclaration constructor = (ConstructorDeclaration) method;
+ constructor.analyseCode(scope, initializerContext, nonStaticFieldInfo.copy());
+ // compute the recursive invocation balance:
+ // how many thisReferences vs. superReferences to constructors
+ int refCount;
+ if ((refCount = constructor.referenceCount) > 0) {
+ if ((constructor.constructorCall == null)
+ || constructor.constructorCall.isSuperAccess()
+ || !constructor.constructorCall.binding.isValidBinding()) {
+ recursionBalance -= refCount;
+ constructor.referenceCount = -1; // for error reporting propagation
+ } else {
+ recursionBalance += refCount;
+ }
+ }
+ }
+ } else { // regular method
+ method.analyseCode(scope, null, FlowInfo.initial(maxFieldCount));
+ }
+ }
+ if (recursionBalance > 0) {
+ // there is one or more cycle(s) amongst constructor invocations
+ scope.problemReporter().recursiveConstructorInvocation(this);
+ }
+ }
+ } catch (AbortType e) {
+ this.ignoreFurtherInvestigation = true;
+ };
+ }
+
+ /*
+ * Check for constructor vs. method with no return type.
+ * Answers true if at least one constructor is defined
+ */
+ public boolean checkConstructors(Parser parser) {
+ //if a constructor has not the name of the type,
+ //convert it into a method with 'null' as its return type
+
+ boolean hasConstructor = false;
+ if (methods != null) {
+ for (int i = methods.length; --i >= 0;) {
+ AbstractMethodDeclaration am;
+ if ((am = methods[i]).isConstructor()) {
+ if (!CharOperation.equals(am.selector, name)) {
+ // the constructor was in fact a method with no return type
+ // unless an explicit constructor call was supplied
+ ConstructorDeclaration c = (ConstructorDeclaration) am;
+ if ((c.constructorCall == null)
+ || (c.constructorCall.isImplicitSuper())) { //changed to a method
+ MethodDeclaration m = new MethodDeclaration();
+ m.sourceStart = c.sourceStart;
+ m.sourceEnd = c.sourceEnd;
+ m.bodyStart = c.bodyStart;
+ m.bodyEnd = c.bodyEnd;
+ m.declarationSourceEnd = c.declarationSourceEnd;
+ m.declarationSourceStart = c.declarationSourceStart;
+ m.selector = c.selector;
+ m.statements = c.statements;
+ m.modifiers = c.modifiers;
+ m.arguments = c.arguments;
+ m.thrownExceptions = c.thrownExceptions;
+ m.explicitDeclarations = c.explicitDeclarations;
+ m.returnType = null;
+ methods[i] = m;
+ }
+ } else {
+ if (this.isInterface()) {
+ // report the problem and continue the parsing
+ parser.problemReporter().interfaceCannotHaveConstructors(
+ (ConstructorDeclaration) am,
+ parser.compilationUnit.compilationResult);
+ }
+ hasConstructor = true;
+ }
+ }
+ }
+ }
+ return hasConstructor;
+ }
+
+ public CompilationResult compilationResult() {
+ return scope.referenceCompilationUnit().compilationResult;
+ }
+
+ public ConstructorDeclaration createsInternalConstructor(
+ boolean needExplicitConstructorCall,
+ boolean needToInsert) {
+
+ //Add to method'set, the default constuctor that just recall the
+ //super constructor with no arguments
+ //The arguments' type will be positionned by the TC so just use
+ //the default int instead of just null (consistency purpose)
+
+ //the constructor
+ ConstructorDeclaration constructor = new ConstructorDeclaration();
+ constructor.isDefaultConstructor = true;
+ constructor.selector = name;
+ if (modifiers != AccDefault) {
+ constructor.modifiers =
+ ((this instanceof MemberTypeDeclaration) && (modifiers & AccPrivate) != 0)
+ ? AccDefault
+ : modifiers & AccVisibilityMASK;
+ }
+
+ //if you change this setting, please update the
+ //SourceIndexer2.buildTypeDeclaration(TypeDeclaration,char[]) method
+ constructor.declarationSourceStart = constructor.sourceStart = sourceStart;
+ constructor.declarationSourceEnd =
+ constructor.sourceEnd = constructor.bodyEnd = sourceEnd;
+
+ //the super call inside the constructor
+ if (needExplicitConstructorCall) {
+ constructor.constructorCall =
+ new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper);
+ constructor.constructorCall.sourceStart = sourceStart;
+ constructor.constructorCall.sourceEnd = sourceEnd;
+ }
+
+ //adding the constructor in the methods list
+ if (needToInsert) {
+ if (methods == null) {
+ methods = new AbstractMethodDeclaration[] { constructor };
+ } else {
+ AbstractMethodDeclaration[] newMethods;
+ System.arraycopy(
+ methods,
+ 0,
+ newMethods = new AbstractMethodDeclaration[methods.length + 1],
+ 1,
+ methods.length);
+ newMethods[0] = constructor;
+ methods = newMethods;
+ }
+ }
+ return constructor;
+ }
+
+ /*
+ * Find the matching parse node, answers null if nothing found
+ */
+ public FieldDeclaration declarationOf(FieldBinding fieldBinding) {
+ if (fieldBinding != null) {
+ for (int i = 0, max = this.fields.length; i < max; i++) {
+ FieldDeclaration fieldDecl;
+ if ((fieldDecl = this.fields[i]).binding == fieldBinding)
+ return fieldDecl;
+ }
+ }
+ return null;
+ }
+
+ /*
+ * Find the matching parse node, answers null if nothing found
+ */
+ public TypeDeclaration declarationOf(MemberTypeBinding memberTypeBinding) {
+ if (memberTypeBinding != null) {
+ for (int i = 0, max = this.memberTypes.length; i < max; i++) {
+ TypeDeclaration memberTypeDecl;
+ if ((memberTypeDecl = this.memberTypes[i]).binding == memberTypeBinding)
+ return memberTypeDecl;
+ }
+ }
+ return null;
+ }
+
+ /*
+ * Find the matching parse node, answers null if nothing found
+ */
+ public AbstractMethodDeclaration declarationOf(MethodBinding methodBinding) {
+ if (methodBinding != null) {
+ for (int i = 0, max = this.methods.length; i < max; i++) {
+ AbstractMethodDeclaration methodDecl;
+
+ if ((methodDecl = this.methods[i]).binding == methodBinding)
+ return methodDecl;
+ }
+ }
+ return null;
+ }
+
+ /*
+ * Finds the matching type amoung this type's member types.
+ * Returns null if no type with this name is found.
+ * The type name is a compound name relative to this type
+ * eg. if this type is X and we're looking for Y.X.A.B
+ * then a type name would be {X, A, B}
+ */
+ public TypeDeclaration declarationOfType(char[][] typeName) {
+ int typeNameLength = typeName.length;
+ if (typeNameLength < 1 || !CharOperation.equals(typeName[0], this.name)) {
+ return null;
+ }
+ if (typeNameLength == 1) {
+ return this;
+ }
+ char[][] subTypeName = new char[typeNameLength - 1][];
+ System.arraycopy(typeName, 1, subTypeName, 0, typeNameLength - 1);
+ for (int i = 0; i < this.memberTypes.length; i++) {
+ TypeDeclaration typeDecl = this.memberTypes[i].declarationOfType(subTypeName);
+ if (typeDecl != null) {
+ return typeDecl;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Generic bytecode generation for type
+ */
+ public void generateCode(ClassFile enclosingClassFile) {
+ if (ignoreFurtherInvestigation) {
+ if (binding == null)
+ return;
+ ClassFile.createProblemType(
+ this,
+ scope.referenceCompilationUnit().compilationResult);
+ return;
+ }
+ try {
+ // create the result for a compiled type
+ ClassFile classFile = new ClassFile(binding, enclosingClassFile, false);
+ // generate all fiels
+ classFile.addFieldInfos();
+
+ // record the inner type inside its own .class file to be able
+ // to generate inner classes attributes
+ if (binding.isMemberType())
+ classFile.recordEnclosingTypeAttributes(binding);
+ if (binding.isLocalType()) {
+ enclosingClassFile.recordNestedLocalAttribute(binding);
+ classFile.recordNestedLocalAttribute(binding);
+ }
+ if (memberTypes != null) {
+ for (int i = 0, max = memberTypes.length; i < max; i++) {
+ // record the inner type inside its own .class file to be able
+ // to generate inner classes attributes
+ classFile.recordNestedMemberAttribute(memberTypes[i].binding);
+ memberTypes[i].generateCode(scope, classFile);
+ }
+ }
+ // generate all methods
+ classFile.setForMethodInfos();
+ if (methods != null) {
+ for (int i = 0, max = methods.length; i < max; i++) {
+ methods[i].generateCode(scope, classFile);
+ }
+ }
+
+ // generate all methods
+ classFile.addSpecialMethods();
+
+ if (ignoreFurtherInvestigation) { // trigger problem type generation for code gen errors
+ throw new AbortType(scope.referenceCompilationUnit().compilationResult);
+ }
+
+ // finalize the compiled type result
+ classFile.addAttributes();
+ scope.referenceCompilationUnit().compilationResult.record(
+ binding.constantPoolName(),
+ classFile);
+ } catch (AbortType e) {
+ if (binding == null)
+ return;
+ ClassFile.createProblemType(
+ this,
+ scope.referenceCompilationUnit().compilationResult);
+ }
+ }
+
+ /**
+ * Bytecode generation for a local inner type (API as a normal statement code gen)
+ */
+ public void generateCode(BlockScope blockScope, CodeStream codeStream) {
+ int pc = codeStream.position;
+ if (binding != null) {
+ ((NestedTypeBinding) binding).computeSyntheticArgumentsOffset();
+ }
+ generateCode(codeStream.classFile);
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ /**
+ * Bytecode generation for a member inner type
+ */
+ public void generateCode(ClassScope classScope, ClassFile enclosingClassFile) {
+
+ ((NestedTypeBinding) binding).computeSyntheticArgumentsOffset();
+ generateCode(enclosingClassFile);
+ }
+
+ /**
+ * Bytecode generation for a package member
+ */
+ public void generateCode(CompilationUnitScope unitScope) {
+ generateCode((ClassFile) null);
+ }
+
+ public boolean isInterface() {
+
+ return (modifiers & AccInterface) != 0;
+ }
+
+ public final boolean needClassInitMethod() {
+ //the real test is next code but the test on NotAConstant is
+ //not valid UNTIL the TC has runned :-( .....
+ //More, the binding hasn't been done.....:-(....
+
+ //Thus the idea is therefore to generate a <clint> when some static
+ //fields exist. If it has no statement, it will not be generated
+
+ /*--------------------------------------------------
+ if ( fields == null ) return false;
+ for( int i = fields.length ; --i>= 0;){
+ FieldDeclaration field = fields[i];
+ if (field.binding.isStatic())
+ {if ( (field.binding.isFinal()) && (field.initialization == null) ) return true ;
+ if ( !field.isField()) return true ; //initializer are not-isField()
+ if ( (field.initialization != null) && (field.binding.constant == NotAConstant) ) return true ;}}
+
+ return false ;}
+ ----------------------------------------------------*/
+ if (fields == null)
+ return false;
+ if (isInterface())
+ return true; // fields are implicitly statics
+ for (int i = fields.length; --i >= 0;) {
+ FieldDeclaration field = fields[i];
+ //need to test the modifier directly while there is no binding yet
+ if ((field.modifiers & AccStatic) != 0)
+ return true;
+ }
+
+ return false;
+ }
+
+ public void parseMethod(Parser parser, CompilationUnitDeclaration unit) {
+ //connect method bodies
+ if (unit.ignoreMethodBodies)
+ return;
+
+ // no scope were created, so cannot report further errors
+ if (binding == null)
+ return;
+
+ //members
+ if (memberTypes != null) {
+ for (int i = memberTypes.length; --i >= 0;)
+ memberTypes[i].parseMethod(parser, unit);
+ }
+
+ //methods
+ if (methods != null) {
+ for (int i = methods.length; --i >= 0;)
+ methods[i].parseStatements(parser, unit);
+ }
+
+ //initializers
+ if (fields != null) {
+ for (int i = fields.length; --i >= 0;) {
+ if (fields[i] instanceof Initializer) {
+ ((Initializer) fields[i]).parseStatements(parser, this, unit);
+ }
+ }
+ }
+ }
+
+ public void resolve() {
+ if (binding == null) {
+ ignoreFurtherInvestigation = true;
+ return;
+ }
+
+ try {
+ // check superclass & interfaces
+ if (binding.superclass != null) // watch out for Object ! (and other roots)
+ if (isTypeUseDeprecated(binding.superclass, scope))
+ scope.problemReporter().deprecatedType(binding.superclass, superclass);
+ if (superInterfaces != null)
+ for (int i = superInterfaces.length; --i >= 0;)
+ if (superInterfaces[i].binding != null)
+ if (isTypeUseDeprecated(superInterfaces[i].binding, scope))
+ scope.problemReporter().deprecatedType(
+ superInterfaces[i].binding,
+ superInterfaces[i]);
+
+ maxFieldCount = 0;
+ int lastFieldID = -1;
+ if (fields != null) {
+ for (int i = 0, count = fields.length; i < count; i++) {
+ FieldDeclaration field = fields[i];
+ if (field.isField()) {
+ if (field.binding == null) {
+ ignoreFurtherInvestigation = true;
+ continue;
+ }
+ maxFieldCount++;
+ lastFieldID = field.binding.id;
+ } else { // initializer
+ ((Initializer) field).lastFieldID = lastFieldID + 1;
+ }
+ field.resolve(field.isStatic() ? staticInitializerScope : initializerScope);
+ }
+ }
+ if (memberTypes != null)
+ for (int i = 0, count = memberTypes.length; i < count; i++)
+ memberTypes[i].resolve(scope);
+ if (methods != null)
+ for (int i = 0, count = methods.length; i < count; i++)
+ methods[i].resolve(scope);
+ } catch (AbortType e) {
+ this.ignoreFurtherInvestigation = true;
+ return;
+ };
+ }
+
+ public void resolve(BlockScope blockScope) {
+ // local type declaration
+
+ // need to build its scope first and proceed with binding's creation
+ blockScope.addLocalType(this);
+
+ // and TC....
+ if (binding != null) {
+ // binding is not set if the receiver could not be created
+ resolve();
+ updateMaxFieldCount();
+ }
+ }
+
+ public void resolve(ClassScope upperScope) {
+ // member scopes are already created
+ // request the construction of a binding if local member type
+
+ resolve();
+ updateMaxFieldCount();
+ }
+
+ public void resolve(CompilationUnitScope upperScope) {
+ // top level : scope are already created
+
+ resolve();
+ updateMaxFieldCount();
+ }
+
+ public void tagAsHavingErrors() {
+ ignoreFurtherInvestigation = true;
+ }
+
+ public String toString(int tab) {
+ /*slow code */
+
+ return tabString(tab) + toStringHeader() + toStringBody(tab);
+ }
+
+ public String toStringBody(int tab) {
+ /*slow code */
+
+ String s = " {";
+ if (memberTypes != null) {
+ for (int i = 0; i < memberTypes.length; i++) {
+ if (memberTypes[i] != null) {
+ s += "\n" + memberTypes[i].toString(tab + 1);
+ }
+ }
+ }
+ if (fields != null) {
+ for (int fieldI = 0; fieldI < fields.length; fieldI++) {
+ if (fields[fieldI] != null) {
+ s += "\n" + fields[fieldI].toString(tab + 1);
+ if (fields[fieldI].isField())
+ s += ";";
+ }
+ }
+ }
+ if (methods != null) {
+ for (int i = 0; i < methods.length; i++) {
+ if (methods[i] != null) {
+ s += "\n" + methods[i].toString(tab + 1);
+ }
+ }
+ }
+ s += "\n" + tabString(tab) + "}";
+ return s;
+ }
+
+ public String toStringHeader() {
+ /*slow code */
+
+ String s = "";
+ if (modifiers != AccDefault) {
+ s += modifiersString(modifiers);
+ }
+ s += (isInterface() ? "interface " : "class ") + new String(name);
+ if (superclass != null)
+ s += " extends " + superclass.toString(0);
+ if (superInterfaces != null && superInterfaces.length > 0) {
+ s += (isInterface() ? " extends " : " implements ");
+ for (int i = 0; i < superInterfaces.length; i++) {
+ s += superInterfaces[i].toString(0);
+ if (i != superInterfaces.length - 1)
+ s += ", ";
+ };
+ };
+
+ return s;
+ }
+
+ /**
+ * Iteration for a local innertype
+ *
+ */
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ if (ignoreFurtherInvestigation)
+ return;
+ try {
+ if (visitor.visit(this, blockScope)) {
+ if (superclass != null)
+ superclass.traverse(visitor, scope);
+ if (superInterfaces != null) {
+ int superInterfaceLength = superInterfaces.length;
+ for (int i = 0; i < superInterfaceLength; i++)
+ superInterfaces[i].traverse(visitor, scope);
+ }
+ if (memberTypes != null) {
+ int memberTypesLength = memberTypes.length;
+ for (int i = 0; i < memberTypesLength; i++)
+ memberTypes[i].traverse(visitor, scope);
+ }
+ if (fields != null) {
+ int fieldsLength = fields.length;
+ for (int i = 0; i < fieldsLength; i++) {
+ FieldDeclaration field;
+ if ((field = fields[i]).isStatic()) {
+ // local type cannot have static fields
+ } else {
+ field.traverse(visitor, initializerScope);
+ }
+ }
+ }
+ if (methods != null) {
+ int methodsLength = methods.length;
+ for (int i = 0; i < methodsLength; i++)
+ methods[i].traverse(visitor, scope);
+ }
+ }
+ visitor.endVisit(this, blockScope);
+ } catch (AbortType e) {
+ }
+ }
+
+ /**
+ * Iteration for a member innertype
+ *
+ */
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ ClassScope classScope) {
+ if (ignoreFurtherInvestigation)
+ return;
+ try {
+ if (visitor.visit(this, classScope)) {
+ if (superclass != null)
+ superclass.traverse(visitor, scope);
+ if (superInterfaces != null) {
+ int superInterfaceLength = superInterfaces.length;
+ for (int i = 0; i < superInterfaceLength; i++)
+ superInterfaces[i].traverse(visitor, scope);
+ }
+ if (memberTypes != null) {
+ int memberTypesLength = memberTypes.length;
+ for (int i = 0; i < memberTypesLength; i++)
+ memberTypes[i].traverse(visitor, scope);
+ }
+ if (fields != null) {
+ int fieldsLength = fields.length;
+ for (int i = 0; i < fieldsLength; i++) {
+ FieldDeclaration field;
+ if ((field = fields[i]).isStatic()) {
+ field.traverse(visitor, staticInitializerScope);
+ } else {
+ field.traverse(visitor, initializerScope);
+ }
+ }
+ }
+ if (methods != null) {
+ int methodsLength = methods.length;
+ for (int i = 0; i < methodsLength; i++)
+ methods[i].traverse(visitor, scope);
+ }
+ }
+ visitor.endVisit(this, classScope);
+ } catch (AbortType e) {
+ }
+ }
+
+ /**
+ * Iteration for a package member type
+ *
+ */
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ CompilationUnitScope unitScope) {
+ if (ignoreFurtherInvestigation)
+ return;
+ try {
+ if (visitor.visit(this, unitScope)) {
+ if (superclass != null)
+ superclass.traverse(visitor, scope);
+ if (superInterfaces != null) {
+ int superInterfaceLength = superInterfaces.length;
+ for (int i = 0; i < superInterfaceLength; i++)
+ superInterfaces[i].traverse(visitor, scope);
+ }
+ if (memberTypes != null) {
+ int memberTypesLength = memberTypes.length;
+ for (int i = 0; i < memberTypesLength; i++)
+ memberTypes[i].traverse(visitor, scope);
+ }
+ if (fields != null) {
+ int fieldsLength = fields.length;
+ for (int i = 0; i < fieldsLength; i++) {
+ FieldDeclaration field;
+ if ((field = fields[i]).isStatic()) {
+ field.traverse(visitor, staticInitializerScope);
+ } else {
+ field.traverse(visitor, initializerScope);
+ }
+ }
+ }
+ if (methods != null) {
+ int methodsLength = methods.length;
+ for (int i = 0; i < methodsLength; i++)
+ methods[i].traverse(visitor, scope);
+ }
+ }
+ } catch (AbortType e) {
+ }
+ }
+
+ /**
+ * MaxFieldCount's computation is necessary so as to reserve space for
+ * the flow info field portions. It corresponds to the maximum amount of
+ * fields this class or one of its innertypes have.
+ *
+ * During name resolution, types are traversed, and the max field count is recorded
+ * on the outermost type. It is then propagated down during the flow analysis.
+ *
+ * This method is doing either up/down propagation.
+ */
+ void updateMaxFieldCount() {
+ if (binding == null)
+ return; // error scenario
+ TypeDeclaration outerMostType = scope.outerMostClassScope().referenceType();
+ if (maxFieldCount > outerMostType.maxFieldCount) {
+ outerMostType.maxFieldCount = maxFieldCount; // up
+ } else {
+ maxFieldCount = outerMostType.maxFieldCount; // down
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java
new file mode 100644
index 0000000000..87d8e49e03
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java
@@ -0,0 +1,107 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public abstract class TypeReference extends Expression {
+ public TypeBinding binding;
+ public TypeReference() {
+ super();
+ }
+
+ // allows us to trap completion & selection nodes
+
+ public void aboutToResolve(Scope scope) {
+ }
+
+ /*
+ * Answer a base type reference (can be an array of base type).
+ */
+ public static final TypeReference baseTypeReference(int baseType, int dim) {
+
+ if (dim == 0) {
+ switch (baseType) {
+ case (T_void) :
+ return new SingleTypeReference(VoidBinding.simpleName, 0);
+ case (T_boolean) :
+ return new SingleTypeReference(BooleanBinding.simpleName, 0);
+ case (T_char) :
+ return new SingleTypeReference(CharBinding.simpleName, 0);
+ case (T_float) :
+ return new SingleTypeReference(FloatBinding.simpleName, 0);
+ case (T_double) :
+ return new SingleTypeReference(DoubleBinding.simpleName, 0);
+ case (T_byte) :
+ return new SingleTypeReference(ByteBinding.simpleName, 0);
+ case (T_short) :
+ return new SingleTypeReference(ShortBinding.simpleName, 0);
+ case (T_int) :
+ return new SingleTypeReference(IntBinding.simpleName, 0);
+ default : //T_long
+ return new SingleTypeReference(LongBinding.simpleName, 0);
+ }
+ }
+ switch (baseType) {
+ case (T_void) :
+ return new ArrayTypeReference(VoidBinding.simpleName, dim, 0);
+ case (T_boolean) :
+ return new ArrayTypeReference(BooleanBinding.simpleName, dim, 0);
+ case (T_char) :
+ return new ArrayTypeReference(CharBinding.simpleName, dim, 0);
+ case (T_float) :
+ return new ArrayTypeReference(FloatBinding.simpleName, dim, 0);
+ case (T_double) :
+ return new ArrayTypeReference(DoubleBinding.simpleName, dim, 0);
+ case (T_byte) :
+ return new ArrayTypeReference(ByteBinding.simpleName, dim, 0);
+ case (T_short) :
+ return new ArrayTypeReference(ShortBinding.simpleName, dim, 0);
+ case (T_int) :
+ return new ArrayTypeReference(IntBinding.simpleName, dim, 0);
+ default : //T_long
+ return new ArrayTypeReference(LongBinding.simpleName, dim, 0);
+ }
+ }
+
+ public abstract TypeReference copyDims(int dim);
+ public int dimensions() {
+ return 0;
+ }
+
+ public abstract TypeBinding getTypeBinding(Scope scope);
+ /**
+ * @return char[][]
+ */
+ public abstract char[][] getTypeName();
+ public boolean isTypeReference() {
+ return true;
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ // handle the error here
+ constant = NotAConstant;
+ if (binding != null) {
+ // is a shared type reference which was already resolved
+ if (!binding.isValidBinding())
+ return null; // already reported error
+ } else {
+ binding = getTypeBinding(scope);
+ if (!binding.isValidBinding()) {
+ scope.problemReporter().invalidType(this, binding);
+ return null;
+ }
+ if (isTypeUseDeprecated(binding, scope))
+ scope.problemReporter().deprecatedType(binding, this);
+ }
+ return binding;
+ }
+
+ public abstract void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ ClassScope classScope);
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java
new file mode 100644
index 0000000000..ba50cd5d31
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java
@@ -0,0 +1,299 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class UnaryExpression extends OperatorExpression {
+ public Expression expression;
+ public Constant optimizedBooleanConstant;
+
+ public UnaryExpression(Expression expression, int operator) {
+ this.expression = expression;
+ this.bits |= operator << OperatorSHIFT; // encode operator
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
+ return expression
+ .analyseCode(currentScope, flowContext, flowInfo)
+ .asNegatedCondition();
+ } else {
+ return expression.analyseCode(currentScope, flowContext, flowInfo);
+ }
+ }
+
+ public Constant conditionalConstant() {
+
+ return optimizedBooleanConstant == null ? constant : optimizedBooleanConstant;
+ }
+
+ /**
+ * Code generation for an unary operation
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param valueRequired boolean
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ Label falseLabel, endifLabel;
+ if (constant != Constant.NotAConstant) {
+ // inlined value
+ if (valueRequired) {
+ codeStream.generateConstant(constant, implicitConversion);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ switch ((bits & OperatorMASK) >> OperatorSHIFT) {
+ case NOT :
+ switch (expression.implicitConversion >> 4) /* runtime type */ {
+ case T_boolean :
+ // ! <boolean>
+ // Generate code for the condition
+ expression.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ null,
+ (falseLabel = new Label(codeStream)),
+ valueRequired);
+ if (valueRequired) {
+ codeStream.iconst_0();
+ codeStream.goto_(endifLabel = new Label(codeStream));
+ codeStream.decrStackSize(1);
+ falseLabel.place();
+ if (valueRequired)
+ codeStream.iconst_1();
+ endifLabel.place();
+ }
+ break;
+ }
+ break;
+ case TWIDDLE :
+ switch (expression.implicitConversion >> 4 /* runtime */
+ ) {
+ case T_int :
+ // ~int
+ expression.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ codeStream.iconst_m1();
+ codeStream.ixor();
+ }
+ break;
+ case T_long :
+ expression.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ codeStream.ldc2_w(-1L);
+ codeStream.lxor();
+ }
+ }
+ break;
+ case MINUS :
+ // - <num>
+ if (constant != NotAConstant) {
+ if (valueRequired) {
+ switch (expression.implicitConversion >> 4 /* runtime */
+ ) {
+ case T_int :
+ codeStream.generateInlinedValue(constant.intValue() * -1);
+ break;
+ case T_float :
+ codeStream.generateInlinedValue(constant.floatValue() * -1.0f);
+ break;
+ case T_long :
+ codeStream.generateInlinedValue(constant.longValue() * -1L);
+ break;
+ case T_double :
+ codeStream.generateInlinedValue(constant.doubleValue() * -1.0);
+ }
+ }
+ } else {
+ expression.generateCode(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ switch (expression.implicitConversion >> 4 /* runtime type */
+ ) {
+ case T_int :
+ codeStream.ineg();
+ break;
+ case T_float :
+ codeStream.fneg();
+ break;
+ case T_long :
+ codeStream.lneg();
+ break;
+ case T_double :
+ codeStream.dneg();
+ }
+ }
+ }
+ break;
+ case PLUS :
+ expression.generateCode(currentScope, codeStream, valueRequired);
+ }
+ if (valueRequired) {
+ codeStream.generateImplicitConversion(implicitConversion);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ /**
+ * Boolean operator code generation
+ * Optimized operations are: &&, ||, <, <=, >, >=, &, |, ^
+ */
+ public void generateOptimizedBoolean(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Label trueLabel,
+ Label falseLabel,
+ boolean valueRequired) {
+
+ if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) {
+ int pc = codeStream.position;
+ if (constant.booleanValue() == true) {
+ // constant == true
+ if (valueRequired) {
+ if (falseLabel == null) {
+ // implicit falling through the FALSE case
+ if (trueLabel != null) {
+ codeStream.goto_(trueLabel);
+ }
+ }
+ }
+ } else {
+ if (valueRequired) {
+ if (falseLabel != null) {
+ // implicit falling through the TRUE case
+ if (trueLabel == null) {
+ codeStream.goto_(falseLabel);
+ }
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ return;
+ }
+ if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
+ expression.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ falseLabel,
+ trueLabel,
+ valueRequired);
+ } else {
+ super.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ trueLabel,
+ falseLabel,
+ valueRequired);
+ }
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ TypeBinding expressionTb = expression.resolveType(scope);
+ if (expressionTb == null) {
+ constant = NotAConstant;
+ return null;
+ }
+ int expressionId = expressionTb.id;
+ if (expressionId > 15) {
+ constant = NotAConstant;
+ scope.problemReporter().invalidOperator(this, expressionTb);
+ return null;
+ }
+
+ int tableId;
+ switch ((bits & OperatorMASK) >> OperatorSHIFT) {
+ case NOT :
+ tableId = AND_AND;
+ break;
+ case TWIDDLE :
+ tableId = LEFT_SHIFT;
+ break;
+ default :
+ tableId = MINUS;
+ } //+ and - cases
+
+ // the code is an int
+ // (cast) left Op (cast) rigth --> result
+ // 0000 0000 0000 0000 0000
+ // <<16 <<12 <<8 <<4 <<0
+ int result = ResolveTypeTables[tableId][(expressionId << 4) + expressionId];
+ expression.implicitConversion = result >>> 12;
+ TypeBinding type;
+ switch (result & 0x0000F) { // only switch on possible result type.....
+ case T_boolean :
+ type = BooleanBinding;
+ break;
+ case T_byte :
+ type = ByteBinding;
+ break;
+ case T_char :
+ type = CharBinding;
+ break;
+ case T_double :
+ type = DoubleBinding;
+ break;
+ case T_float :
+ type = FloatBinding;
+ break;
+ case T_int :
+ type = IntBinding;
+ break;
+ case T_long :
+ type = LongBinding;
+ break;
+ default : //error........
+ constant = Constant.NotAConstant;
+ if (expressionId != T_undefined)
+ scope.problemReporter().invalidOperator(this, expressionTb);
+ return null;
+ }
+
+ // compute the constant when valid
+ if (expression.constant != Constant.NotAConstant) {
+ constant =
+ Constant.computeConstantOperation(
+ expression.constant,
+ expressionId,
+ (bits & OperatorMASK) >> OperatorSHIFT);
+ } else {
+ constant = Constant.NotAConstant;
+ if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
+ Constant cst = expression.conditionalConstant();
+ if (cst.typeID() == T_boolean)
+ optimizedBooleanConstant = Constant.fromValue(!cst.booleanValue());
+ }
+ }
+ return type;
+ }
+
+ public String toStringExpressionNoParenthesis() {
+ /* slow code*/
+
+ return operatorToString() + " " + expression.toStringExpression();
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ if (visitor.visit(this, blockScope)) {
+ expression.traverse(visitor, blockScope);
+ }
+ visitor.endVisit(this, blockScope);
+ }
+
+}
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
new file mode 100644
index 0000000000..01a3518bec
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java
@@ -0,0 +1,226 @@
+package org.eclipse.jdt.internal.compiler.ast;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class WhileStatement extends Statement {
+ public Expression condition;
+ public Statement action;
+
+ private Label breakLabel, continueLabel;
+
+ int preCondInitStateIndex = -1;
+ int condIfTrueInitStateIndex = -1;
+ int mergedInitStateIndex = -1;
+ public WhileStatement(Expression condition, Statement action, int s, int e) {
+ this.condition = condition;
+ this.action = action;
+ sourceStart = s;
+ sourceEnd = e;
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo) {
+ breakLabel = new Label();
+ continueLabel = new Label();
+
+ preCondInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(flowInfo);
+ LoopingFlowContext condLoopContext;
+ FlowInfo postCondInfo =
+ condition.analyseCode(
+ currentScope,
+ (condLoopContext =
+ new LoopingFlowContext(flowContext, this, null, null, currentScope)),
+ flowInfo);
+ condLoopContext.complainOnFinalAssignmentsInLoop(currentScope, postCondInfo);
+
+ LoopingFlowContext loopingContext;
+ if ((action == null) || action.isEmptyBlock()) {
+ if ((condition.constant != NotAConstant)
+ && (condition.constant.booleanValue() == true)) {
+ return FlowInfo.DeadEnd;
+ } else {
+ FlowInfo mergedInfo = postCondInfo.initsWhenFalse().unconditionalInits();
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(mergedInfo);
+ return mergedInfo;
+ }
+ } else {
+ // in case the condition was inlined to false, record the fact that there is no way to reach any
+ // statement inside the looping action
+ loopingContext =
+ new LoopingFlowContext(
+ flowContext,
+ this,
+ breakLabel,
+ continueLabel,
+ currentScope);
+ FlowInfo actionInfo =
+ ((condition.constant != Constant.NotAConstant)
+ && (condition.constant.booleanValue() == false))
+ ? FlowInfo.DeadEnd
+ : postCondInfo.initsWhenTrue().copy();
+
+ // for computing local var attributes
+ condIfTrueInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(
+ postCondInfo.initsWhenTrue());
+
+ if (!actionInfo.complainIfUnreachable(action, currentScope)) {
+ actionInfo = action.analyseCode(currentScope, loopingContext, actionInfo);
+ }
+
+ // code generation can be optimized when no need to continue in the loop
+ if ((actionInfo == FlowInfo.DeadEnd) || actionInfo.isFakeReachable()) {
+ if ((loopingContext.initsOnContinue == FlowInfo.DeadEnd)
+ || loopingContext.initsOnContinue.isFakeReachable()) {
+ continueLabel = null;
+ } else {
+ loopingContext.complainOnFinalAssignmentsInLoop(
+ currentScope,
+ loopingContext.initsOnContinue);
+ }
+ } else {
+ loopingContext.complainOnFinalAssignmentsInLoop(currentScope, actionInfo);
+ }
+ }
+
+ // infinite loop
+ FlowInfo mergedInfo;
+ if ((condition.constant != Constant.NotAConstant)
+ && (condition.constant.booleanValue() == true)) {
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(
+ mergedInfo = loopingContext.initsOnBreak);
+ return mergedInfo;
+ }
+
+ // end of loop: either condition false or break
+ mergedInfo =
+ postCondInfo.initsWhenFalse().unconditionalInits().mergedWith(
+ loopingContext.initsOnBreak);
+ mergedInitStateIndex =
+ currentScope.methodScope().recordInitializationStates(mergedInfo);
+ return mergedInfo;
+ }
+
+ /**
+ * While code generation
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ */
+ public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+ if ((bits & IsReachableMASK) == 0) {
+ return;
+ }
+ int pc = codeStream.position;
+ breakLabel.codeStream = codeStream;
+
+ // generate condition
+ if (continueLabel == null) {
+ // no need to reverse condition
+ if (condition.constant == NotAConstant) {
+ condition.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ null,
+ breakLabel,
+ true);
+ }
+ } else {
+ continueLabel.codeStream = codeStream;
+ if (!(((condition.constant != NotAConstant)
+ && (condition.constant.booleanValue() == true))
+ || (action == null)
+ || action.isEmptyBlock())) {
+ int jumpPC = codeStream.position;
+ codeStream.goto_(continueLabel);
+ codeStream.recordPositionsFrom(jumpPC, condition);
+ }
+ }
+ // generate the action
+ Label actionLabel;
+ (actionLabel = new Label(codeStream)).place();
+ if (action != null) {
+ // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect
+ if (condIfTrueInitStateIndex != -1) {
+ // insert all locals initialized inside the condition into the action generated prior to the condition
+ codeStream.addDefinitelyAssignedVariables(
+ currentScope,
+ condIfTrueInitStateIndex);
+ }
+ action.generateCode(currentScope, codeStream);
+ // May loose some local variable initializations : affecting the local variable attributes
+ if (preCondInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ preCondInitStateIndex);
+ }
+
+ }
+ // output condition and branch back to the beginning of the repeated action
+ if (continueLabel != null) {
+ continueLabel.place();
+ condition.generateOptimizedBoolean(
+ currentScope,
+ codeStream,
+ actionLabel,
+ null,
+ true);
+ }
+ breakLabel.place();
+
+ // May loose some local variable initializations : affecting the local variable attributes
+ if (mergedInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(
+ currentScope,
+ mergedInitStateIndex);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public void resolve(BlockScope scope) {
+ TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding);
+ condition.implicitWidening(type, type);
+ if (action != null)
+ action.resolve(scope);
+ }
+
+ public String toString(int tab) {
+ /* slow code */
+
+ String s = tabString(tab);
+ s = s + "while (" + condition.toStringExpression() + ")";
+ if (action == null)
+ s = s + " {} ;";
+ else
+ if (action instanceof Block)
+ s = s + "\n" + action.toString(tab + 1);
+ else
+ s = s + " {\n" + action.toString(tab + 1) + "}";
+ return s;
+ }
+
+ public void traverse(
+ IAbstractSyntaxTreeVisitor visitor,
+ BlockScope blockScope) {
+ if (visitor.visit(this, blockScope)) {
+ condition.traverse(visitor, blockScope);
+ if (action != null)
+ action.traverse(visitor, blockScope);
+ }
+ visitor.endVisit(this, blockScope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileConstants.java
new file mode 100644
index 0000000000..864154ca79
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileConstants.java
@@ -0,0 +1,34 @@
+package org.eclipse.jdt.internal.compiler.classfmt;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.*;
+
+public interface ClassFileConstants extends IConstants {
+
+ int Utf8Tag = 1;
+ int IntegerTag = 3;
+ int FloatTag = 4;
+ int LongTag = 5;
+ int DoubleTag = 6;
+ int ClassTag = 7;
+ int StringTag = 8;
+ int FieldRefTag = 9;
+ int MethodRefTag = 10;
+ int InterfaceMethodRefTag = 11;
+ int NameAndTypeTag = 12;
+
+ int ConstantMethodRefFixedSize = 5;
+ int ConstantClassFixedSize = 3;
+ int ConstantDoubleFixedSize = 9;
+ int ConstantFieldRefFixedSize = 5;
+ int ConstantFloatFixedSize = 5;
+ int ConstantIntegerFixedSize = 5;
+ int ConstantInterfaceMethodRefFixedSize = 5;
+ int ConstantLongFixedSize = 9;
+ int ConstantStringFixedSize = 3;
+ int ConstantUtf8FixedSize = 3;
+ int ConstantNameAndTypeFixedSize = 5;
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
new file mode 100644
index 0000000000..7b95830299
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
@@ -0,0 +1,564 @@
+package org.eclipse.jdt.internal.compiler.classfmt;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.*;
+
+import org.eclipse.jdt.internal.compiler.util.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+
+import java.io.*;
+
+public class ClassFileReader
+ extends ClassFileStruct
+ implements AttributeNamesConstants, IBinaryType {
+ private int constantPoolCount;
+ private int[] constantPoolOffsets;
+ private int accessFlags;
+ private char[] className;
+ private char[] superclassName;
+ private int interfacesCount;
+ private char[][] interfaceNames;
+ private int fieldsCount;
+ private FieldInfo[] fields;
+ private int methodsCount;
+ private MethodInfo[] methods;
+ private InnerClassInfo[] innerInfos;
+ private char[] sourceFileName;
+ // initialized in case the .class file is a nested type
+ private InnerClassInfo innerInfo;
+ private char[] classFileName;
+ private int classNameIndex;
+ private int innerInfoIndex;
+ /**
+ * @param classFileBytes actual bytes of a .class file
+ * @param fileName actual name of the file that contains the bytes, can be null
+ */
+ public ClassFileReader(byte classFileBytes[], char[] fileName)
+ throws ClassFormatException {
+ // This method looks ugly but is actually quite simple, the constantPool is constructed
+ // in 3 passes. All non-primitive constant pool members that usually refer to other members
+ // by index are tweaked to have their value in inst vars, this minor cost at read-time makes
+ // all subsequent uses of the constant pool element faster.
+ super(classFileBytes, 0);
+ classFileName = fileName;
+ int readOffset = 10;
+ try {
+ constantPoolCount = this.u2At(8);
+ // Pass #1 - Fill in all primitive constants
+ constantPoolOffsets = new int[constantPoolCount];
+ for (int i = 1; i < constantPoolCount; i++) {
+ int tag = this.u1At(readOffset);
+ switch (tag) {
+ case Utf8Tag :
+ constantPoolOffsets[i] = readOffset;
+ readOffset += u2At(readOffset + 1);
+ readOffset += ConstantUtf8FixedSize;
+ break;
+ case IntegerTag :
+ constantPoolOffsets[i] = readOffset;
+ readOffset += ConstantIntegerFixedSize;
+ break;
+ case FloatTag :
+ constantPoolOffsets[i] = readOffset;
+ readOffset += ConstantFloatFixedSize;
+ break;
+ case LongTag :
+ constantPoolOffsets[i] = readOffset;
+ readOffset += ConstantLongFixedSize;
+ i++;
+ break;
+ case DoubleTag :
+ constantPoolOffsets[i] = readOffset;
+ readOffset += ConstantDoubleFixedSize;
+ i++;
+ break;
+ case ClassTag :
+ constantPoolOffsets[i] = readOffset;
+ readOffset += ConstantClassFixedSize;
+ break;
+ case StringTag :
+ constantPoolOffsets[i] = readOffset;
+ readOffset += ConstantStringFixedSize;
+ break;
+ case FieldRefTag :
+ constantPoolOffsets[i] = readOffset;
+ readOffset += ConstantFieldRefFixedSize;
+ break;
+ case MethodRefTag :
+ constantPoolOffsets[i] = readOffset;
+ readOffset += ConstantMethodRefFixedSize;
+ break;
+ case InterfaceMethodRefTag :
+ constantPoolOffsets[i] = readOffset;
+ readOffset += ConstantInterfaceMethodRefFixedSize;
+ break;
+ case NameAndTypeTag :
+ constantPoolOffsets[i] = readOffset;
+ readOffset += ConstantNameAndTypeFixedSize;
+ }
+ }
+ // Read and validate access flags
+ accessFlags = u2At(readOffset);
+ readOffset += 2;
+
+ // Read the classname, use exception handlers to catch bad format
+ classNameIndex = u2At(readOffset);
+ className = getConstantClassNameAt(classNameIndex);
+ readOffset += 2;
+
+ // Read the superclass name, can be null for java.lang.Object
+ int superclassNameIndex = u2At(readOffset);
+ readOffset += 2;
+ // if superclassNameIndex is equals to 0 there is no need to set a value for the
+ // field superclassName. null is fine.
+ if (superclassNameIndex != 0) {
+ superclassName = getConstantClassNameAt(superclassNameIndex);
+ }
+
+ // Read the interfaces, use exception handlers to catch bad format
+ interfacesCount = u2At(readOffset);
+ readOffset += 2;
+ if (interfacesCount != 0) {
+ interfaceNames = new char[interfacesCount][];
+ for (int i = 0; i < interfacesCount; i++) {
+ interfaceNames[i] = getConstantClassNameAt(u2At(readOffset));
+ readOffset += 2;
+ }
+ }
+ // Read the fields, use exception handlers to catch bad format
+ fieldsCount = u2At(readOffset);
+ readOffset += 2;
+ if (fieldsCount != 0) {
+ FieldInfo field;
+ fields = new FieldInfo[fieldsCount];
+ for (int i = 0; i < fieldsCount; i++) {
+ field = new FieldInfo(reference, constantPoolOffsets, readOffset);
+ fields[i] = field;
+ readOffset += field.sizeInBytes();
+ }
+ }
+ // Read the methods
+ methodsCount = u2At(readOffset);
+ readOffset += 2;
+ if (methodsCount != 0) {
+ methods = new MethodInfo[methodsCount];
+ MethodInfo method;
+ for (int i = 0; i < methodsCount; i++) {
+ method = new MethodInfo(reference, constantPoolOffsets, readOffset);
+ methods[i] = method;
+ readOffset += method.sizeInBytes();
+ }
+ }
+
+ // Read the attributes
+ int attributesCount = u2At(readOffset);
+ readOffset += 2;
+
+ for (int i = 0; i < attributesCount; i++) {
+ int utf8Offset = constantPoolOffsets[u2At(readOffset)];
+ char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+ if (CharOperation.equals(attributeName, DeprecatedName)) {
+ accessFlags |= AccDeprecated;
+ } else {
+ if (CharOperation.equals(attributeName, InnerClassName)) {
+ int innerOffset = readOffset + 6;
+ int number_of_classes = u2At(innerOffset);
+ if (number_of_classes != 0) {
+ innerInfos = new InnerClassInfo[number_of_classes];
+ for (int j = 0; j < number_of_classes; j++) {
+ innerInfos[j] =
+ new InnerClassInfo(reference, constantPoolOffsets, innerOffset + 2);
+ if (classNameIndex == innerInfos[j].innerClassNameIndex) {
+ innerInfo = innerInfos[j];
+ innerInfoIndex = j;
+ }
+ innerOffset += 8;
+ }
+ }
+ } else {
+ if (CharOperation.equals(attributeName, SourceName)) {
+ utf8Offset = constantPoolOffsets[u2At(readOffset + 6)];
+ sourceFileName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+ } else {
+ if (CharOperation.equals(attributeName, SyntheticName)) {
+ accessFlags |= AccSynthetic;
+ }
+ }
+ }
+ }
+ readOffset += (6 + u4At(readOffset + 2));
+ }
+ } catch (Exception e) {
+ throw new ClassFormatException(
+ ClassFormatException.ErrTruncatedInput,
+ readOffset);
+ }
+ }
+
+ /**
+ * Answer the receiver's access flags. The value of the access_flags
+ * item is a mask of modifiers used with class and interface declarations.
+ * @return int
+ */
+ public int accessFlags() {
+ return accessFlags;
+ }
+
+ /**
+ * (c)1998 Object Technology International.
+ * (c)1998 International Business Machines Corporation.
+ *
+ * Answer the char array that corresponds to the class name of the constant class.
+ * constantPoolIndex is the index in the constant pool that is a constant class entry.
+ *
+ * @param int constantPoolIndex
+ * @return char[]
+ */
+ private char[] getConstantClassNameAt(int constantPoolIndex) {
+ int utf8Offset =
+ constantPoolOffsets[u2At(constantPoolOffsets[constantPoolIndex] + 1)];
+ return utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+ }
+
+ /**
+ * Answer the int array that corresponds to all the offsets of each entry in the constant pool
+ *
+ * @return int[]
+ */
+ public int[] getConstantPoolOffsets() {
+ return constantPoolOffsets;
+ }
+
+ /*
+ * Answer the resolved compoundName of the enclosing type
+ * or null if the receiver is a top level type.
+ */
+ public char[] getEnclosingTypeName() {
+ if (innerInfo != null) {
+ return innerInfo.getEnclosingTypeName();
+ }
+ return null;
+ }
+
+ /**
+ * Answer the receiver's fields or null if the array is empty.
+ * @return org.eclipse.jdt.internal.compiler.api.IBinaryField[]
+ */
+ public IBinaryField[] getFields() {
+ return fields;
+ }
+
+ /**
+ * Answer the file name which defines the type.
+ * The format is unspecified.
+ */
+ public char[] getFileName() {
+ return classFileName;
+ }
+
+ /**
+ * Answer the source name if the receiver is a inner type. Return null if it is an anonymous class or if the receiver is a top-level class.
+ * e.g.
+ * public class A {
+ * public class B {
+ * }
+ * public void foo() {
+ * class C {}
+ * }
+ * public Runnable bar() {
+ * return new Runnable() {
+ * public void run() {}
+ * };
+ * }
+ * }
+ * It returns {'B'} for the member A$B
+ * It returns null for A
+ * It returns {'C'} for the local class A$1$C
+ * It returns null for the anonymous A$1
+ * @return char[]
+ */
+ public char[] getInnerSourceName() {
+ if (innerInfo != null)
+ return innerInfo.getSourceName();
+ return null;
+ }
+
+ /**
+ * Answer the resolved names of the receiver's interfaces in the
+ * class file format as specified in section 4.2 of the Java 2 VM spec
+ * or null if the array is empty.
+ *
+ * For example, java.lang.String is java/lang/String.
+ * @return char[][]
+ */
+ public char[][] getInterfaceNames() {
+ return interfaceNames;
+ }
+
+ /**
+ * Answer the receiver's nested types or null if the array is empty.
+ *
+ * This nested type info is extracted from the inner class attributes.
+ * Ask the name environment to find a member type using its compound name
+ * @return org.eclipse.jdt.internal.compiler.api.IBinaryNestedType[]
+ */
+ public IBinaryNestedType[] getMemberTypes() {
+ // we might have some member types of the current type
+ if (innerInfos == null)
+ return null;
+
+ int length = innerInfos.length;
+ int startingIndex = innerInfo != null ? innerInfoIndex + 1 : 0;
+ if (length != startingIndex) {
+ IBinaryNestedType[] memberTypes =
+ new IBinaryNestedType[length - innerInfoIndex];
+ int memberTypeIndex = 0;
+ for (int i = startingIndex; i < length; i++) {
+ InnerClassInfo currentInnerInfo = innerInfos[i];
+ int outerClassNameIdx = currentInnerInfo.outerClassNameIndex;
+ if (outerClassNameIdx != 0 && outerClassNameIdx == classNameIndex) {
+ memberTypes[memberTypeIndex++] = currentInnerInfo;
+ }
+ }
+ if (memberTypeIndex == 0)
+ return null;
+ if (memberTypeIndex != memberTypes.length) {
+ // we need to resize the memberTypes array. Some local or anonymous classes
+ // are present in the current class.
+ System.arraycopy(
+ memberTypes,
+ 0,
+ (memberTypes = new IBinaryNestedType[memberTypeIndex]),
+ 0,
+ memberTypeIndex);
+ }
+ return memberTypes;
+ }
+ return null;
+ }
+
+ /**
+ * Answer the receiver's methods or null if the array is empty.
+ * @return org.eclipse.jdt.internal.compiler.api.env.IBinaryMethod[]
+ */
+ public IBinaryMethod[] getMethods() {
+ return methods;
+ }
+
+ /**
+ * Answer an int whose bits are set according the access constants
+ * defined by the VM spec.
+ * Set the AccDeprecated and AccSynthetic bits if necessary
+ * @return int
+ */
+ public int getModifiers() {
+ if (innerInfo != null) {
+ return innerInfo.getModifiers();
+ }
+ return accessFlags;
+ }
+
+ /**
+ * Answer the resolved name of the type in the
+ * class file format as specified in section 4.2 of the Java 2 VM spec.
+ *
+ * For example, java.lang.String is java/lang/String.
+ * @return char[]
+ */
+ public char[] getName() {
+ return className;
+ }
+
+ /**
+ * Answer the resolved name of the receiver's superclass in the
+ * class file format as specified in section 4.2 of the Java 2 VM spec
+ * or null if it does not have one.
+ *
+ * For example, java.lang.String is java/lang/String.
+ * @return char[]
+ */
+ public char[] getSuperclassName() {
+ return superclassName;
+ }
+
+ /**
+ * Answer true if the receiver is an anonymous type, false otherwise
+ *
+ * @return <CODE>boolean</CODE>
+ */
+ public boolean isAnonymous() {
+ return innerInfo != null
+ && innerInfo.getEnclosingTypeName() == null
+ && innerInfo.getSourceName() == null;
+ }
+
+ /**
+ * Answer whether the receiver contains the resolved binary form
+ * or the unresolved source form of the type.
+ * @return boolean
+ */
+ public boolean isBinaryType() {
+ return true;
+ }
+
+ /**
+ * Answer true if the receiver is a class. False otherwise.
+ * @return boolean
+ */
+ public boolean isClass() {
+ return (getModifiers() & AccInterface) == 0;
+ }
+
+ /**
+ * Answer true if the receiver is an interface. False otherwise.
+ * @return boolean
+ */
+ public boolean isInterface() {
+ return (getModifiers() & AccInterface) != 0;
+ }
+
+ /**
+ * Answer true if the receiver is a local type, false otherwise
+ *
+ * @return <CODE>boolean</CODE>
+ */
+ public boolean isLocal() {
+ return innerInfo != null
+ && innerInfo.getEnclosingTypeName() == null
+ && innerInfo.getSourceName() != null;
+ }
+
+ /**
+ * Answer true if the receiver is a member type, false otherwise
+ *
+ * @return <CODE>boolean</CODE>
+ */
+ public boolean isMember() {
+ return innerInfo != null && innerInfo.getEnclosingTypeName() != null;
+ }
+
+ /**
+ * Answer true if the receiver is a nested type, false otherwise
+ *
+ * @return <CODE>boolean</CODE>
+ */
+ public boolean isNestedType() {
+ return innerInfo != null;
+ }
+
+ /**
+ * (c)1998 Object Technology International.
+ * (c)1998 International Business Machines Corporation.
+ *
+ * @param file The file you want to read
+ * @return org.eclipse.jdt.internal.compiler.classfmt.DietClassFile
+ */
+ public static ClassFileReader read(java.io.File file)
+ throws ClassFormatException, java.io.IOException {
+ int fileLength;
+ byte classFileBytes[] = new byte[fileLength = (int) file.length()];
+ java.io.FileInputStream stream = new java.io.FileInputStream(file);
+ int bytesRead = 0;
+ int lastReadSize = 0;
+ while ((lastReadSize != -1) && (bytesRead != fileLength)) {
+ lastReadSize = stream.read(classFileBytes, bytesRead, fileLength - bytesRead);
+ bytesRead += lastReadSize;
+ }
+ ClassFileReader classFile =
+ new ClassFileReader(classFileBytes, file.getAbsolutePath().toCharArray());
+ stream.close();
+ return classFile;
+ }
+
+ /**
+ * (c)1998 Object Technology International.
+ * (c)1998 International Business Machines Corporation.
+ *
+ * @param String fileName
+ */
+ public static ClassFileReader read(String fileName)
+ throws ClassFormatException, java.io.IOException {
+ int fileLength;
+ File file = new File(fileName);
+ byte classFileBytes[] = new byte[fileLength = (int) file.length()];
+ java.io.FileInputStream stream = new java.io.FileInputStream(file);
+ int bytesRead = 0;
+ int lastReadSize = 0;
+ while ((lastReadSize != -1) && (bytesRead != fileLength)) {
+ lastReadSize = stream.read(classFileBytes, bytesRead, fileLength - bytesRead);
+ bytesRead += lastReadSize;
+ }
+ ClassFileReader classFile =
+ new ClassFileReader(classFileBytes, fileName.toCharArray());
+ stream.close();
+ return classFile;
+ }
+
+ /**
+ * (c)1998 Object Technology International.
+ * (c)1998 International Business Machines Corporation.
+ *
+ * @param java.util.zip.ZipFile zip
+ * @param java.lang.String filename
+ * @return org.eclipse.jdt.internal.compiler.classfmt.DietClassFile
+ */
+ public static ClassFileReader read(java.util.zip.ZipFile zip, String filename)
+ throws ClassFormatException, java.io.IOException {
+ java.util.zip.ZipEntry ze = zip.getEntry(filename);
+ if (ze == null)
+ return null;
+ java.io.InputStream zipInputStream = zip.getInputStream(ze);
+ byte classFileBytes[] = new byte[(int) ze.getSize()];
+ int length = classFileBytes.length;
+ int len = 0;
+ int readSize = 0;
+ while ((readSize != -1) && (len != length)) {
+ readSize = zipInputStream.read(classFileBytes, len, length - len);
+ len += readSize;
+ }
+ zipInputStream.close();
+ return new ClassFileReader(classFileBytes, filename.toCharArray());
+ }
+
+ /**
+ * (c)1998 Object Technology International.
+ * (c)1998 International Business Machines Corporation.
+ *
+ * Answer the source file name attribute. Return null if there is no source file attribute for the receiver.
+ *
+ * @return char[]
+ */
+ public char[] sourceFileName() {
+ return sourceFileName;
+ }
+
+ /**
+ * (c)1998 Object Technology International.
+ * (c)1998 International Business Machines Corporation.
+ *
+ *
+ */
+ public String toString() {
+ java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream();
+ java.io.PrintWriter print = new java.io.PrintWriter(out);
+
+ print.println(this.getClass().getName() + "{");
+ print.println(" className: " + new String(getName()));
+ print.println(
+ " superclassName: "
+ + (getSuperclassName() == null ? "null" : new String(getSuperclassName())));
+ print.println(
+ " access_flags: "
+ + ClassFileStruct.printTypeModifiers(accessFlags())
+ + "("
+ + accessFlags()
+ + ")");
+
+ print.flush();
+ return out.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileStruct.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileStruct.java
new file mode 100644
index 0000000000..beaf57797e
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileStruct.java
@@ -0,0 +1,324 @@
+package org.eclipse.jdt.internal.compiler.classfmt;
+
+abstract public class ClassFileStruct implements ClassFileConstants {
+ byte[] reference;
+ int structOffset;
+ /**
+ * (c)1998 Object Technology International.
+ * (c)1998 International Business Machines Corporation.
+ *
+ *
+ * @param classFileBytes byte[]
+ * @param offset int
+ */
+ public ClassFileStruct(byte classFileBytes[], int off) {
+ reference = classFileBytes;
+ structOffset = off;
+ }
+
+ /**
+ * (c)1998 Object Technology International.
+ * (c)1998 International Business Machines Corporation.
+ *
+ *
+ * @param classFileBytes byte[]
+ * @param offset int
+ * @param verifyStructure boolean
+ */
+ public ClassFileStruct(
+ byte classFileBytes[],
+ int off,
+ boolean verifyStructure) {
+ reference = classFileBytes;
+ structOffset = off;
+ }
+
+ /**
+ * (c)1998 Object Technology International.
+ * (c)1998 International Business Machines Corporation.
+ *
+ *
+ * @return double
+ * @param relativeOffset int
+ */
+ public double doubleAt(int relativeOffset) {
+ return (Double.longBitsToDouble(this.i8At(relativeOffset)));
+ }
+
+ /**
+ * (c)1998 Object Technology International.
+ * (c)1998 International Business Machines Corporation.
+ *
+ *
+ * @return float
+ * @param relativeOffset int
+ */
+ public float floatAt(int relativeOffset) {
+ return (Float.intBitsToFloat(this.i4At(relativeOffset)));
+ }
+
+ /**
+ * (c)1998 Object Technology International.
+ * (c)1998 International Business Machines Corporation.
+ *
+ *
+ * @return int
+ * @param relativeOffset int
+ */
+ public int i1At(int relativeOffset) {
+ return reference[relativeOffset + structOffset];
+ }
+
+ /**
+ * (c)1998 Object Technology International.
+ * (c)1998 International Business Machines Corporation.
+ *
+ *
+ * @return int
+ * @param relativeOffset int
+ */
+ public int i2At(int relativeOffset) {
+ int position = relativeOffset + structOffset;
+ return (reference[position++] << 8) + (reference[position] & 0xFF);
+ }
+
+ /**
+ * (c)1998 Object Technology International.
+ * (c)1998 International Business Machines Corporation.
+ *
+ *
+ * @return int
+ * @param relativeOffset int
+ */
+ public int i4At(int relativeOffset) {
+ int position = relativeOffset + structOffset;
+ return ((reference[position++] & 0xFF) << 24)
+ + ((reference[position++] & 0xFF) << 16)
+ + ((reference[position++] & 0xFF) << 8)
+ + (reference[position] & 0xFF);
+ }
+
+ /**
+ * (c)1998 Object Technology International.
+ * (c)1998 International Business Machines Corporation.
+ *
+ *
+ * @return int
+ * @param relativeOffset int
+ */
+ public long i8At(int relativeOffset) {
+ int position = relativeOffset + structOffset;
+ return (((long) (reference[position++] & 0xFF)) << 56)
+ + (((long) (reference[position++] & 0xFF)) << 48)
+ + (((long) (reference[position++] & 0xFF)) << 40)
+ + (((long) (reference[position++] & 0xFF)) << 32)
+ + (((long) (reference[position++] & 0xFF)) << 24)
+ + (((long) (reference[position++] & 0xFF)) << 16)
+ + (((long) (reference[position++] & 0xFF)) << 8)
+ + ((long) (reference[position++] & 0xFF));
+ }
+
+ /**
+ * (c)1998 Object Technology International.
+ * (c)1998 International Business Machines Corporation.
+ *
+ *
+ * @param modifiers int
+ */
+ public static String printTypeModifiers(int modifiers) {
+
+ java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream();
+ java.io.PrintWriter print = new java.io.PrintWriter(out);
+
+ if ((modifiers & AccPublic) != 0)
+ print.print("public ");
+ if ((modifiers & AccPrivate) != 0)
+ print.print("private ");
+ if ((modifiers & AccFinal) != 0)
+ print.print("final ");
+ if ((modifiers & AccSuper) != 0)
+ print.print("super ");
+ if ((modifiers & AccInterface) != 0)
+ print.print("interface ");
+ if ((modifiers & AccAbstract) != 0)
+ print.print("abstract ");
+ print.flush();
+ return out.toString();
+ }
+
+ /**
+ * (c)1998 Object Technology International.
+ * (c)1998 International Business Machines Corporation.
+ *
+ *
+ * @return int
+ * @param relativeOffset int
+ */
+ public int u1At(int relativeOffset) {
+ return (reference[relativeOffset + structOffset] & 0xFF);
+ }
+
+ /**
+ * (c)1998 Object Technology International.
+ * (c)1998 International Business Machines Corporation.
+ *
+ *
+ * @return int
+ * @param relativeOffset int
+ */
+ public int u2At(int relativeOffset) {
+ int position = relativeOffset + structOffset;
+ return ((reference[position++] & 0xFF) << 8) + (reference[position] & 0xFF);
+ }
+
+ /**
+ * (c)1998 Object Technology International.
+ * (c)1998 International Business Machines Corporation.
+ *
+ *
+ * @return int
+ * @param relativeOffset int
+ */
+ public long u4At(int relativeOffset) {
+ int position = relativeOffset + structOffset;
+ return (
+ ((reference[position++] & 0xFFL) << 24)
+ + ((reference[position++] & 0xFF) << 16)
+ + ((reference[position++] & 0xFF) << 8)
+ + (reference[position] & 0xFF));
+ }
+
+ /**
+ * (c)1998 Object Technology International.
+ * (c)1998 International Business Machines Corporation.
+ *
+ *
+ * @return String
+ * @param relativeOffset int
+ */
+ public char[] utf8At(int relativeOffset, int bytesAvailable) {
+ int x, y, z;
+ int length = bytesAvailable;
+ char outputBuf[] = new char[bytesAvailable];
+ int outputPos = 0;
+ int readOffset = structOffset + relativeOffset;
+
+ while (length != 0) {
+ x = reference[readOffset++] & 0xFF;
+ length--;
+ if ((0x80 & x) != 0) {
+ y = this.reference[readOffset++] & 0xFF;
+ length--;
+ if ((x & 0x20) != 0) {
+ z = this.reference[readOffset++] & 0xFF;
+ length--;
+ x = ((x & 0x1F) << 12) + ((y & 0x3F) << 6) + (z & 0x3F);
+ } else {
+ x = ((x & 0x1F) << 6) + (y & 0x3F);
+ }
+ }
+ outputBuf[outputPos++] = (char) x;
+ }
+
+ if (outputPos != bytesAvailable) {
+ System.arraycopy(outputBuf, 0, (outputBuf = new char[outputPos]), 0, outputPos);
+ }
+ return outputBuf;
+ }
+
+ /**
+ * (c)1998 Object Technology International.
+ * (c)1998 International Business Machines Corporation.
+ *
+ *
+ * @return String
+ * @param relativeOffset int
+ */
+ public char[] utf8At(
+ int relativeOffset,
+ int bytesAvailable,
+ boolean testValidity)
+ throws ClassFormatException {
+ int x, y, z;
+ int length = bytesAvailable;
+ char outputBuf[] = new char[bytesAvailable];
+ int outputPos = 0;
+ int readOffset = structOffset + relativeOffset;
+
+ while (length != 0) {
+ x = reference[readOffset++] & 0xFF;
+ length--;
+ if ((0x80 & x) != 0) {
+ if (testValidity) {
+ if ((0x40 & x) == 0) {
+ throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8);
+ }
+ if (length < 1) {
+ throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8);
+ }
+ }
+ y = this.reference[readOffset++] & 0xFF;
+ length--;
+ if (testValidity) {
+ if ((y & 0xC0) != 0x80) {
+ throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8);
+ }
+ }
+ if ((x & 0x20) != 0) {
+ if (testValidity && (length < 1)) {
+ throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8);
+ }
+ z = this.reference[readOffset++] & 0xFF;
+ length--;
+ if (testValidity && ((z & 0xC0) != 0x80)) {
+ throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8);
+ }
+ x = ((x & 0x1F) << 12) + ((y & 0x3F) << 6) + (z & 0x3F);
+ if (testValidity && (x < 0x0800)) {
+ throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8);
+ }
+ } else {
+ x = ((x & 0x1F) << 6) + (y & 0x3F);
+ if (testValidity && !((x == 0) || (x >= 0x80))) {
+ throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8);
+ }
+ }
+ } else {
+ if (testValidity && x == 0) {
+ throw new ClassFormatException(ClassFormatException.ErrMalformedUtf8);
+ }
+ }
+ outputBuf[outputPos++] = (char) x;
+ }
+
+ if (outputPos != bytesAvailable) {
+ System.arraycopy(outputBuf, 0, (outputBuf = new char[outputPos]), 0, outputPos);
+ }
+ return outputBuf;
+ }
+
+ public static void verifyMethodNameAndSignature(char[] name, char[] signature)
+ throws ClassFormatException {
+
+ // ensure name is not empty
+ if (name.length == 0) {
+ throw new ClassFormatException(ClassFormatException.ErrInvalidMethodName);
+ }
+
+ // if name begins with the < character it must be clinit or init
+ if (name[0] == '<') {
+ if (new String(name).equals("<clinit>") || new String(name).equals("<init>")) {
+ int signatureLength = signature.length;
+ if (!((signatureLength > 2)
+ && (signature[0] == '(')
+ && (signature[signatureLength - 2] == ')')
+ && (signature[signatureLength - 1] == 'V'))) {
+ throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
+ }
+ } else {
+ throw new ClassFormatException(ClassFormatException.ErrInvalidMethodName);
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFormatException.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFormatException.java
new file mode 100644
index 0000000000..0a94e8a36b
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFormatException.java
@@ -0,0 +1,67 @@
+package org.eclipse.jdt.internal.compiler.classfmt;
+
+public class ClassFormatException extends Exception {
+ private int errorCode;
+ private int bufferPosition;
+
+ public static final int ErrBadMagic = 1;
+ public static final int ErrBadMinorVersion = 2;
+ public static final int ErrBadMajorVersion = 3;
+
+ public static final int ErrBadConstantClass = 4;
+ public static final int ErrBadConstantString = 5;
+ public static final int ErrBadConstantNameAndType = 6;
+ public static final int ErrBadConstantFieldRef = 7;
+ public static final int ErrBadConstantMethodRef = 8;
+ public static final int ErrBadConstantInterfaceMethodRef = 9;
+ public static final int ErrBadConstantPoolIndex = 10;
+ public static final int ErrBadSuperclassName = 11;
+ public static final int ErrInterfaceCannotBeFinal = 12;
+ public static final int ErrInterfaceMustBeAbstract = 13;
+ public static final int ErrBadModifiers = 14;
+ public static final int ErrClassCannotBeAbstractFinal = 15;
+ public static final int ErrBadClassname = 16;
+ public static final int ErrBadFieldInfo = 17;
+ public static final int ErrBadMethodInfo = 17;
+
+ public static final int ErrEmptyConstantPool = 18;
+ public static final int ErrMalformedUtf8 = 19;
+ public static final int ErrUnknownConstantTag = 20;
+ public static final int ErrTruncatedInput = 21;
+ public static final int ErrMethodMustBeAbstract = 22;
+ public static final int ErrMalformedAttribute = 23;
+ public static final int ErrBadInterface = 24;
+ public static final int ErrInterfaceMustSubclassObject = 25;
+ public static final int ErrIncorrectInterfaceMethods = 26;
+ public static final int ErrInvalidMethodName = 27;
+ public static final int ErrInvalidMethodSignature = 28;
+
+ /**
+ * (c)1998 Object Technology International.
+ * (c)1998 International Business Machines Corporation.
+ *
+ *
+ */
+ public ClassFormatException(int code) {
+ errorCode = code;
+ }
+
+ /**
+ * (c)1998 Object Technology International.
+ * (c)1998 International Business Machines Corporation.
+ *
+ *
+ */
+ public ClassFormatException(int code, int bufPos) {
+ errorCode = code;
+ bufferPosition = bufPos;
+ }
+
+ /**
+ * @return int
+ */
+ public int getErrorCode() {
+ return errorCode;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/FieldInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/FieldInfo.java
new file mode 100644
index 0000000000..1f39e2870e
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/FieldInfo.java
@@ -0,0 +1,296 @@
+package org.eclipse.jdt.internal.compiler.classfmt;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.*;
+
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class FieldInfo
+ extends ClassFileStruct
+ implements AttributeNamesConstants, IBinaryField {
+ private Constant constant;
+ private boolean isDeprecated;
+ private int[] constantPoolOffsets;
+ private int accessFlags;
+ private char[] name;
+ private char[] signature;
+ private int attributesCount;
+ private int attributeBytes;
+ /**
+ * @param classFileBytes byte[]
+ * @param offsets int[]
+ * @param offset int
+ */
+ public FieldInfo(byte classFileBytes[], int offsets[], int offset)
+ throws ClassFormatException {
+ super(classFileBytes, offset);
+ constantPoolOffsets = offsets;
+ accessFlags = -1;
+ int attributesCount = u2At(6);
+ int readOffset = 8;
+ for (int i = 0; i < attributesCount; i++) {
+ readOffset += (6 + u4At(readOffset + 2));
+ }
+ attributeBytes = readOffset;
+ }
+
+ /**
+ * Return the constant of the field.
+ * Return org.eclipse.jdt.internal.compiler.Constant.NotAConstant if there is none.
+ * @return org.eclipse.jdt.internal.compiler.Constant
+ */
+ public Constant getConstant() {
+ if (constant == null) {
+ // read constant
+ readConstantAttribute();
+ }
+ return constant;
+ }
+
+ /**
+ * Answer an int whose bits are set according the access constants
+ * defined by the VM spec.
+ * Set the AccDeprecated and AccSynthetic bits if necessary
+ * @return int
+ */
+ public int getModifiers() {
+ if (accessFlags == -1) {
+ // compute the accessflag. Don't forget the deprecated attribute
+ accessFlags = u2At(0);
+ readDeprecatedAttributes();
+ if (isDeprecated) {
+ accessFlags |= AccDeprecated;
+ }
+ if (isSynthetic()) {
+ accessFlags |= AccSynthetic;
+ }
+ }
+ return accessFlags;
+ }
+
+ /**
+ * Answer the name of the field.
+ * @return char[]
+ */
+ public char[] getName() {
+ if (name == null) {
+ // read the name
+ int utf8Offset = constantPoolOffsets[u2At(2)] - structOffset;
+ name = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+ }
+ return name;
+ }
+
+ /**
+ * Answer the resolved name of the receiver's type in the
+ * class file format as specified in section 4.3.2 of the Java 2 VM spec.
+ *
+ * For example:
+ * - java.lang.String is Ljava/lang/String;
+ * - an int is I
+ * - a 2 dimensional array of strings is [[Ljava/lang/String;
+ * - an array of floats is [F
+ * @return char[]
+ */
+ public char[] getTypeName() {
+ if (signature == null) {
+ // read the signature
+ int utf8Offset = constantPoolOffsets[u2At(4)] - structOffset;
+ signature = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+ }
+ return signature;
+ }
+
+ /**
+ * Return a wrapper that contains the constant of the field.
+ * Throws a java.ibm.compiler.java.classfmt.ClassFormatException in case the signature is
+ * incompatible with the constant tag.
+ *
+ * @exception java.ibm.compiler.java.classfmt.ClassFormatException
+ * @return java.lang.Object
+ */
+ public Object getWrappedConstantValue() throws ClassFormatException {
+
+ int attributesCount = u2At(6);
+ int readOffset = 8;
+ for (int i = 0; i < attributesCount; i++) {
+ int utf8Offset = constantPoolOffsets[u2At(8)] - structOffset;
+ char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+ if (CharOperation.equals(attributeName, ConstantValueName)) {
+ // read the right constant
+ int relativeOffset = constantPoolOffsets[u2At(14)] - structOffset;
+ switch (u1At(relativeOffset)) {
+ case IntegerTag :
+ return new Integer(i4At(relativeOffset + 1));
+ case FloatTag :
+ return new Float(floatAt(relativeOffset + 1));
+ case DoubleTag :
+ return new Double(doubleAt(relativeOffset + 1));
+ case LongTag :
+ return new Long(i8At(relativeOffset + 1));
+ case StringTag :
+ utf8Offset = constantPoolOffsets[u2At(relativeOffset + 1)] - structOffset;
+ return String.valueOf(utf8At(utf8Offset + 3, u2At(utf8Offset + 1)));
+ }
+ }
+ readOffset += (6 + u4At(readOffset + 2));
+ }
+ return null;
+ }
+
+ /**
+ * Return true if the field has a constant value attribute, false otherwise.
+ * @return boolean
+ */
+ public boolean hasConstant() {
+ int attributesCount = u2At(6);
+ int readOffset = 8;
+ boolean isConstant = false;
+ for (int i = 0; i < attributesCount; i++) {
+ int utf8Offset = constantPoolOffsets[u2At(8)] - structOffset;
+ char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+ if (CharOperation.equals(attributeName, ConstantValueName)) {
+ isConstant = true;
+ }
+ readOffset += (6 + u4At(readOffset + 2));
+ }
+ return isConstant;
+ }
+
+ /**
+ * Return true if the field is a synthetic field, false otherwise.
+ * @return boolean
+ */
+ private boolean isSynthetic() {
+ int attributesCount = u2At(6);
+ int readOffset = 8;
+ boolean isSynthetic = false;
+ for (int i = 0; i < attributesCount; i++) {
+ int utf8Offset = constantPoolOffsets[u2At(8)] - structOffset;
+ char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+ if (CharOperation.equals(attributeName, SyntheticName)) {
+ isSynthetic = true;
+ }
+ readOffset += (6 + u4At(readOffset + 2));
+ }
+ return isSynthetic;
+ }
+
+ private void readConstantAttribute() {
+ int attributesCount = u2At(6);
+ int readOffset = 8;
+ boolean isConstant = false;
+ for (int i = 0; i < attributesCount; i++) {
+ int utf8Offset = constantPoolOffsets[u2At(8)] - structOffset;
+ char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+ if (CharOperation.equals(attributeName, ConstantValueName)) {
+ isConstant = true;
+ // read the right constant
+ int relativeOffset = constantPoolOffsets[u2At(14)] - structOffset;
+ switch (u1At(relativeOffset)) {
+ case IntegerTag :
+ char[] sign = getTypeName();
+ if (sign.length == 1) {
+ switch (sign[0]) {
+ case 'Z' : // boolean constant
+ constant = new BooleanConstant(i4At(relativeOffset + 1) == 1);
+ break;
+ case 'I' : // integer constant
+ constant = new IntConstant(i4At(relativeOffset + 1));
+ break;
+ case 'C' : // char constant
+ constant = new CharConstant((char) i4At(relativeOffset + 1));
+ break;
+ case 'B' : // byte constant
+ constant = new ByteConstant((byte) i4At(relativeOffset + 1));
+ break;
+ case 'S' : // short constant
+ constant = new ShortConstant((short) i4At(relativeOffset + 1));
+ break;
+ default :
+ constant = Constant.NotAConstant;
+ }
+ } else {
+ constant = Constant.NotAConstant;
+ }
+ break;
+ case FloatTag :
+ constant = new FloatConstant(floatAt(relativeOffset + 1));
+ break;
+ case DoubleTag :
+ constant = new DoubleConstant(doubleAt(relativeOffset + 1));
+ break;
+ case LongTag :
+ constant = new LongConstant(i8At(relativeOffset + 1));
+ break;
+ case StringTag :
+ utf8Offset = constantPoolOffsets[u2At(relativeOffset + 1)] - structOffset;
+ constant =
+ new StringConstant(
+ String.valueOf(utf8At(utf8Offset + 3, u2At(utf8Offset + 1))));
+ break;
+ }
+ }
+ readOffset += (6 + u4At(readOffset + 2));
+ }
+ if (!isConstant) {
+ constant = Constant.NotAConstant;
+ }
+ }
+
+ private void readDeprecatedAttributes() {
+ int attributesCount = u2At(6);
+ int readOffset = 8;
+ for (int i = 0; i < attributesCount; i++) {
+ int utf8Offset = constantPoolOffsets[u2At(readOffset)] - structOffset;
+ char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+ if (CharOperation.equals(attributeName, DeprecatedName)) {
+ isDeprecated = true;
+ }
+ readOffset += (6 + u4At(readOffset + 2));
+ }
+ }
+
+ /**
+ * Answer the size of the receiver in bytes.
+ *
+ * @return int
+ */
+ public int sizeInBytes() {
+ return attributeBytes;
+ }
+
+ public void throwFormatException() throws ClassFormatException {
+ throw new ClassFormatException(ClassFormatException.ErrBadFieldInfo);
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer(this.getClass().getName());
+ int modifiers = getModifiers();
+ return buffer
+ .append("{")
+ .append(
+ ((modifiers & AccDeprecated) != 0 ? "deprecated " : "")
+ + ((modifiers & 0x0001) == 1 ? "public " : "")
+ + ((modifiers & 0x0002) == 0x0002 ? "private " : "")
+ + ((modifiers & 0x0004) == 0x0004 ? "protected " : "")
+ + ((modifiers & 0x0008) == 0x000008 ? "static " : "")
+ + ((modifiers & 0x0010) == 0x0010 ? "final " : "")
+ + ((modifiers & 0x0040) == 0x0040 ? "volatile " : "")
+ + ((modifiers & 0x0080) == 0x0080 ? "transient " : ""))
+ .append(getTypeName())
+ .append(" ")
+ .append(getName())
+ .append(" ")
+ .append(getConstant())
+ .append("}")
+ .toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/InnerClassInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/InnerClassInfo.java
new file mode 100644
index 0000000000..8ed522ad70
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/InnerClassInfo.java
@@ -0,0 +1,130 @@
+package org.eclipse.jdt.internal.compiler.classfmt;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/**
+ * Describes one entry in the classes table of the InnerClasses attribute.
+ * See the inner class specification (The class file attribute "InnerClasses").
+ */
+
+import org.eclipse.jdt.internal.compiler.env.*;
+
+public class InnerClassInfo
+ extends ClassFileStruct
+ implements IBinaryNestedType {
+ int innerClassNameIndex = -1;
+ int outerClassNameIndex = -1;
+ private int innerNameIndex = -1;
+ private char[] innerClassName;
+ private char[] outerClassName;
+ private char[] innerName;
+ private int accessFlags = -1;
+ private int[] constantPoolOffsets;
+ private boolean readInnerClassName = false;
+ private boolean readOuterClassName = false;
+ public InnerClassInfo(byte classFileBytes[], int offsets[], int offset)
+ throws ClassFormatException {
+ super(classFileBytes, offset);
+ constantPoolOffsets = offsets;
+ innerClassNameIndex = u2At(0);
+ outerClassNameIndex = u2At(2);
+ }
+
+ /**
+ * Answer the resolved name of the enclosing type in the
+ * class file format as specified in section 4.2 of the Java 2 VM spec.
+ *
+ * For example, java.lang.String is java/lang/String.
+ * @return char[]
+ */
+ public char[] getEnclosingTypeName() {
+ if (!readOuterClassName) {
+ // read outer class name
+ readOuterClassName = true;
+ if (outerClassNameIndex != 0) {
+ int utf8Offset =
+ constantPoolOffsets[u2At(
+ constantPoolOffsets[outerClassNameIndex] - structOffset + 1)]
+ - structOffset;
+ outerClassName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+ }
+
+ }
+ return outerClassName;
+ }
+
+ /**
+ * Answer an int whose bits are set according the access constants
+ * defined by the VM spec.
+ * @return int
+ */
+ public int getModifiers() {
+ if (accessFlags == -1) {
+ // read access flag
+ accessFlags = u2At(6);
+ }
+ return accessFlags;
+ }
+
+ /**
+ * Answer the resolved name of the member type in the
+ * class file format as specified in section 4.2 of the Java 2 VM spec.
+ *
+ * For example, p1.p2.A.M is p1/p2/A$M.
+ * @return char[]
+ */
+ public char[] getName() {
+ if (!readInnerClassName) {
+ // read the inner class name
+ readInnerClassName = true;
+ if (innerClassNameIndex != 0) {
+ int classOffset = constantPoolOffsets[innerClassNameIndex] - structOffset;
+ int utf8Offset = constantPoolOffsets[u2At(classOffset + 1)] - structOffset;
+ innerClassName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+ }
+ }
+ return innerClassName;
+ }
+
+ /**
+ * Answer the source name of the member type.
+ *
+ * For example, p1.p2.A.M is M.
+ * @return char[]
+ */
+ public char[] getSourceName() {
+ if (innerNameIndex == -1) {
+ // read inner name
+ innerNameIndex = u2At(4);
+ if (innerNameIndex != 0) {
+ int utf8Offset = constantPoolOffsets[innerNameIndex] - structOffset;
+ innerName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+ }
+
+ }
+ return innerName;
+ }
+
+ /**
+ * Answer the string representation of the receiver
+ * @return java.lang.String
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ if (getName() != null) {
+ buffer.append(getName());
+ }
+ buffer.append("\n");
+ if (getEnclosingTypeName() != null) {
+ buffer.append(getEnclosingTypeName());
+ }
+ buffer.append("\n");
+ if (getSourceName() != null) {
+ buffer.append(getSourceName());
+ }
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/MethodInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/MethodInfo.java
new file mode 100644
index 0000000000..def8737d11
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/MethodInfo.java
@@ -0,0 +1,225 @@
+package org.eclipse.jdt.internal.compiler.classfmt;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.*;
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class MethodInfo
+ extends ClassFileStruct
+ implements IBinaryMethod, AttributeNamesConstants {
+ private char[][] exceptionNames;
+ private int[] constantPoolOffsets;
+ private boolean isDeprecated;
+ private int accessFlags;
+ private char[] name;
+ private char[] signature;
+ private int attributesCount;
+ private int attributeBytes;
+ static private final char[][] noException = new char[0][0];
+ private int decodeIndex;
+ /**
+ * @param classFileBytes byte[]
+ * @param offsets int[]
+ * @param offset int
+ */
+ public MethodInfo(byte classFileBytes[], int offsets[], int offset)
+ throws ClassFormatException {
+ super(classFileBytes, offset);
+ constantPoolOffsets = offsets;
+ accessFlags = -1;
+ int attributesCount = u2At(6);
+ int readOffset = 8;
+ for (int i = 0; i < attributesCount; i++) {
+ readOffset += (6 + u4At(readOffset + 2));
+ }
+ attributeBytes = readOffset;
+ }
+
+ /**
+ * Answer the resolved names of the exception types in the
+ * class file format as specified in section 4.2 of the Java 2 VM spec
+ * or null if the array is empty.
+ *
+ * For example, java.lang.String is java/lang/String.
+ * @return char[][]
+ */
+ public char[][] getExceptionTypeNames() {
+ if (exceptionNames == null) {
+ readExceptionAttributes();
+ }
+ return exceptionNames;
+ }
+
+ /**
+ * Answer the receiver's method descriptor which describes the parameter &
+ * return types as specified in section 4.3.3 of the Java 2 VM spec.
+ *
+ * For example:
+ * - int foo(String) is (Ljava/lang/String;)I
+ * - void foo(Object[]) is (I)[Ljava/lang/Object;
+ * @return char[]
+ */
+ public char[] getMethodDescriptor() {
+ if (signature == null) {
+ // read the name
+ int utf8Offset = constantPoolOffsets[u2At(4)] - structOffset;
+ signature = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+ }
+ return signature;
+ }
+
+ /**
+ * Answer an int whose bits are set according the access constants
+ * defined by the VM spec.
+ * Set the AccDeprecated and AccSynthetic bits if necessary
+ * @return int
+ */
+ public int getModifiers() {
+ if (accessFlags == -1) {
+ // compute the accessflag. Don't forget the deprecated attribute
+ accessFlags = u2At(0);
+ readDeprecatedAttributes();
+ if (isDeprecated) {
+ accessFlags |= AccDeprecated;
+ }
+ if (isSynthetic()) {
+ accessFlags |= AccSynthetic;
+ }
+ }
+ return accessFlags;
+ }
+
+ /**
+ * Answer the name of the method.
+ *
+ * For a constructor, answer <init> & <clinit> for a clinit method.
+ * @return char[]
+ */
+ public char[] getSelector() {
+ if (name == null) {
+ // read the name
+ int utf8Offset = constantPoolOffsets[u2At(2)] - structOffset;
+ name = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+ }
+ return name;
+ }
+
+ /**
+ * Answer true if the method is a class initializer, false otherwise.
+ * @return boolean
+ */
+ public boolean isClinit() {
+ char[] selector = getSelector();
+ return selector[0] == '<' && selector.length == 8; // Can only match <clinit>
+ }
+
+ /**
+ * Answer true if the method is a constructor, false otherwise.
+ * @return boolean
+ */
+ public boolean isConstructor() {
+ char[] selector = getSelector();
+ return selector[0] == '<' && selector.length == 6; // Can only match <init>
+ }
+
+ /**
+ * Return true if the field is a synthetic method, false otherwise.
+ * @return boolean
+ */
+ private boolean isSynthetic() {
+ int attributesCount = u2At(6);
+ int readOffset = 8;
+ boolean isSynthetic = false;
+ for (int i = 0; i < attributesCount; i++) {
+ int utf8Offset = constantPoolOffsets[u2At(8)] - structOffset;
+ char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+ if (CharOperation.equals(attributeName, SyntheticName)) {
+ isSynthetic = true;
+ }
+ readOffset += (6 + u4At(readOffset + 2));
+ }
+ return isSynthetic;
+ }
+
+ private void readDeprecatedAttributes() {
+ int attributesCount = u2At(6);
+ int readOffset = 8;
+ for (int i = 0; i < attributesCount; i++) {
+ int utf8Offset = constantPoolOffsets[u2At(readOffset)] - structOffset;
+ char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+ if (CharOperation.equals(attributeName, DeprecatedName)) {
+ isDeprecated = true;
+ }
+ readOffset += (6 + u4At(readOffset + 2));
+ }
+ }
+
+ private void readExceptionAttributes() {
+ int attributesCount = u2At(6);
+ int readOffset = 8;
+ for (int i = 0; i < attributesCount; i++) {
+ int utf8Offset = constantPoolOffsets[u2At(readOffset)] - structOffset;
+ char[] attributeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+ if (CharOperation.equals(attributeName, ExceptionsName)) {
+ // read the number of exception entries
+ int entriesNumber = u2At(readOffset + 6);
+ // place the readOffset at the beginning of the exceptions table
+ readOffset += 8;
+ if (entriesNumber == 0) {
+ exceptionNames = noException;
+ } else {
+ exceptionNames = new char[entriesNumber][];
+ for (int j = 0; j < entriesNumber; j++) {
+ utf8Offset =
+ constantPoolOffsets[u2At(
+ constantPoolOffsets[u2At(readOffset)] - structOffset + 1)]
+ - structOffset;
+ exceptionNames[j] = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+ readOffset += 2;
+ }
+ }
+ } else {
+ readOffset += (6 + u4At(readOffset + 2));
+ }
+ }
+ if (exceptionNames == null) {
+ exceptionNames = noException;
+ }
+ }
+
+ /**
+ * Answer the size of the receiver in bytes.
+ *
+ * @return int
+ */
+ public int sizeInBytes() {
+ return attributeBytes;
+ }
+
+ public String toString() {
+ int modifiers = getModifiers();
+ StringBuffer buffer = new StringBuffer(this.getClass().getName());
+ return buffer
+ .append("{")
+ .append(
+ ((modifiers & AccDeprecated) != 0 ? "deprecated " : "")
+ + ((modifiers & 0x0001) == 1 ? "public " : "")
+ + ((modifiers & 0x0002) == 0x0002 ? "private " : "")
+ + ((modifiers & 0x0004) == 0x0004 ? "protected " : "")
+ + ((modifiers & 0x0008) == 0x000008 ? "static " : "")
+ + ((modifiers & 0x0010) == 0x0010 ? "final " : "")
+ + ((modifiers & 0x0040) == 0x0040 ? "volatile " : "")
+ + ((modifiers & 0x0080) == 0x0080 ? "transient " : ""))
+ .append(getSelector())
+ .append(getMethodDescriptor())
+ .append("}")
+ .toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/AttributeNamesConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/AttributeNamesConstants.java
new file mode 100644
index 0000000000..04970db5aa
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/AttributeNamesConstants.java
@@ -0,0 +1,54 @@
+package org.eclipse.jdt.internal.compiler.codegen;
+
+public interface AttributeNamesConstants {
+ final char[] SyntheticName =
+ new char[] { 'S', 'y', 'n', 't', 'h', 'e', 't', 'i', 'c' };
+ final char[] ConstantValueName =
+ new char[] { 'C', 'o', 'n', 's', 't', 'a', 'n', 't', 'V', 'a', 'l', 'u', 'e' };
+ final char[] LineNumberTableName =
+ new char[] {
+ 'L',
+ 'i',
+ 'n',
+ 'e',
+ 'N',
+ 'u',
+ 'm',
+ 'b',
+ 'e',
+ 'r',
+ 'T',
+ 'a',
+ 'b',
+ 'l',
+ 'e' };
+ final char[] LocalVariableTableName =
+ new char[] {
+ 'L',
+ 'o',
+ 'c',
+ 'a',
+ 'l',
+ 'V',
+ 'a',
+ 'r',
+ 'i',
+ 'a',
+ 'b',
+ 'l',
+ 'e',
+ 'T',
+ 'a',
+ 'b',
+ 'l',
+ 'e' };
+ final char[] InnerClassName =
+ new char[] { 'I', 'n', 'n', 'e', 'r', 'C', 'l', 'a', 's', 's', 'e', 's' };
+ final char[] CodeName = new char[] { 'C', 'o', 'd', 'e' };
+ final char[] ExceptionsName =
+ new char[] { 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n', 's' };
+ final char[] SourceName =
+ new char[] { 'S', 'o', 'u', 'r', 'c', 'e', 'F', 'i', 'l', 'e' };
+ final char[] DeprecatedName =
+ new char[] { 'D', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd' };
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CaseLabel.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CaseLabel.java
new file mode 100644
index 0000000000..565565ec2b
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CaseLabel.java
@@ -0,0 +1,82 @@
+package org.eclipse.jdt.internal.compiler.codegen;
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+public class CaseLabel extends Label {
+ public int instructionPosition = POS_NOT_SET;
+ public int backwardsBranch = POS_NOT_SET;
+ /**
+ * CaseLabel constructor comment.
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ */
+ public CaseLabel(CodeStream codeStream) {
+ super(codeStream);
+ }
+
+ /*
+ * Put down a refernece to the array at the location in the codestream.
+ */
+ void branch() {
+ if (position == POS_NOT_SET) {
+ addForwardReference(codeStream.position);
+ // Leave 4 bytes free to generate the jump offset afterwards
+ codeStream.position += 4;
+ codeStream.classFileOffset += 4;
+ } else { //Position is set. Write it!
+ codeStream.writeSignedWord(position - codeStream.position + 1);
+ }
+ }
+
+ /*
+ * Put down a refernece to the array at the location in the codestream.
+ */
+ void branchWide() {
+ if (position == POS_NOT_SET) {
+ addForwardReference(codeStream.position);
+ // Leave 4 bytes free to generate the jump offset afterwards
+ codeStream.position += 4;
+ } else { //Position is set. Write it!
+ codeStream.writeSignedWord(position - codeStream.position + 1);
+ }
+ }
+
+ public boolean isStandardLabel() {
+ return false;
+ }
+
+ /*
+ * Put down a refernece to the array at the location in the codestream.
+ */
+ public void place() {
+ position = codeStream.position;
+ if (instructionPosition == POS_NOT_SET)
+ backwardsBranch = position;
+ else {
+ int offset = position - instructionPosition;
+ for (int i = 0; i < forwardReferenceCount; i++) {
+ codeStream.writeSignedWord(forwardReferences[i], offset);
+ }
+ // add the label int the codeStream labels collection
+ codeStream.addLabel(this);
+ }
+ }
+
+ /*
+ * Put down a refernece to the array at the location in the codestream.
+ */
+ void placeInstruction() {
+ if (instructionPosition == POS_NOT_SET) {
+ instructionPosition = codeStream.position;
+ if (backwardsBranch != POS_NOT_SET) {
+ int offset = backwardsBranch - instructionPosition;
+ for (int i = 0; i < forwardReferenceCount; i++)
+ codeStream.writeSignedWord(forwardReferences[i], offset);
+ backwardsBranch = POS_NOT_SET;
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CharArrayCache.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CharArrayCache.java
new file mode 100644
index 0000000000..a2072cab75
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CharArrayCache.java
@@ -0,0 +1,193 @@
+package org.eclipse.jdt.internal.compiler.codegen;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class CharArrayCache {
+ // to avoid using Enumerations, walk the individual tables skipping nulls
+ public char[] keyTable[];
+ public int valueTable[];
+ int elementSize; // number of elements in the table
+ int threshold;
+ /**
+ * Constructs a new, empty hashtable. A default capacity is used.
+ * Note that the hashtable will automatically grow when it gets full.
+ */
+ public CharArrayCache() {
+ this(13);
+ }
+
+ /**
+ * Constructs a new, empty hashtable with the specified initial
+ * capacity.
+ * @param initialCapacity int
+ * the initial number of buckets
+ */
+ public CharArrayCache(int initialCapacity) {
+ this.elementSize = 0;
+ this.threshold = (int) (initialCapacity * 0.66f);
+ this.keyTable = new char[initialCapacity][];
+ this.valueTable = new int[initialCapacity];
+ }
+
+ /**
+ * Clears the hash table so that it has no more elements in it.
+ */
+ public void clear() {
+ for (int i = keyTable.length; --i >= 0;) {
+ keyTable[i] = null;
+ valueTable[i] = 0;
+ }
+ elementSize = 0;
+ }
+
+ /** Returns true if the collection contains an element for the key.
+ *
+ * @param char[] key the key that we are looking for
+ * @return boolean
+ * @see ConstantPoolCache#contains
+ */
+ public boolean containsKey(char[] key) {
+ int index = hashCodeChar(key);
+ while (keyTable[index] != null) {
+ if (CharOperation.equals(keyTable[index], key))
+ return true;
+ index = (index + 1) % keyTable.length;
+ }
+ return false;
+ }
+
+ /** Gets the object associated with the specified key in the
+ * hashtable.
+ * @param key <CODE>char[]</CODE> the specified key
+ * @return int the element for the key or -1 if the key is not
+ * defined in the hash table.
+ * @see ConstantPoolCache#put
+ */
+ public int get(char[] key) {
+ int index = hashCodeChar(key);
+ while (keyTable[index] != null) {
+ if (CharOperation.equals(keyTable[index], key))
+ return valueTable[index];
+ index = (index + 1) % keyTable.length;
+ }
+ return -1;
+ }
+
+ private int hashCodeChar(char[] val) {
+ int length = val.length;
+ int hash = 0;
+ int n = 2; // number of characters skipped
+ for (int i = 0; i < length; i += n) {
+ hash += val[i];
+ }
+ return (hash & 0x7FFFFFFF) % keyTable.length;
+ }
+
+ /**
+ * Puts the specified element into the hashtable, using the specified
+ * key. The element may be retrieved by doing a get() with the same key.
+ * The key and the element cannot be null.
+ *
+ * @param key <CODE>Object</CODE> the specified key in the hashtable
+ * @param value <CODE>int</CODE> the specified element
+ * @see ConstantPoolCache#get
+ * @return int the old value of the key, or -1 if it did not have one.
+ */
+ public int put(char[] key, int value) {
+ int index = hashCodeChar(key);
+ while (keyTable[index] != null) {
+ if (CharOperation.equals(keyTable[index], key))
+ return valueTable[index] = value;
+ index = (index + 1) % keyTable.length;
+ }
+ keyTable[index] = key;
+ valueTable[index] = value;
+
+ // assumes the threshold is never equal to the size of the table
+ if (++elementSize > threshold)
+ rehash();
+ return value;
+ }
+
+ /**
+ * Rehashes the content of the table into a bigger table.
+ * This method is called automatically when the hashtable's
+ * size exceeds the threshold.
+ */
+ private void rehash() {
+ CharArrayCache newHashtable = new CharArrayCache(keyTable.length * 2);
+ for (int i = keyTable.length; --i >= 0;)
+ if (keyTable[i] != null)
+ newHashtable.put(keyTable[i], valueTable[i]);
+
+ this.keyTable = newHashtable.keyTable;
+ this.valueTable = newHashtable.valueTable;
+ this.threshold = newHashtable.threshold;
+ }
+
+ /** Remove the object associated with the specified key in the
+ * hashtable.
+ * @param key <CODE>char[]</CODE> the specified key
+ */
+ public void remove(char[] key) {
+ int index = hashCodeChar(key);
+ while (keyTable[index] != null) {
+ if (CharOperation.equals(keyTable[index], key)) {
+ valueTable[index] = 0;
+ keyTable[index] = null;
+ return;
+ }
+ index = (index + 1) % keyTable.length;
+ }
+ }
+
+ /**
+ * Returns the key corresponding to the value. Returns null if the
+ * receiver doesn't contain the value.
+ * @param value int the value that we are looking for
+ * @return Object
+ */
+ public char[] returnKeyFor(int value) {
+ for (int i = keyTable.length; i-- > 0;) {
+ if (valueTable[i] == value) {
+ return keyTable[i];
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the number of elements contained in the hashtable.
+ *
+ * @return <CODE>int</CODE> The size of the table
+ */
+ public int size() {
+ return elementSize;
+ }
+
+ /**
+ * Converts to a rather lengthy String.
+ *
+ * return String the ascii representation of the receiver
+ */
+ public String toString() {
+ int max = size();
+ StringBuffer buf = new StringBuffer();
+ buf.append("{");
+ for (int i = 0; i < max; ++i) {
+ if (keyTable[i] != null) {
+ buf.append(keyTable[i]).append("->").append(valueTable[i]);
+ }
+ if (i < max) {
+ buf.append(", ");
+ }
+ }
+ buf.append("}");
+ return buf.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
new file mode 100644
index 0000000000..366b810aa7
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
@@ -0,0 +1,6052 @@
+package org.eclipse.jdt.internal.compiler.codegen;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+import java.util.*;
+
+import org.eclipse.jdt.internal.compiler.*;
+
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.classfmt.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class CodeStream
+ implements OperatorIds, ClassFileConstants, Opcodes, BaseTypes, TypeConstants, TypeIds {
+ // It will be responsible for the following items.
+
+ // -> Tracking Max Stack.
+
+ public int stackMax; // Use Ints to keep from using extra bc when adding
+ public int stackDepth; // Use Ints to keep from using extra bc when adding
+ public int maxLocals;
+ public static final int max = 100; // Maximum size of the code array
+ public static final int growFactor = 400;
+ public static final int LABELS_INCREMENT = 5;
+ public byte[] bCodeStream;
+ public int pcToSourceMapSize;
+ public int[] pcToSourceMap = new int[24];
+ public int lastEntryPC; // last entry recorded
+ public int[] lineSeparatorPositions;
+ public int position; // So when first set can be incremented
+ public int classFileOffset;
+ public int startingClassFileOffset;
+ // I need to keep the starting point inside the byte array
+ public ConstantPool constantPool;
+ // The constant pool used to generate bytecodes that need to store information into the constant pool
+ public ClassFile classFile; // The current classfile it is associated to.
+ // local variable attributes output
+ public static final int LOCALS_INCREMENT = 10;
+ public LocalVariableBinding[] locals =
+ new LocalVariableBinding[LOCALS_INCREMENT];
+ static LocalVariableBinding[] noLocals =
+ new LocalVariableBinding[LOCALS_INCREMENT];
+ public LocalVariableBinding[] visibleLocals =
+ new LocalVariableBinding[LOCALS_INCREMENT];
+ static LocalVariableBinding[] noVisibleLocals =
+ new LocalVariableBinding[LOCALS_INCREMENT];
+ int visibleLocalsCount;
+ public AbstractMethodDeclaration methodDeclaration;
+ public ExceptionLabel[] exceptionHandlers =
+ new ExceptionLabel[LABELS_INCREMENT];
+ static ExceptionLabel[] noExceptionHandlers =
+ new ExceptionLabel[LABELS_INCREMENT];
+ public int exceptionHandlersNumber;
+ public static FieldBinding[] ImplicitThis = new FieldBinding[] {
+ };
+
+ public boolean generateLineNumberAttributes;
+ public boolean generateLocalVariableTableAttributes;
+ public boolean preserveUnusedLocals;
+ // store all the labels placed at the current position to be able to optimize
+ // a jump to the next bytecode.
+ public Label[] labels = new Label[LABELS_INCREMENT];
+ static Label[] noLabels = new Label[LABELS_INCREMENT];
+ public int countLabels;
+ public int allLocalsCounter;
+ public int maxFieldCount;
+ public CodeStream(ClassFile classFile) {
+ generateLineNumberAttributes =
+ (classFile.produceDebugAttributes & CompilerOptions.Lines) != 0;
+ generateLocalVariableTableAttributes =
+ (classFile.produceDebugAttributes & CompilerOptions.Vars) != 0;
+ if (generateLineNumberAttributes) {
+ lineSeparatorPositions =
+ classFile
+ .referenceBinding
+ .scope
+ .referenceCompilationUnit()
+ .compilationResult
+ .lineSeparatorPositions;
+ }
+ }
+
+ final public void aaload() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_aaload;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_aaload);
+ }
+ }
+
+ final public void aastore() {
+ countLabels = 0;
+ stackDepth -= 3;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_aastore;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_aastore);
+ }
+ }
+
+ final public void aconst_null() {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_aconst_null;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_aconst_null);
+ }
+ }
+
+ public final void addDefinitelyAssignedVariables(
+ Scope scope,
+ int initStateIndex) {
+ // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect
+ if (!generateLocalVariableTableAttributes)
+ return;
+ /* if (initStateIndex == lastInitStateIndexWhenAddingInits)
+ return;
+ lastInitStateIndexWhenAddingInits = initStateIndex;
+ if (lastInitStateIndexWhenRemovingInits != initStateIndex){
+ lastInitStateIndexWhenRemovingInits = -2; // reinitialize remove index
+ // remove(1)-add(1)-remove(1) -> ignore second remove
+ // remove(1)-add(2)-remove(1) -> perform second remove
+ }
+
+ */
+ for (int i = 0; i < visibleLocalsCount; i++) {
+ LocalVariableBinding localBinding = visibleLocals[i];
+ if (localBinding != null) {
+ // Check if the local is definitely assigned
+ if ((initStateIndex != -1)
+ && isDefinitelyAssigned(scope, initStateIndex, localBinding)) {
+ if ((localBinding.initializationCount == 0)
+ || (localBinding.initializationPCs[((localBinding.initializationCount - 1) << 1)
+ + 1]
+ != -1)) {
+ /* There are two cases:
+ * 1) there is no initialization interval opened ==> add an opened interval
+ * 2) there is already some initialization intervals but the last one is closed ==> add an opened interval
+ * An opened interval means that the value at localBinding.initializationPCs[localBinding.initializationCount - 1][1]
+ * is equals to -1.
+ * initializationPCs is a collection of pairs of int:
+ * first value is the startPC and second value is the endPC. -1 one for the last value means that the interval
+ * is not closed yet.
+ */
+ localBinding.recordInitializationStartPC(position);
+ }
+ }
+ }
+ }
+ }
+
+ public void addLabel(Label aLabel) {
+ if (countLabels == labels.length)
+ System.arraycopy(
+ labels,
+ 0,
+ (labels = new Label[countLabels + LABELS_INCREMENT]),
+ 0,
+ countLabels);
+ labels[countLabels++] = aLabel;
+ }
+
+ public void addVisibleLocalVariable(LocalVariableBinding localBinding) {
+ if (!generateLocalVariableTableAttributes)
+ return;
+
+ if (visibleLocalsCount >= visibleLocals.length) {
+ System.arraycopy(
+ visibleLocals,
+ 0,
+ (visibleLocals = new LocalVariableBinding[visibleLocalsCount * 2]),
+ 0,
+ visibleLocalsCount);
+ }
+ visibleLocals[visibleLocalsCount++] = localBinding;
+ }
+
+ final public void aload(int iArg) {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ if (maxLocals <= iArg) {
+ maxLocals = iArg + 1;
+ }
+ if (iArg > 255) { // Widen
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_wide;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_wide);
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_aload;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_aload);
+ }
+ writeUnsignedShort(iArg);
+ } else {
+ // Don't need to use the wide bytecode
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_aload;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_aload);
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) (iArg);
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) iArg);
+ }
+ }
+ }
+
+ final public void aload_0() {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ if (maxLocals == 0) {
+ maxLocals = 1;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_aload_0;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_aload_0);
+ }
+ }
+
+ final public void aload_1() {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ if (maxLocals <= 1) {
+ maxLocals = 2;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_aload_1;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_aload_1);
+ }
+ }
+
+ final public void aload_2() {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ if (maxLocals <= 2) {
+ maxLocals = 3;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_aload_2;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_aload_2);
+ }
+ }
+
+ final public void aload_3() {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ if (maxLocals <= 3) {
+ maxLocals = 4;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_aload_3;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_aload_3);
+ }
+ }
+
+ public final void anewarray(TypeBinding typeBinding) {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_anewarray;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_anewarray);
+ }
+ writeUnsignedShort(constantPool.literalIndex(typeBinding));
+ }
+
+ public void anewarrayJavaLangClass() {
+ // anewarray: java.lang.Class
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_anewarray;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_anewarray);
+ }
+ writeUnsignedShort(constantPool.literalIndexForJavaLangClass());
+ }
+
+ public void anewarrayJavaLangObject() {
+ // anewarray: java.lang.Object
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_anewarray;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_anewarray);
+ }
+ writeUnsignedShort(constantPool.literalIndexForJavaLangObject());
+ }
+
+ final public void areturn() {
+ countLabels = 0;
+ stackDepth--;
+ // the stackDepth should be equal to 0
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_areturn;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_areturn);
+ }
+ }
+
+ public void arrayAt(int typeBindingID) {
+ switch (typeBindingID) {
+ case T_int :
+ this.iaload();
+ break;
+ case T_byte :
+ case T_boolean :
+ this.baload();
+ break;
+ case T_short :
+ this.saload();
+ break;
+ case T_char :
+ this.caload();
+ break;
+ case T_long :
+ this.laload();
+ break;
+ case T_float :
+ this.faload();
+ break;
+ case T_double :
+ this.daload();
+ break;
+ default :
+ this.aaload();
+ }
+ }
+
+ public void arrayAtPut(int elementTypeID, boolean valueRequired) {
+ switch (elementTypeID) {
+ case T_int :
+ if (valueRequired)
+ dup_x2();
+ iastore();
+ break;
+ case T_byte :
+ case T_boolean :
+ if (valueRequired)
+ dup_x2();
+ bastore();
+ break;
+ case T_short :
+ if (valueRequired)
+ dup_x2();
+ sastore();
+ break;
+ case T_char :
+ if (valueRequired)
+ dup_x2();
+ castore();
+ break;
+ case T_long :
+ if (valueRequired)
+ dup2_x2();
+ lastore();
+ break;
+ case T_float :
+ if (valueRequired)
+ dup_x2();
+ fastore();
+ break;
+ case T_double :
+ if (valueRequired)
+ dup2_x2();
+ dastore();
+ break;
+ default :
+ if (valueRequired)
+ dup_x2();
+ aastore();
+ }
+ }
+
+ final public void arraylength() {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_arraylength;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_arraylength);
+ }
+ }
+
+ final public void astore(int iArg) {
+ countLabels = 0;
+ stackDepth--;
+ if (maxLocals <= iArg) {
+ maxLocals = iArg + 1;
+ }
+ if (iArg > 255) { // Widen
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_wide;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_wide);
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_astore;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_astore);
+ }
+ writeUnsignedShort(iArg);
+ } else {
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_astore;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_astore);
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) iArg;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) iArg);
+ }
+ }
+ }
+
+ final public void astore_0() {
+ countLabels = 0;
+ stackDepth--;
+ if (maxLocals == 0) {
+ maxLocals = 1;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_astore_0;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_astore_0);
+ }
+ }
+
+ final public void astore_1() {
+ countLabels = 0;
+ stackDepth--;
+ if (maxLocals <= 1) {
+ maxLocals = 2;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_astore_1;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_astore_1);
+ }
+ }
+
+ final public void astore_2() {
+ countLabels = 0;
+ stackDepth--;
+ if (maxLocals <= 2) {
+ maxLocals = 3;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_astore_2;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_astore_2);
+ }
+ }
+
+ final public void astore_3() {
+ countLabels = 0;
+ stackDepth--;
+ if (maxLocals <= 3) {
+ maxLocals = 4;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_astore_3;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_astore_3);
+ }
+ }
+
+ final public void athrow() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_athrow;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_athrow);
+ }
+ }
+
+ final public void baload() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_baload;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_baload);
+ }
+ }
+
+ final public void bastore() {
+ countLabels = 0;
+ stackDepth -= 3;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_bastore;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_bastore);
+ }
+ }
+
+ final public void bipush(byte b) {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_bipush;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_bipush);
+ }
+ writeSignedByte(b);
+ }
+
+ final public void caload() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_caload;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_caload);
+ }
+ }
+
+ final public void castore() {
+ countLabels = 0;
+ stackDepth -= 3;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_castore;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_castore);
+ }
+ }
+
+ public final void checkcast(TypeBinding typeBinding) {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_checkcast;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_checkcast);
+ }
+ writeUnsignedShort(constantPool.literalIndex(typeBinding));
+ }
+
+ public final void checkcastJavaLangError() {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_checkcast;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_checkcast);
+ }
+ writeUnsignedShort(constantPool.literalIndexForJavaLangError());
+ }
+
+ final public void d2f() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_d2f;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_d2f);
+ }
+ }
+
+ final public void d2i() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_d2i;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_d2i);
+ }
+ }
+
+ final public void d2l() {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_d2l;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_d2l);
+ }
+ }
+
+ final public void dadd() {
+ countLabels = 0;
+ stackDepth -= 2;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dadd;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dadd);
+ }
+ }
+
+ final public void daload() {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_daload;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_daload);
+ }
+ }
+
+ final public void dastore() {
+ countLabels = 0;
+ stackDepth -= 4;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dastore;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dastore);
+ }
+ }
+
+ final public void dcmpg() {
+ countLabels = 0;
+ stackDepth -= 3;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dcmpg;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dcmpg);
+ }
+ }
+
+ final public void dcmpl() {
+ countLabels = 0;
+ stackDepth -= 3;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dcmpl;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dcmpl);
+ }
+ }
+
+ final public void dconst_0() {
+ countLabels = 0;
+ stackDepth += 2;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dconst_0;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dconst_0);
+ }
+ }
+
+ final public void dconst_1() {
+ countLabels = 0;
+ stackDepth += 2;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dconst_1;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dconst_1);
+ }
+ }
+
+ final public void ddiv() {
+ countLabels = 0;
+ stackDepth -= 2;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ddiv;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ddiv);
+ }
+ }
+
+ public void decrStackSize(int offset) {
+ stackDepth -= offset;
+ }
+
+ final public void dload(int iArg) {
+ countLabels = 0;
+ stackDepth += 2;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ if (maxLocals < iArg + 2) {
+ maxLocals = iArg + 2; // + 2 because it is a double
+ }
+ if (iArg > 255) { // Widen
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_wide;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_wide);
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dload;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dload);
+ }
+ writeUnsignedShort(iArg);
+ } else {
+ // Don't need to use the wide bytecode
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dload;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dload);
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) iArg;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) iArg);
+ }
+ }
+ }
+
+ final public void dload_0() {
+ countLabels = 0;
+ stackDepth += 2;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ if (maxLocals < 2) {
+ maxLocals = 2;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dload_0;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dload_0);
+ }
+ }
+
+ final public void dload_1() {
+ countLabels = 0;
+ stackDepth += 2;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ if (maxLocals < 3) {
+ maxLocals = 3;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dload_1;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dload_1);
+ }
+ }
+
+ final public void dload_2() {
+ countLabels = 0;
+ stackDepth += 2;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ if (maxLocals < 4) {
+ maxLocals = 4;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dload_2;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dload_2);
+ }
+ }
+
+ final public void dload_3() {
+ countLabels = 0;
+ stackDepth += 2;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ if (maxLocals < 5) {
+ maxLocals = 5;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dload_3;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dload_3);
+ }
+ }
+
+ final public void dmul() {
+ countLabels = 0;
+ stackDepth -= 2;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dmul;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dmul);
+ }
+ }
+
+ final public void dneg() {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dneg;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dneg);
+ }
+ }
+
+ final public void drem() {
+ countLabels = 0;
+ stackDepth -= 2;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_drem;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_drem);
+ }
+ }
+
+ final public void dreturn() {
+ countLabels = 0;
+ stackDepth -= 2;
+ // the stackDepth should be equal to 0
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dreturn;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dreturn);
+ }
+ }
+
+ final public void dstore(int iArg) {
+ countLabels = 0;
+ stackDepth -= 2;
+ if (maxLocals <= iArg + 1) {
+ maxLocals = iArg + 2;
+ }
+ if (iArg > 255) { // Widen
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_wide;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_wide);
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dstore;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dstore);
+ }
+ writeUnsignedShort(iArg);
+ } else {
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dstore;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dstore);
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) iArg;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) iArg);
+ }
+ }
+ }
+
+ final public void dstore_0() {
+ countLabels = 0;
+ stackDepth -= 2;
+ if (maxLocals < 2) {
+ maxLocals = 2;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dstore_0;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dstore_0);
+ }
+ }
+
+ final public void dstore_1() {
+ countLabels = 0;
+ stackDepth -= 2;
+ if (maxLocals < 3) {
+ maxLocals = 3;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dstore_1;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dstore_1);
+ }
+ }
+
+ final public void dstore_2() {
+ countLabels = 0;
+ stackDepth -= 2;
+ if (maxLocals < 4) {
+ maxLocals = 4;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dstore_2;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dstore_2);
+ }
+ }
+
+ final public void dstore_3() {
+ countLabels = 0;
+ stackDepth -= 2;
+ if (maxLocals < 5) {
+ maxLocals = 5;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dstore_3;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dstore_3);
+ }
+ }
+
+ final public void dsub() {
+ countLabels = 0;
+ stackDepth -= 2;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dsub;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dsub);
+ }
+ }
+
+ final public void dup() {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dup;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dup);
+ }
+ }
+
+ final public void dup_x1() {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dup_x1;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dup_x1);
+ }
+ }
+
+ final public void dup_x2() {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dup_x2;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dup_x2);
+ }
+ }
+
+ final public void dup2() {
+ countLabels = 0;
+ stackDepth += 2;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dup2;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dup2);
+ }
+ }
+
+ final public void dup2_x1() {
+ countLabels = 0;
+ stackDepth += 2;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dup2_x1;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dup2_x1);
+ }
+ }
+
+ final public void dup2_x2() {
+ countLabels = 0;
+ stackDepth += 2;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_dup2_x2;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_dup2_x2);
+ }
+ }
+
+ public void exitUserScope(BlockScope blockScope) {
+ // mark all the scope's locals as loosing their definite assignment
+
+ if (!generateLocalVariableTableAttributes)
+ return;
+ for (int i = 0; i < visibleLocalsCount; i++) {
+ LocalVariableBinding visibleLocal = visibleLocals[i];
+ if ((visibleLocal != null)
+ && (visibleLocal.declaringScope == blockScope)
+ && (visibleLocal.initializationCount > 0)) {
+ // for filtering out preserved locals never initialized
+ visibleLocals[i].recordInitializationEndPC(position);
+ visibleLocals[i] = null; // this variable is no longer visible afterwards
+ }
+ }
+ }
+
+ final public void f2d() {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_f2d;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_f2d);
+ }
+ }
+
+ final public void f2i() {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_f2i;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_f2i);
+ }
+ }
+
+ final public void f2l() {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_f2l;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_f2l);
+ }
+ }
+
+ final public void fadd() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_fadd;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_fadd);
+ }
+ }
+
+ final public void faload() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_faload;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_faload);
+ }
+ }
+
+ final public void fastore() {
+ countLabels = 0;
+ stackDepth -= 3;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_fastore;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_fastore);
+ }
+ }
+
+ final public void fcmpg() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_fcmpg;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_fcmpg);
+ }
+ }
+
+ final public void fcmpl() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_fcmpl;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_fcmpl);
+ }
+ }
+
+ final public void fconst_0() {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_fconst_0;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_fconst_0);
+ }
+ }
+
+ final public void fconst_1() {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_fconst_1;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_fconst_1);
+ }
+ }
+
+ final public void fconst_2() {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_fconst_2;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_fconst_2);
+ }
+ }
+
+ final public void fdiv() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_fdiv;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_fdiv);
+ }
+ }
+
+ final public void fload(int iArg) {
+ countLabels = 0;
+ stackDepth++;
+ if (maxLocals <= iArg) {
+ maxLocals = iArg + 1;
+ }
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ if (iArg > 255) { // Widen
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_wide;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_wide);
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_fload;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_fload);
+ }
+ writeUnsignedShort(iArg);
+ } else {
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_fload;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_fload);
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) iArg;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) iArg);
+ }
+ }
+ }
+
+ final public void fload_0() {
+ countLabels = 0;
+ stackDepth++;
+ if (maxLocals == 0) {
+ maxLocals = 1;
+ }
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_fload_0;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_fload_0);
+ }
+ }
+
+ final public void fload_1() {
+ countLabels = 0;
+ stackDepth++;
+ if (maxLocals <= 1) {
+ maxLocals = 2;
+ }
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_fload_1;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_fload_1);
+ }
+ }
+
+ final public void fload_2() {
+ countLabels = 0;
+ stackDepth++;
+ if (maxLocals <= 2) {
+ maxLocals = 3;
+ }
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_fload_2;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_fload_2);
+ }
+ }
+
+ final public void fload_3() {
+ countLabels = 0;
+ stackDepth++;
+ if (maxLocals <= 3) {
+ maxLocals = 4;
+ }
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_fload_3;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_fload_3);
+ }
+ }
+
+ final public void fmul() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_fmul;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_fmul);
+ }
+ }
+
+ final public void fneg() {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_fneg;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_fneg);
+ }
+ }
+
+ final public void frem() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_frem;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_frem);
+ }
+ }
+
+ final public void freturn() {
+ countLabels = 0;
+ stackDepth--;
+ // the stackDepth should be equal to 0
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_freturn;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_freturn);
+ }
+ }
+
+ final public void fstore(int iArg) {
+ countLabels = 0;
+ stackDepth--;
+ if (maxLocals <= iArg) {
+ maxLocals = iArg + 1;
+ }
+ if (iArg > 255) { // Widen
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_wide;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_wide);
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_fstore;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_fstore);
+ }
+ writeUnsignedShort(iArg);
+ } else {
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_fstore;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_fstore);
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) iArg;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) iArg);
+ }
+ }
+ }
+
+ final public void fstore_0() {
+ countLabels = 0;
+ stackDepth--;
+ if (maxLocals == 0) {
+ maxLocals = 1;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_fstore_0;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_fstore_0);
+ }
+ }
+
+ final public void fstore_1() {
+ countLabels = 0;
+ stackDepth--;
+ if (maxLocals <= 1) {
+ maxLocals = 2;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_fstore_1;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_fstore_1);
+ }
+ }
+
+ final public void fstore_2() {
+ countLabels = 0;
+ stackDepth--;
+ if (maxLocals <= 2) {
+ maxLocals = 3;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_fstore_2;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_fstore_2);
+ }
+ }
+
+ final public void fstore_3() {
+ countLabels = 0;
+ stackDepth--;
+ if (maxLocals <= 3) {
+ maxLocals = 4;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_fstore_3;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_fstore_3);
+ }
+ }
+
+ final public void fsub() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_fsub;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_fsub);
+ }
+ }
+
+ /**
+ * Macro for building a class descriptor object
+ */
+ public void generateClassLiteralAccessForType(
+ TypeBinding accessedType,
+ FieldBinding syntheticFieldBinding) {
+ Label endLabel;
+ ExceptionLabel anyExceptionHandler;
+ int saveStackSize;
+ if (accessedType.isBaseType()) {
+ this.getTYPE(accessedType.id);
+ return;
+ }
+ endLabel = new Label(this);
+
+ if (syntheticFieldBinding != null) { // non interface case
+ this.getstatic(syntheticFieldBinding);
+ this.dup();
+ this.ifnonnull(endLabel);
+ this.pop();
+ }
+
+ /* Macro for building a class descriptor object... using or not a field cache to store it into...
+ this sequence is responsible for building the actual class descriptor.
+
+ If the fieldCache is set, then it is supposed to be the body of a synthetic access method
+ factoring the actual descriptor creation out of the invocation site (saving space).
+ If the fieldCache is nil, then we are dumping the bytecode on the invocation site, since
+ we have no way to get a hand on the field cache to do better. */
+
+ // Wrap the code in an exception handler to convert a ClassNotFoundException into a NoClassDefError
+
+ anyExceptionHandler =
+ new ExceptionLabel(
+ this,
+ TypeBinding.NullBinding /* represents ClassNotFoundException*/);
+ this.ldc(
+ accessedType == TypeBinding.NullBinding
+ ? "java.lang.Object"
+ : String.valueOf(accessedType.constantPoolName()).replace('/', '.'));
+ this.invokeClassForName();
+
+ /* We need to protect the runtime code from binary inconsistencies
+ in case the accessedType is missing, the ClassNotFoundException has to be converted
+ into a NoClassDefError(old ex message), we thus need to build an exception handler for this one. */
+ anyExceptionHandler.placeEnd();
+
+ if (syntheticFieldBinding != null) { // non interface case
+ this.dup();
+ this.putstatic(syntheticFieldBinding);
+ }
+ this.goto_(endLabel);
+
+ // Generate the body of the exception handler
+ saveStackSize = stackDepth;
+ stackDepth = 1;
+ /* ClassNotFoundException on stack -- the class literal could be doing more things
+ on the stack, which means that the stack may not be empty at this point in the
+ above code gen. So we save its state and restart it from 1. */
+
+ anyExceptionHandler.place();
+
+ // Transform the current exception, and repush and throw a
+ // NoClassDefFoundError(ClassNotFound.getMessage())
+
+ this.newNoClassDefFoundError();
+ this.dup_x1();
+ this.swap();
+
+ // Retrieve the message from the old exception
+ this.invokeThrowableGetMessage();
+
+ // Send the constructor taking a message string as an argument
+ this.invokeNoClassDefFoundErrorStringConstructor();
+ this.athrow();
+ endLabel.place();
+ stackDepth = saveStackSize;
+ }
+
+ /**
+ * This method returns the exception handler to be able to generate the exception handler
+ * attribute.
+ */
+ final public int[] generateCodeAttributeForProblemMethod(
+ String errorName,
+ String problemMessage) {
+ /**
+ * Equivalent code:
+ * try {
+ * throw ((Error) (Class.forName(errorName).getConstructor(new Class[] {Class.forName("java.lang.String")})).newInstance(new Object[] {problemMessage}));
+ * } catch (Exception e) {
+ * throw (NullPointerException) null;
+ * }
+ */
+ int endPC, handlerPC;
+ ldc(errorName);
+ invokeClassForName();
+ iconst_1();
+ anewarrayJavaLangClass();
+ dup();
+ iconst_0();
+ ldc("java.lang.String");
+ invokeClassForName();
+ aastore();
+ invokeConstructorGetConstructor();
+ iconst_1();
+ anewarrayJavaLangObject();
+ dup();
+ iconst_0();
+ ldc(problemMessage);
+ aastore();
+ invokeObjectNewInstance();
+ checkcastJavaLangError();
+ athrow();
+ endPC = handlerPC = position;
+ pop();
+ aconst_null();
+ athrow();
+ return_();
+ return new int[] { 0, endPC, handlerPC };
+ }
+
+ public void generateConstant(Constant constant, int implicitConversionCode) {
+ int targetTypeID = implicitConversionCode >> 4;
+ switch (targetTypeID) {
+ case T_boolean :
+ generateInlinedValue(constant.booleanValue());
+ break;
+ case T_char :
+ generateInlinedValue(constant.charValue());
+ break;
+ case T_byte :
+ generateInlinedValue(constant.byteValue());
+ break;
+ case T_short :
+ generateInlinedValue(constant.shortValue());
+ break;
+ case T_int :
+ generateInlinedValue(constant.intValue());
+ break;
+ case T_long :
+ generateInlinedValue(constant.longValue());
+ break;
+ case T_float :
+ generateInlinedValue(constant.floatValue());
+ break;
+ case T_double :
+ generateInlinedValue(constant.doubleValue());
+ break;
+ case T_String :
+ this.ldc(constant.stringValue());
+ break;
+ default : //reference object (constant can be from T_null or T_String)
+ if (constant.typeID() == T_String)
+ ldc(constant.stringValue());
+ else
+ aconst_null();
+ }
+ }
+
+ /**
+ * @param implicitConversionCode int
+ */
+ public void generateImplicitConversion(int implicitConversionCode) {
+ switch (implicitConversionCode) {
+ case Float2Char :
+ this.f2i();
+ this.i2c();
+ break;
+ case Double2Char :
+ this.d2i();
+ this.i2c();
+ break;
+ case Int2Char :
+ case Short2Char :
+ case Byte2Char :
+ this.i2c();
+ break;
+ case Long2Char :
+ this.l2i();
+ this.i2c();
+ break;
+ case Char2Float :
+ case Short2Float :
+ case Int2Float :
+ case Byte2Float :
+ this.i2f();
+ break;
+ case Double2Float :
+ this.d2f();
+ break;
+ case Long2Float :
+ this.l2f();
+ break;
+ case Float2Byte :
+ this.f2i();
+ this.i2b();
+ break;
+ case Double2Byte :
+ this.d2i();
+ this.i2b();
+ break;
+ case Int2Byte :
+ case Short2Byte :
+ case Char2Byte :
+ this.i2b();
+ break;
+ case Long2Byte :
+ this.l2i();
+ this.i2b();
+ break;
+ case Byte2Double :
+ case Char2Double :
+ case Short2Double :
+ case Int2Double :
+ this.i2d();
+ break;
+ case Float2Double :
+ this.f2d();
+ break;
+ case Long2Double :
+ this.l2d();
+ break;
+ case Byte2Short :
+ case Char2Short :
+ case Int2Short :
+ this.i2s();
+ break;
+ case Double2Short :
+ this.d2i();
+ this.i2s();
+ break;
+ case Long2Short :
+ this.l2i();
+ this.i2s();
+ break;
+ case Float2Short :
+ this.f2i();
+ this.i2s();
+ break;
+ case Double2Int :
+ this.d2i();
+ break;
+ case Float2Int :
+ this.f2i();
+ break;
+ case Long2Int :
+ this.l2i();
+ break;
+ case Int2Long :
+ case Char2Long :
+ case Byte2Long :
+ case Short2Long :
+ this.i2l();
+ break;
+ case Double2Long :
+ this.d2l();
+ break;
+ case Float2Long :
+ this.f2l();
+ }
+ }
+
+ public void generateInlinedValue(byte inlinedValue) {
+ switch (inlinedValue) {
+ case -1 :
+ this.iconst_m1();
+ break;
+ case 0 :
+ this.iconst_0();
+ break;
+ case 1 :
+ this.iconst_1();
+ break;
+ case 2 :
+ this.iconst_2();
+ break;
+ case 3 :
+ this.iconst_3();
+ break;
+ case 4 :
+ this.iconst_4();
+ break;
+ case 5 :
+ this.iconst_5();
+ break;
+ default :
+ if ((-128 <= inlinedValue) && (inlinedValue <= 127)) {
+ this.bipush((byte) inlinedValue);
+ return;
+ }
+ }
+ }
+
+ public void generateInlinedValue(char inlinedValue) {
+ switch (inlinedValue) {
+ case 0 :
+ this.iconst_0();
+ break;
+ case 1 :
+ this.iconst_1();
+ break;
+ case 2 :
+ this.iconst_2();
+ break;
+ case 3 :
+ this.iconst_3();
+ break;
+ case 4 :
+ this.iconst_4();
+ break;
+ case 5 :
+ this.iconst_5();
+ break;
+ default :
+ if ((6 <= inlinedValue) && (inlinedValue <= 127)) {
+ this.bipush((byte) inlinedValue);
+ return;
+ }
+ if ((128 <= inlinedValue) && (inlinedValue <= 32767)) {
+ this.sipush(inlinedValue);
+ return;
+ }
+ this.ldc(inlinedValue);
+ }
+ }
+
+ public void generateInlinedValue(double inlinedValue) {
+ if (inlinedValue == 0.0) {
+ if (Double.doubleToLongBits(inlinedValue) != 0L)
+ this.ldc2_w(inlinedValue);
+ else
+ this.dconst_0();
+ return;
+ }
+ if (inlinedValue == 1.0) {
+ this.dconst_1();
+ return;
+ }
+ this.ldc2_w(inlinedValue);
+ }
+
+ public void generateInlinedValue(float inlinedValue) {
+ if (inlinedValue == 0.0f) {
+ if (Float.floatToIntBits(inlinedValue) != 0)
+ this.ldc(inlinedValue);
+ else
+ this.fconst_0();
+ return;
+ }
+ if (inlinedValue == 1.0f) {
+ this.fconst_1();
+ return;
+ }
+ if (inlinedValue == 2.0f) {
+ this.fconst_2();
+ return;
+ }
+ this.ldc(inlinedValue);
+ }
+
+ public void generateInlinedValue(int inlinedValue) {
+ switch (inlinedValue) {
+ case -1 :
+ this.iconst_m1();
+ break;
+ case 0 :
+ this.iconst_0();
+ break;
+ case 1 :
+ this.iconst_1();
+ break;
+ case 2 :
+ this.iconst_2();
+ break;
+ case 3 :
+ this.iconst_3();
+ break;
+ case 4 :
+ this.iconst_4();
+ break;
+ case 5 :
+ this.iconst_5();
+ break;
+ default :
+ if ((-128 <= inlinedValue) && (inlinedValue <= 127)) {
+ this.bipush((byte) inlinedValue);
+ return;
+ }
+ if ((-32768 <= inlinedValue) && (inlinedValue <= 32767)) {
+ this.sipush(inlinedValue);
+ return;
+ }
+ this.ldc(inlinedValue);
+ }
+ }
+
+ public void generateInlinedValue(long inlinedValue) {
+ if (inlinedValue == 0) {
+ this.lconst_0();
+ return;
+ }
+ if (inlinedValue == 1) {
+ this.lconst_1();
+ return;
+ }
+ this.ldc2_w(inlinedValue);
+ }
+
+ public void generateInlinedValue(short inlinedValue) {
+ switch (inlinedValue) {
+ case -1 :
+ this.iconst_m1();
+ break;
+ case 0 :
+ this.iconst_0();
+ break;
+ case 1 :
+ this.iconst_1();
+ break;
+ case 2 :
+ this.iconst_2();
+ break;
+ case 3 :
+ this.iconst_3();
+ break;
+ case 4 :
+ this.iconst_4();
+ break;
+ case 5 :
+ this.iconst_5();
+ break;
+ default :
+ if ((-128 <= inlinedValue) && (inlinedValue <= 127)) {
+ this.bipush((byte) inlinedValue);
+ return;
+ }
+ this.sipush(inlinedValue);
+ }
+ }
+
+ public void generateInlinedValue(boolean inlinedValue) {
+ if (inlinedValue)
+ this.iconst_1();
+ else
+ this.iconst_0();
+ }
+
+ public void generateObjectWrapperForType(TypeBinding valueType) {
+
+ /* The top of stack must be encapsulated inside
+ * a wrapper object if it corresponds to a base type
+ */
+ char[][] wrapperTypeCompoundName = null;
+ switch (valueType.id) {
+ case T_int : // new: java.lang.Integer
+ wrapperTypeCompoundName =
+ new char[][] {
+ "java".toCharArray(),
+ "lang".toCharArray(),
+ "Integer".toCharArray()};
+ break;
+ case T_boolean : // new: java.lang.Boolean
+ wrapperTypeCompoundName =
+ new char[][] {
+ "java".toCharArray(),
+ "lang".toCharArray(),
+ "Boolean".toCharArray()};
+ break;
+ case T_byte : // new: java.lang.Byte
+ wrapperTypeCompoundName =
+ new char[][] {
+ "java".toCharArray(),
+ "lang".toCharArray(),
+ "Byte".toCharArray()};
+ break;
+ case T_char : // new: java.lang.Character
+ wrapperTypeCompoundName =
+ new char[][] {
+ "java".toCharArray(),
+ "lang".toCharArray(),
+ "Character".toCharArray()};
+ break;
+ case T_float : // new: java.lang.Float
+ wrapperTypeCompoundName =
+ new char[][] {
+ "java".toCharArray(),
+ "lang".toCharArray(),
+ "Float".toCharArray()};
+ break;
+ case T_double : // new: java.lang.Double
+ wrapperTypeCompoundName =
+ new char[][] {
+ "java".toCharArray(),
+ "lang".toCharArray(),
+ "Double".toCharArray()};
+ break;
+ case T_short : // new: java.lang.Short
+ wrapperTypeCompoundName =
+ new char[][] {
+ "java".toCharArray(),
+ "lang".toCharArray(),
+ "Short".toCharArray()};
+ break;
+ case T_long : // new: java.lang.Long
+ wrapperTypeCompoundName =
+ new char[][] {
+ "java".toCharArray(),
+ "lang".toCharArray(),
+ "Long".toCharArray()};
+ break;
+ }
+ TypeBinding wrapperType =
+ methodDeclaration.scope.getType(wrapperTypeCompoundName);
+ new_(wrapperType);
+ if (valueType.id == T_long || valueType.id == T_double) {
+ dup_x2();
+ dup_x2();
+ pop();
+ } else {
+ dup_x1();
+ swap();
+ }
+ MethodBinding methodBinding =
+ methodDeclaration.scope.getMethod(
+ wrapperType,
+ QualifiedNamesConstants.Init,
+ new TypeBinding[] { valueType },
+ null);
+ invokespecial(methodBinding);
+ }
+
+ public void generateOuterAccess(
+ Object[] mappingSequence,
+ AstNode invocationSite,
+ Scope scope) {
+ if (mappingSequence == null)
+ return;
+ if (mappingSequence == BlockScope.EmulationPathToImplicitThis) {
+ if (scope.methodScope().isConstructorCall) {
+ scope.problemReporter().errorThisSuperInStatic(invocationSite);
+ }
+ this.aload_0();
+ return;
+ }
+ if (mappingSequence[0] instanceof FieldBinding) {
+ FieldBinding fieldBinding = (FieldBinding) mappingSequence[0];
+ if (scope.methodScope().isConstructorCall) {
+ scope.problemReporter().errorThisSuperInStatic(invocationSite);
+ }
+ this.aload_0();
+ this.getfield(fieldBinding);
+ } else {
+ load((LocalVariableBinding) mappingSequence[0]);
+ }
+ for (int i = 1, length = mappingSequence.length; i < length; i++) {
+ if (mappingSequence[i] instanceof FieldBinding) {
+ FieldBinding fieldBinding = (FieldBinding) mappingSequence[i];
+ this.getfield(fieldBinding);
+ } else {
+ this.invokestatic((MethodBinding) mappingSequence[i]);
+ }
+ }
+ }
+
+ /**
+ * The equivalent code performs a string conversion:
+ *
+ * @param oper1 org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param oper1 org.eclipse.jdt.internal.compiler.ast.Expression
+ * @param oper2 org.eclipse.jdt.internal.compiler.ast.Expression
+ */
+ public void generateStringAppend(
+ BlockScope blockScope,
+ Expression oper1,
+ Expression oper2) {
+ int pc;
+ if (oper1 == null) {
+ /* Operand is already on the stack, and maybe nil:
+ note type1 is always to java.lang.String here.*/
+ this.newStringBuffer();
+ this.dup_x1();
+ this.swap();
+ // If argument is reference type, need to transform it
+ // into a string (handles null case)
+ this.invokeStringValueOf(T_Object);
+ this.invokeStringBufferStringConstructor();
+ } else {
+ pc = position;
+ oper1.generateOptimizedStringBufferCreation(
+ blockScope,
+ this,
+ oper1.implicitConversion & 0xF);
+ this.recordPositionsFrom(pc, oper1);
+ }
+ pc = position;
+ oper2.generateOptimizedStringBuffer(
+ blockScope,
+ this,
+ oper2.implicitConversion & 0xF);
+ this.recordPositionsFrom(pc, oper2);
+ this.invokeStringBufferToString();
+ }
+
+ /**
+ * Code responsible to generate the suitable code to supply values for the synthetic arguments of
+ * a constructor invocation of a nested type.
+ */
+ public void generateSyntheticArgumentValues(
+ BlockScope currentScope,
+ ReferenceBinding targetType,
+ Expression enclosingInstance,
+ AstNode invocationSite) {
+
+ // perform some emulation work in case there is some and we are inside a local type only
+ ReferenceBinding[] syntheticArgumentTypes;
+
+ // generate the enclosing instance first
+ if ((syntheticArgumentTypes = targetType.syntheticEnclosingInstanceTypes())
+ != null) {
+ ReferenceBinding targetEnclosingType = targetType.enclosingType();
+ for (int i = 0, max = syntheticArgumentTypes.length; i < max; i++) {
+ ReferenceBinding syntheticArgType = syntheticArgumentTypes[i];
+ if (enclosingInstance != null && i == 0) {
+ boolean enclosingInstanceRequired =
+ targetType.isAnonymousType()
+ ? syntheticArgType == targetType.superclass().enclosingType()
+ // supplying enclosing instance for the anonymous type's superclass
+ : syntheticArgType == targetEnclosingType;
+ if (!enclosingInstanceRequired) {
+ currentScope.problemReporter().unnecessaryEnclosingInstanceSpecification(
+ enclosingInstance,
+ targetType);
+ }
+ enclosingInstance.generateCode(currentScope, this, enclosingInstanceRequired);
+ } else {
+ Object[] emulationPath =
+ currentScope.getCompatibleEmulationPath(syntheticArgType);
+ if (emulationPath == null) {
+ // could not emulate a path to a given enclosing instance (must specify one - if direct enclosing instance)
+ if (syntheticArgType == targetEnclosingType) {
+ // missing direct enclosing instance
+ currentScope.problemReporter().missingEnclosingInstanceSpecification(
+ targetEnclosingType,
+ invocationSite);
+ } else {
+ currentScope.problemReporter().needImplementation();
+ }
+ } else {
+ this.generateOuterAccess(emulationPath, invocationSite, currentScope);
+ }
+ }
+ }
+ } else { // we may still have an enclosing instance to consider
+ if (enclosingInstance != null) {
+ currentScope.problemReporter().unnecessaryEnclosingInstanceSpecification(
+ enclosingInstance,
+ targetType);
+ enclosingInstance.generateCode(currentScope, this, false);
+ // do not want the value
+ }
+ }
+ // generate the synthetic outer arguments then
+ SyntheticArgumentBinding syntheticArguments[];
+ if ((syntheticArguments = targetType.syntheticOuterLocalVariables()) != null) {
+ for (int i = 0, max = syntheticArguments.length; i < max; i++) {
+ VariableBinding[] emulationPath =
+ currentScope.getEmulationPath(syntheticArguments[i].actualOuterLocalVariable);
+ if (emulationPath == null) {
+ // could not emulate a path to a given outer local variable (internal error)
+ currentScope.problemReporter().needImplementation();
+ } else {
+ this.generateOuterAccess(emulationPath, invocationSite, currentScope);
+ }
+ }
+ }
+ }
+
+ /**
+ * @param parameters org.eclipse.jdt.internal.compiler.lookup.TypeBinding[]
+ * @param constructorBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding
+ */
+ public void generateSyntheticBodyForConstructorAccess(SyntheticAccessMethodBinding accessBinding) {
+
+ initializeMaxLocals(accessBinding);
+
+ MethodBinding constructorBinding = accessBinding.targetMethod;
+ TypeBinding[] parameters = constructorBinding.parameters;
+ int length = parameters.length;
+ int resolvedPosition = 1;
+ this.aload_0();
+ if (constructorBinding.declaringClass.isNestedType()) {
+ NestedTypeBinding nestedType =
+ (NestedTypeBinding) constructorBinding.declaringClass;
+ SyntheticArgumentBinding[] syntheticArguments =
+ nestedType.syntheticEnclosingInstances();
+ for (int i = 0;
+ i < (syntheticArguments == null ? 0 : syntheticArguments.length);
+ i++) {
+ TypeBinding type;
+ load((type = syntheticArguments[i].type), resolvedPosition);
+ if ((type == DoubleBinding) || (type == LongBinding))
+ resolvedPosition += 2;
+ else
+ resolvedPosition++;
+ }
+ syntheticArguments = nestedType.syntheticOuterLocalVariables();
+ for (int i = 0;
+ i < (syntheticArguments == null ? 0 : syntheticArguments.length);
+ i++) {
+ TypeBinding type;
+ load((type = syntheticArguments[i].type), resolvedPosition);
+ if ((type == DoubleBinding) || (type == LongBinding))
+ resolvedPosition += 2;
+ else
+ resolvedPosition++;
+ }
+ }
+ for (int i = 0; i < length; i++) {
+ load(parameters[i], resolvedPosition);
+ if ((parameters[i] == DoubleBinding) || (parameters[i] == LongBinding))
+ resolvedPosition += 2;
+ else
+ resolvedPosition++;
+ }
+ this.invokespecial(constructorBinding);
+ this.return_();
+ }
+
+ public void generateSyntheticBodyForFieldReadAccess(SyntheticAccessMethodBinding accessBinding) {
+ initializeMaxLocals(accessBinding);
+ FieldBinding fieldBinding = accessBinding.targetReadField;
+ TypeBinding type;
+ if (fieldBinding.isStatic())
+ this.getstatic(fieldBinding);
+ else {
+ this.aload_0();
+ this.getfield(fieldBinding);
+ }
+ if ((type = fieldBinding.type).isBaseType()) {
+ if (type == IntBinding)
+ this.ireturn();
+ else
+ if (type == FloatBinding)
+ this.freturn();
+ else
+ if (type == LongBinding)
+ this.lreturn();
+ else
+ if (type == DoubleBinding)
+ this.dreturn();
+ else
+ this.ireturn();
+ } else
+ this.areturn();
+ }
+
+ public void generateSyntheticBodyForFieldWriteAccess(SyntheticAccessMethodBinding accessBinding) {
+ initializeMaxLocals(accessBinding);
+ FieldBinding fieldBinding = accessBinding.targetWriteField;
+ if (fieldBinding.isStatic()) {
+ load(fieldBinding.type, 0);
+ this.putstatic(fieldBinding);
+ } else {
+ this.aload_0();
+ load(fieldBinding.type, 1);
+ this.putfield(fieldBinding);
+ }
+ this.return_();
+ }
+
+ public void generateSyntheticBodyForMethodAccess(SyntheticAccessMethodBinding accessBinding) {
+
+ initializeMaxLocals(accessBinding);
+ MethodBinding methodBinding = accessBinding.targetMethod;
+ TypeBinding[] parameters = methodBinding.parameters;
+ int length = parameters.length;
+ int resolvedPosition;
+ if (methodBinding.isStatic())
+ resolvedPosition = 0;
+ else {
+ this.aload_0();
+ resolvedPosition = 1;
+ }
+ for (int i = 0; i < length; i++) {
+ load(parameters[i], resolvedPosition);
+ if ((parameters[i] == DoubleBinding) || (parameters[i] == LongBinding))
+ resolvedPosition += 2;
+ else
+ resolvedPosition++;
+ }
+ TypeBinding type;
+ int id;
+ if (methodBinding.isStatic())
+ this.invokestatic(methodBinding);
+ else {
+ if (methodBinding.isConstructor()
+ || methodBinding.isPrivate()
+ // qualified super "X.super.foo()" targets methods from superclass
+ || (methodBinding.declaringClass != methodDeclaration.binding.declaringClass)) {
+ this.invokespecial(methodBinding);
+ } else {
+ if (methodBinding.declaringClass.isInterface()) {
+ this.invokeinterface(methodBinding);
+ } else {
+ this.invokevirtual(methodBinding);
+ }
+ }
+ }
+ if ((type = methodBinding.returnType).isBaseType())
+ if (type == VoidBinding)
+ this.return_();
+ else
+ if (type == IntBinding)
+ this.ireturn();
+ else
+ if (type == FloatBinding)
+ this.freturn();
+ else
+ if (type == LongBinding)
+ this.lreturn();
+ else
+ if (type == DoubleBinding)
+ this.dreturn();
+ else
+ this.ireturn();
+ else
+ this.areturn();
+ }
+
+ final public byte[] getContents() {
+ byte[] contents;
+ System.arraycopy(bCodeStream, 0, contents = new byte[position], 0, position);
+ return contents;
+ }
+
+ final public void getfield(FieldBinding fieldBinding) {
+ countLabels = 0;
+ if ((fieldBinding.type.id == T_double) || (fieldBinding.type.id == T_long)) {
+ if (++stackDepth > stackMax)
+ stackMax = stackDepth;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_getfield;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_getfield);
+ }
+ writeUnsignedShort(constantPool.literalIndex(fieldBinding));
+ }
+
+ final public void getstatic(FieldBinding fieldBinding) {
+ countLabels = 0;
+ if ((fieldBinding.type.id == T_double) || (fieldBinding.type.id == T_long))
+ stackDepth += 2;
+ else
+ stackDepth += 1;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_getstatic;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_getstatic);
+ }
+ writeUnsignedShort(constantPool.literalIndex(fieldBinding));
+ }
+
+ public void getSystemOut() {
+ countLabels = 0;
+ if (++stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_getstatic;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_getstatic);
+ }
+ writeUnsignedShort(constantPool.literalIndexForJavaLangSystemOut());
+ }
+
+ public void getTYPE(int baseTypeID) {
+ countLabels = 0;
+ if (++stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_getstatic;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_getstatic);
+ }
+ switch (baseTypeID) {
+ // getstatic: java.lang.Byte.TYPE
+ case T_byte :
+ writeUnsignedShort(constantPool.literalIndexForJavaLangByteTYPE());
+ break;
+ // getstatic: java.lang.Short.TYPE
+ case T_short :
+ writeUnsignedShort(constantPool.literalIndexForJavaLangShortTYPE());
+ break;
+ // getstatic: java.lang.Character.TYPE
+ case T_char :
+ writeUnsignedShort(constantPool.literalIndexForJavaLangCharacterTYPE());
+ break;
+ // getstatic: java.lang.Integer.TYPE
+ case T_int :
+ writeUnsignedShort(constantPool.literalIndexForJavaLangIntegerTYPE());
+ break;
+ // getstatic: java.lang.Long.TYPE
+ case T_long :
+ writeUnsignedShort(constantPool.literalIndexForJavaLangLongTYPE());
+ break;
+ // getstatic: java.lang.Float.TYPE
+ case T_float :
+ writeUnsignedShort(constantPool.literalIndexForJavaLangFloatTYPE());
+ break;
+ // getstatic: java.lang.Double.TYPE
+ case T_double :
+ writeUnsignedShort(constantPool.literalIndexForJavaLangDoubleTYPE());
+ break;
+ // getstatic: java.lang.Boolean.TYPE
+ case T_boolean :
+ writeUnsignedShort(constantPool.literalIndexForJavaLangBooleanTYPE());
+ break;
+ // getstatic: java.lang.Void.TYPE
+ case T_void :
+ writeUnsignedShort(constantPool.literalIndexForJavaLangVoidTYPE());
+ break;
+ }
+ }
+
+ /**
+ * We didn't call it goto, because there is a conflit with the goto keyword
+ */
+ final public void goto_(Label lbl) {
+ try {
+ lbl.inlineForwardReferencesFromLabelsTargeting(position);
+ /*
+ Possible optimization for code such as:
+ public Object foo() {
+ boolean b = true;
+ if (b) {
+ if (b)
+ return null;
+ } else {
+ if (b) {
+ return null;
+ }
+ }
+ return null;
+ }
+ The goto around the else block for the first if will
+ be unreachable, because the thenClause of the second if
+ returns.
+ See inlineForwardReferencesFromLabelsTargeting defined
+ on the Label class for the remaining part of this
+ optimization.
+ if (!lbl.isBranchTarget(position)) {
+ switch(bCodeStream[classFileOffset-1]) {
+ case OPC_return :
+ case OPC_areturn:
+ return;
+ }
+ }*/
+ position++;
+ bCodeStream[classFileOffset++] = OPC_goto;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_goto);
+ }
+ lbl.branch();
+ }
+
+ final public void goto_w(Label lbl) {
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_goto_w;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_goto_w);
+ }
+ lbl.branchWide();
+ }
+
+ final public void i2b() {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_i2b;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_i2b);
+ }
+ }
+
+ final public void i2c() {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_i2c;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_i2c);
+ }
+ }
+
+ final public void i2d() {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_i2d;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_i2d);
+ }
+ }
+
+ final public void i2f() {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_i2f;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_i2f);
+ }
+ }
+
+ final public void i2l() {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_i2l;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_i2l);
+ }
+ }
+
+ final public void i2s() {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_i2s;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_i2s);
+ }
+ }
+
+ final public void iadd() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_iadd;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_iadd);
+ }
+ }
+
+ final public void iaload() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_iaload;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_iaload);
+ }
+ }
+
+ final public void iand() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_iand;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_iand);
+ }
+ }
+
+ final public void iastore() {
+ countLabels = 0;
+ stackDepth -= 3;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_iastore;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_iastore);
+ }
+ }
+
+ final public void iconst_0() {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_iconst_0;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_iconst_0);
+ }
+ }
+
+ final public void iconst_1() {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_iconst_1;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_iconst_1);
+ }
+ }
+
+ final public void iconst_2() {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_iconst_2;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_iconst_2);
+ }
+ }
+
+ final public void iconst_3() {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_iconst_3;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_iconst_3);
+ }
+ }
+
+ final public void iconst_4() {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_iconst_4;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_iconst_4);
+ }
+ }
+
+ final public void iconst_5() {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_iconst_5;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_iconst_5);
+ }
+ }
+
+ final public void iconst_m1() {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_iconst_m1;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_iconst_m1);
+ }
+ }
+
+ final public void idiv() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_idiv;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_idiv);
+ }
+ }
+
+ final public void if_acmpeq(Label lbl) {
+ countLabels = 0;
+ stackDepth -= 2;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_if_acmpeq;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_if_acmpeq);
+ }
+ lbl.branch();
+ }
+
+ final public void if_acmpne(Label lbl) {
+ countLabels = 0;
+ stackDepth -= 2;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_if_acmpne;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_if_acmpne);
+ }
+ lbl.branch();
+ }
+
+ final public void if_icmpeq(Label lbl) {
+ countLabels = 0;
+ stackDepth -= 2;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_if_icmpeq;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_if_icmpeq);
+ }
+ lbl.branch();
+ }
+
+ final public void if_icmpge(Label lbl) {
+ countLabels = 0;
+ stackDepth -= 2;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_if_icmpge;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_if_icmpge);
+ }
+ lbl.branch();
+ }
+
+ final public void if_icmpgt(Label lbl) {
+ countLabels = 0;
+ stackDepth -= 2;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_if_icmpgt;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_if_icmpgt);
+ }
+ lbl.branch();
+ }
+
+ final public void if_icmple(Label lbl) {
+ countLabels = 0;
+ stackDepth -= 2;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_if_icmple;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_if_icmple);
+ }
+ lbl.branch();
+ }
+
+ final public void if_icmplt(Label lbl) {
+ countLabels = 0;
+ stackDepth -= 2;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_if_icmplt;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_if_icmplt);
+ }
+ lbl.branch();
+ }
+
+ final public void if_icmpne(Label lbl) {
+ countLabels = 0;
+ stackDepth -= 2;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_if_icmpne;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_if_icmpne);
+ }
+ lbl.branch();
+ }
+
+ final public void ifeq(Label lbl) {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ifeq;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ifeq);
+ }
+ lbl.branch();
+ }
+
+ final public void ifge(Label lbl) {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ifge;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ifge);
+ }
+ lbl.branch();
+ }
+
+ final public void ifgt(Label lbl) {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ifgt;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ifgt);
+ }
+ lbl.branch();
+ }
+
+ final public void ifle(Label lbl) {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ifle;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ifle);
+ }
+ lbl.branch();
+ }
+
+ final public void iflt(Label lbl) {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_iflt;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_iflt);
+ }
+ lbl.branch();
+ }
+
+ final public void ifne(Label lbl) {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ifne;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ifne);
+ }
+ lbl.branch();
+ }
+
+ final public void ifnonnull(Label lbl) {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ifnonnull;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ifnonnull);
+ }
+ lbl.branch();
+ }
+
+ final public void ifnull(Label lbl) {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ifnull;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ifnull);
+ }
+ lbl.branch();
+ }
+
+ final public void iinc(int index, int value) {
+ countLabels = 0;
+ if ((index > 255) || (value < -128 || value > 127)) { // have to widen
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_wide;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_wide);
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_iinc;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_iinc);
+ }
+ writeUnsignedShort(index);
+ writeSignedShort(value);
+ } else {
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_iinc;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_iinc);
+ }
+ writeUnsignedByte(index);
+ writeSignedByte(value);
+ }
+ }
+
+ final public void iload(int iArg) {
+ countLabels = 0;
+ stackDepth++;
+ if (maxLocals <= iArg) {
+ maxLocals = iArg + 1;
+ }
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ if (iArg > 255) { // Widen
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_wide;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_wide);
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_iload;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_iload);
+ }
+ writeUnsignedShort(iArg);
+ } else {
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_iload;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_iload);
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) iArg;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) iArg);
+ }
+ }
+ }
+
+ final public void iload_0() {
+ countLabels = 0;
+ stackDepth++;
+ if (maxLocals <= 0) {
+ maxLocals = 1;
+ }
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_iload_0;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_iload_0);
+ }
+ }
+
+ final public void iload_1() {
+ countLabels = 0;
+ stackDepth++;
+ if (maxLocals <= 1) {
+ maxLocals = 2;
+ }
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_iload_1;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_iload_1);
+ }
+ }
+
+ final public void iload_2() {
+ countLabels = 0;
+ stackDepth++;
+ if (maxLocals <= 2) {
+ maxLocals = 3;
+ }
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_iload_2;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_iload_2);
+ }
+ }
+
+ final public void iload_3() {
+ countLabels = 0;
+ stackDepth++;
+ if (maxLocals <= 3) {
+ maxLocals = 4;
+ }
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_iload_3;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_iload_3);
+ }
+ }
+
+ final public void imul() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_imul;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_imul);
+ }
+ }
+
+ public void incrementTemp(LocalVariableBinding localBinding, int value) {
+ if (value == (short) value) {
+ this.iinc(localBinding.resolvedPosition, value);
+ return;
+ }
+ load(localBinding);
+ this.ldc(value);
+ this.iadd();
+ store(localBinding, false);
+ }
+
+ public void incrStackSize(int offset) {
+ if ((stackDepth += offset) > stackMax)
+ stackMax = stackDepth;
+ }
+
+ public int indexOfSameLineEntrySincePC(int pc, int line) {
+ for (int index = pc, max = pcToSourceMapSize; index < max; index += 2) {
+ if (pcToSourceMap[index + 1] == line)
+ return index;
+ }
+ return -1;
+ }
+
+ final public void ineg() {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ineg;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ineg);
+ }
+ }
+
+ public void init(ClassFile classFile) {
+ this.classFile = classFile;
+ this.constantPool = classFile.constantPool;
+ this.bCodeStream = classFile.contents;
+ this.classFileOffset = classFile.contentsOffset;
+ this.startingClassFileOffset = this.classFileOffset;
+ pcToSourceMapSize = 0;
+ lastEntryPC = 0;
+ int length = visibleLocals.length;
+ if (noVisibleLocals.length < length) {
+ noVisibleLocals = new LocalVariableBinding[length];
+ }
+ System.arraycopy(noVisibleLocals, 0, visibleLocals, 0, length);
+ visibleLocalsCount = 0;
+
+ length = locals.length;
+ if (noLocals.length < length) {
+ noLocals = new LocalVariableBinding[length];
+ }
+ System.arraycopy(noLocals, 0, locals, 0, length);
+ allLocalsCounter = 0;
+
+ length = exceptionHandlers.length;
+ if (noExceptionHandlers.length < length) {
+ noExceptionHandlers = new ExceptionLabel[length];
+ }
+ System.arraycopy(noExceptionHandlers, 0, exceptionHandlers, 0, length);
+ exceptionHandlersNumber = 0;
+
+ length = labels.length;
+ if (noLabels.length < length) {
+ noLabels = new Label[length];
+ }
+ System.arraycopy(noLabels, 0, labels, 0, length);
+ countLabels = 0;
+
+ stackMax = 0;
+ stackDepth = 0;
+ maxLocals = 0;
+ position = 0;
+ }
+
+ /**
+ * @param methodDeclaration org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
+ * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile
+ */
+ public void initializeMaxLocals(MethodBinding methodBinding) {
+
+ maxLocals = (methodBinding == null || methodBinding.isStatic()) ? 0 : 1;
+ // take into account the synthetic parameters
+ if (methodBinding != null) {
+ if (methodBinding.isConstructor()
+ && methodBinding.declaringClass.isNestedType()) {
+ ReferenceBinding enclosingInstanceTypes[];
+ if ((enclosingInstanceTypes =
+ methodBinding.declaringClass.syntheticEnclosingInstanceTypes())
+ != null) {
+ for (int i = 0, max = enclosingInstanceTypes.length; i < max; i++) {
+ maxLocals++;
+ // an enclosingInstanceType can only be a reference binding. It cannot be
+ // LongBinding or DoubleBinding
+ }
+ }
+ SyntheticArgumentBinding syntheticArguments[];
+ if ((syntheticArguments =
+ methodBinding.declaringClass.syntheticOuterLocalVariables())
+ != null) {
+ for (int i = 0, max = syntheticArguments.length; i < max; i++) {
+ TypeBinding argType;
+ if (((argType = syntheticArguments[i].type) == LongBinding)
+ || (argType == DoubleBinding)) {
+ maxLocals += 2;
+ } else {
+ maxLocals++;
+ }
+ }
+ }
+ }
+ TypeBinding[] arguments;
+ if ((arguments = methodBinding.parameters) != null) {
+ for (int i = 0, max = arguments.length; i < max; i++) {
+ TypeBinding argType;
+ if (((argType = arguments[i]) == LongBinding) || (argType == DoubleBinding)) {
+ maxLocals += 2;
+ } else {
+ maxLocals++;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * This methods searches for an existing entry inside the pcToSourceMap table with a pc equals to @pc.
+ * If there is an existing entry it returns -1 (no insertion required).
+ * Otherwise it returns the index where the entry for the pc has to be inserted.
+ * This is based on the fact that the pcToSourceMap table is sorted according to the pc.
+ *
+ * @param int pc
+ * @return int
+ */
+ public static int insertionIndex(int[] pcToSourceMap, int length, int pc) {
+ int g = 0;
+ int d = length - 2;
+ int m = 0;
+ while (g <= d) {
+ m = (g + d) / 2;
+ // we search only on even indexes
+ if ((m % 2) != 0)
+ m--;
+ int currentPC = pcToSourceMap[m];
+ if (pc < currentPC) {
+ d = m - 2;
+ } else
+ if (pc > currentPC) {
+ g = m + 2;
+ } else {
+ return -1;
+ }
+ }
+ if (pc < pcToSourceMap[m])
+ return m;
+ return m + 2;
+ }
+
+ /**
+ * We didn't call it instanceof because there is a conflit with the
+ * instanceof keyword
+ */
+ final public void instance_of(TypeBinding typeBinding) {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_instanceof;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_instanceof);
+ }
+ writeUnsignedShort(constantPool.literalIndex(typeBinding));
+ }
+
+ public void invokeClassForName() {
+ // invokestatic: java.lang.Class.forName(Ljava.lang.String;)Ljava.lang.Class;
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokestatic;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokestatic);
+ }
+ writeUnsignedShort(constantPool.literalIndexForJavaLangClassForName());
+ }
+
+ public void invokeConstructorGetConstructor() {
+ // invokevirtual: java.lang.Class.getConstructor(java.lang.Class[])Ljava.lang.reflect.Constructor;
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokevirtual;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokevirtual);
+ }
+ writeUnsignedShort(constantPool.literalIndexForJavaLangClassGetConstructor());
+ }
+
+ final public void invokeinterface(MethodBinding methodBinding) {
+ // initialized to 1 to take into account this immediately
+ countLabels = 0;
+ int argCount = 1;
+ int id;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokeinterface;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokeinterface);
+ }
+ writeUnsignedShort(constantPool.literalIndex(methodBinding));
+ for (int i = methodBinding.parameters.length - 1; i >= 0; i--)
+ if (((id = methodBinding.parameters[i].id) == T_double) || (id == T_long))
+ argCount += 2;
+ else
+ argCount += 1;
+ writeUnsignedByte(argCount);
+ // Generate a 0 into the byte array. Like the array is already fill with 0, we just need to increment
+ // the number of bytes.
+ position++;
+ classFileOffset++;
+ if (((id = methodBinding.returnType.id) == T_double) || (id == T_long))
+ stackDepth += (2 - argCount);
+ else
+ if (id == T_void)
+ stackDepth -= argCount;
+ else
+ stackDepth += (1 - argCount);
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ }
+
+ public void invokeJavaLangErrorConstructor() {
+ // invokespecial: java.lang.Error<init>(Ljava.lang.String;)V
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokespecial;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokespecial);
+ }
+ stackDepth -= 2;
+ writeUnsignedShort(constantPool.literalIndexForJavaLangErrorConstructor());
+ }
+
+ public void invokeNoClassDefFoundErrorStringConstructor() {
+ // invokespecial: java.lang.NoClassDefFoundError.<init>(Ljava.lang.String;)V
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokespecial;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokespecial);
+ }
+ writeUnsignedShort(
+ constantPool.literalIndexForJavaLangNoClassDefFoundErrorStringConstructor());
+ stackDepth -= 2;
+ }
+
+ public void invokeObjectNewInstance() {
+ // invokevirtual: java.lang.reflect.Constructor.newInstance(java.lang.Object[])Ljava.lang.Object;
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokevirtual;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokevirtual);
+ }
+ writeUnsignedShort(
+ constantPool.literalIndexForJavaLangReflectConstructorNewInstance());
+ }
+
+ final public void invokespecial(MethodBinding methodBinding) {
+ // initialized to 1 to take into account this immediately
+ countLabels = 0;
+ int argCount = 1;
+ int id;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokespecial;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokespecial);
+ }
+ writeUnsignedShort(constantPool.literalIndex(methodBinding));
+ if (methodBinding.isConstructor()
+ && methodBinding.declaringClass.isNestedType()) {
+ // enclosing instances
+ TypeBinding[] syntheticArgumentTypes =
+ methodBinding.declaringClass.syntheticEnclosingInstanceTypes();
+ if (syntheticArgumentTypes != null) {
+ for (int i = 0, max = syntheticArgumentTypes.length; i < max; i++) {
+ if (((id = syntheticArgumentTypes[i].id) == T_double) || (id == T_long)) {
+ argCount += 2;
+ } else {
+ argCount++;
+ }
+ }
+ }
+ // outer local variables
+ SyntheticArgumentBinding[] syntheticArguments =
+ methodBinding.declaringClass.syntheticOuterLocalVariables();
+ if (syntheticArguments != null) {
+ for (int i = 0, max = syntheticArguments.length; i < max; i++) {
+ if (((id = syntheticArguments[i].type.id) == T_double) || (id == T_long)) {
+ argCount += 2;
+ } else {
+ argCount++;
+ }
+ }
+ }
+ }
+ for (int i = methodBinding.parameters.length - 1; i >= 0; i--)
+ if (((id = methodBinding.parameters[i].id) == T_double) || (id == T_long))
+ argCount += 2;
+ else
+ argCount++;
+ if (((id = methodBinding.returnType.id) == T_double) || (id == T_long))
+ stackDepth += (2 - argCount);
+ else
+ if (id == T_void)
+ stackDepth -= argCount;
+ else
+ stackDepth += (1 - argCount);
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ }
+
+ final public void invokestatic(MethodBinding methodBinding) {
+ // initialized to 0 to take into account that there is no this for
+ // a static method
+ countLabels = 0;
+ int argCount = 0;
+ int id;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokestatic;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokestatic);
+ }
+ writeUnsignedShort(constantPool.literalIndex(methodBinding));
+ for (int i = methodBinding.parameters.length - 1; i >= 0; i--)
+ if (((id = methodBinding.parameters[i].id) == T_double) || (id == T_long))
+ argCount += 2;
+ else
+ argCount += 1;
+ if (((id = methodBinding.returnType.id) == T_double) || (id == T_long))
+ stackDepth += (2 - argCount);
+ else
+ if (id == T_void)
+ stackDepth -= argCount;
+ else
+ stackDepth += (1 - argCount);
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ }
+
+ /**
+ * The equivalent code performs a string conversion of the TOS
+ * @param typeID <CODE>int</CODE>
+ */
+ public void invokeStringBufferAppendForType(int typeID) {
+ countLabels = 0;
+ int usedTypeID;
+ if (typeID == T_null)
+ usedTypeID = T_String;
+ else
+ usedTypeID = typeID;
+ // invokevirtual
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokevirtual;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokevirtual);
+ }
+ writeUnsignedShort(
+ constantPool.literalIndexForJavaLangStringBufferAppend(typeID));
+ if ((usedTypeID == T_long) || (usedTypeID == T_double))
+ stackDepth -= 2;
+ else
+ stackDepth--;
+ }
+
+ public void invokeStringBufferDefaultConstructor() {
+ // invokespecial: java.lang.StringBuffer.<init>()V
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokespecial;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokespecial);
+ }
+ writeUnsignedShort(
+ constantPool.literalIndexForJavaLangStringBufferDefaultConstructor());
+ stackDepth--;
+ }
+
+ public void invokeStringBufferStringConstructor() {
+ // invokespecial: java.lang.StringBuffer.<init>(Ljava.lang.String;)V
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokespecial;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokespecial);
+ }
+ writeUnsignedShort(
+ constantPool.literalIndexForJavaLangStringBufferConstructor());
+ stackDepth -= 2;
+ }
+
+ public void invokeStringBufferToString() {
+ // invokevirtual: StringBuffer.toString()Ljava.lang.String;
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokevirtual;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokevirtual);
+ }
+ writeUnsignedShort(constantPool.literalIndexForJavaLangStringBufferToString());
+ }
+
+ public void invokeStringIntern() {
+ // invokevirtual: java.lang.String.intern()
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokevirtual;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokevirtual);
+ }
+ writeUnsignedShort(constantPool.literalIndexForJavaLangStringIntern());
+ }
+
+ public void invokeStringValueOf(int typeID) {
+ // invokestatic: java.lang.String.valueOf(argumentType)
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokestatic;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokestatic);
+ }
+ writeUnsignedShort(constantPool.literalIndexForJavaLangStringValueOf(typeID));
+ }
+
+ public void invokeSystemExit() {
+ // invokestatic: java.lang.System.exit(I)
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokestatic;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokestatic);
+ }
+ writeUnsignedShort(constantPool.literalIndexForJavaLangSystemExitInt());
+ stackDepth--; // int argument
+ }
+
+ public void invokeThrowableGetMessage() {
+ // invokevirtual: java.lang.Throwable.getMessage()Ljava.lang.String;
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokevirtual;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokevirtual);
+ }
+ writeUnsignedShort(constantPool.literalIndexForJavaLangThrowableGetMessage());
+ }
+
+ final public void invokevirtual(MethodBinding methodBinding) {
+ // initialized to 1 to take into account this immediately
+ countLabels = 0;
+ int argCount = 1;
+ int id;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokevirtual;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokevirtual);
+ }
+ writeUnsignedShort(constantPool.literalIndex(methodBinding));
+ for (int i = methodBinding.parameters.length - 1; i >= 0; i--)
+ if (((id = methodBinding.parameters[i].id) == T_double) || (id == T_long))
+ argCount += 2;
+ else
+ argCount++;
+ if (((id = methodBinding.returnType.id) == T_double) || (id == T_long))
+ stackDepth += (2 - argCount);
+ else
+ if (id == T_void)
+ stackDepth -= argCount;
+ else
+ stackDepth += (1 - argCount);
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ }
+
+ final public void ior() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ior;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ior);
+ }
+ }
+
+ final public void irem() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_irem;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_irem);
+ }
+ }
+
+ final public void ireturn() {
+ countLabels = 0;
+ stackDepth--;
+ // the stackDepth should be equal to 0
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ireturn;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ireturn);
+ }
+ }
+
+ public boolean isDefinitelyAssigned(
+ Scope scope,
+ int initStateIndex,
+ LocalVariableBinding local) {
+ // Dependant of UnconditionalFlowInfo.isDefinitelyAssigned(..)
+ if (initStateIndex == -1)
+ return false;
+ if (local.isArgument) {
+ return true;
+ }
+ int position = local.id + maxFieldCount;
+ MethodScope methodScope = scope.methodScope();
+ // id is zero-based
+ if (position < UnconditionalFlowInfo.BitCacheSize) {
+ return (methodScope.definiteInits[initStateIndex] & (1L << position)) != 0;
+ // use bits
+ }
+ // use extra vector
+ long[] extraInits = methodScope.extraDefiniteInits[initStateIndex];
+ if (extraInits == null)
+ return false; // if vector not yet allocated, then not initialized
+ int vectorIndex;
+ if ((vectorIndex = (position / UnconditionalFlowInfo.BitCacheSize) - 1)
+ >= extraInits.length)
+ return false; // if not enough room in vector, then not initialized
+ return (
+ (extraInits[vectorIndex])
+ & (1L << (position % UnconditionalFlowInfo.BitCacheSize)))
+ != 0;
+ }
+
+ final public void ishl() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ishl;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ishl);
+ }
+ }
+
+ final public void ishr() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ishr;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ishr);
+ }
+ }
+
+ final public void istore(int iArg) {
+ countLabels = 0;
+ stackDepth--;
+ if (maxLocals <= iArg) {
+ maxLocals = iArg + 1;
+ }
+ if (iArg > 255) { // Widen
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_wide;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_wide);
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_istore;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_istore);
+ }
+ writeUnsignedShort(iArg);
+ } else {
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_istore;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_istore);
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) iArg;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) iArg);
+ }
+ }
+ }
+
+ final public void istore_0() {
+ countLabels = 0;
+ stackDepth--;
+ if (maxLocals == 0) {
+ maxLocals = 1;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_istore_0;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_istore_0);
+ }
+ }
+
+ final public void istore_1() {
+ countLabels = 0;
+ stackDepth--;
+ if (maxLocals <= 1) {
+ maxLocals = 2;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_istore_1;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_istore_1);
+ }
+ }
+
+ final public void istore_2() {
+ countLabels = 0;
+ stackDepth--;
+ if (maxLocals <= 2) {
+ maxLocals = 3;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_istore_2;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_istore_2);
+ }
+ }
+
+ final public void istore_3() {
+ countLabels = 0;
+ stackDepth--;
+ if (maxLocals <= 3) {
+ maxLocals = 4;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_istore_3;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_istore_3);
+ }
+ }
+
+ final public void isub() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_isub;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_isub);
+ }
+ }
+
+ final public void iushr() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_iushr;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_iushr);
+ }
+ }
+
+ final public void ixor() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ixor;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ixor);
+ }
+ }
+
+ final public void jsr(Label lbl) {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_jsr;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_jsr);
+ }
+ lbl.branch();
+ }
+
+ final public void jsr_w(Label lbl) {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_jsr_w;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_jsr_w);
+ }
+ lbl.branchWide();
+ }
+
+ final public void l2d() {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_l2d;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_l2d);
+ }
+ }
+
+ final public void l2f() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_l2f;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_l2f);
+ }
+ }
+
+ final public void l2i() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_l2i;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_l2i);
+ }
+ }
+
+ final public void ladd() {
+ countLabels = 0;
+ stackDepth -= 2;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ladd;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ladd);
+ }
+ }
+
+ final public void laload() {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_laload;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_laload);
+ }
+ }
+
+ final public void land() {
+ countLabels = 0;
+ stackDepth -= 2;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_land;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_land);
+ }
+ }
+
+ final public void lastore() {
+ countLabels = 0;
+ stackDepth -= 4;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lastore;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lastore);
+ }
+ }
+
+ final public void lcmp() {
+ countLabels = 0;
+ stackDepth -= 3;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lcmp;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lcmp);
+ }
+ }
+
+ final public void lconst_0() {
+ countLabels = 0;
+ stackDepth += 2;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lconst_0;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lconst_0);
+ }
+ }
+
+ final public void lconst_1() {
+ countLabels = 0;
+ stackDepth += 2;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lconst_1;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lconst_1);
+ }
+ }
+
+ final public void ldc(float constant) {
+ countLabels = 0;
+ int index = constantPool.literalIndex(constant);
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ if (index > 255) {
+ // Generate a ldc_w
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ldc_w;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ldc_w);
+ }
+ writeUnsignedShort(index);
+ } else {
+ // Generate a ldc
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ldc;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ldc);
+ }
+ writeUnsignedByte(index);
+ }
+ }
+
+ final public void ldc(int constant) {
+ countLabels = 0;
+ int index = constantPool.literalIndex(constant);
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ if (index > 255) {
+ // Generate a ldc_w
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ldc_w;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ldc_w);
+ }
+ writeUnsignedShort(index);
+ } else {
+ // Generate a ldc
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ldc;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ldc);
+ }
+ writeUnsignedByte(index);
+ }
+ }
+
+ final public void ldc(String constant) {
+ countLabels = 0;
+ int currentConstantPoolIndex = constantPool.currentIndex;
+ int currentConstantPoolOffset = constantPool.currentOffset;
+ int currentCodeStreamPosition = position;
+ int index = constantPool.literalIndexForLdc(constant.toCharArray());
+ if (index > 0) {
+ // the string already exists inside the constant pool
+ // we reuse the same index
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ if (index > 255) {
+ // Generate a ldc_w
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ldc_w;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ldc_w);
+ }
+ writeUnsignedShort(index);
+ } else {
+ // Generate a ldc
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ldc;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ldc);
+ }
+ writeUnsignedByte(index);
+ }
+ } else {
+ // the string is too big to be utf8-encoded in one pass.
+ // we have to split it into different pieces.
+ // first we clean all side-effects due to the code above
+ // this case is very rare, so we can afford to lose time to handle it
+ char[] constantChars = constant.toCharArray();
+ position = currentCodeStreamPosition;
+ constantPool.currentIndex = currentConstantPoolIndex;
+ constantPool.currentOffset = currentConstantPoolOffset;
+ constantPool.stringCache.remove(constantChars);
+ constantPool.UTF8Cache.remove(constantChars);
+ int i = 0;
+ int length = 0;
+ int constantLength = constant.length();
+ byte[] utf8encoding = new byte[Math.min(constantLength + 100, 65535)];
+ int utf8encodingLength = 0;
+ while ((length < 65532) && (i < constantLength)) {
+ char current = constantChars[i];
+ // we resize the byte array immediately if necessary
+ if (length + 3 > (utf8encodingLength = utf8encoding.length)) {
+ System.arraycopy(
+ utf8encoding,
+ 0,
+ (utf8encoding = new byte[Math.min(utf8encodingLength + 100, 65535)]),
+ 0,
+ length);
+ }
+ if ((current >= 0x0001) && (current <= 0x007F)) {
+ // we only need one byte: ASCII table
+ utf8encoding[length++] = (byte) current;
+ } else {
+ if (current > 0x07FF) {
+ // we need 3 bytes
+ utf8encoding[length++] = (byte) (0xE0 | ((current >> 12) & 0x0F));
+ // 0xE0 = 1110 0000
+ utf8encoding[length++] = (byte) (0x80 | ((current >> 6) & 0x3F));
+ // 0x80 = 1000 0000
+ utf8encoding[length++] = (byte) (0x80 | (current & 0x3F)); // 0x80 = 1000 0000
+ } else {
+ // we can be 0 or between 0x0080 and 0x07FF
+ // In that case we only need 2 bytes
+ utf8encoding[length++] = (byte) (0xC0 | ((current >> 6) & 0x1F));
+ // 0xC0 = 1100 0000
+ utf8encoding[length++] = (byte) (0x80 | (current & 0x3F)); // 0x80 = 1000 0000
+ }
+ }
+ i++;
+ }
+ // check if all the string is encoded (PR 1PR2DWJ)
+ // the string is too big to be encoded in one pass
+ newStringBuffer();
+ dup();
+ // write the first part
+ char[] subChars = new char[i];
+ System.arraycopy(constantChars, 0, subChars, 0, i);
+ System.arraycopy(utf8encoding, 0, (utf8encoding = new byte[length]), 0, length);
+ index = constantPool.literalIndex(subChars, utf8encoding);
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ if (index > 255) {
+ // Generate a ldc_w
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ldc_w;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ldc_w);
+ }
+ writeUnsignedShort(index);
+ } else {
+ // Generate a ldc
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ldc;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ldc);
+ }
+ writeUnsignedByte(index);
+ }
+ // write the remaining part
+ invokeStringBufferStringConstructor();
+ while (i < constantLength) {
+ length = 0;
+ utf8encoding = new byte[Math.min(constantLength - i + 100, 65535)];
+ int startIndex = i;
+ while ((length < 65532) && (i < constantLength)) {
+ char current = constantChars[i];
+ // we resize the byte array immediately if necessary
+ if (constantLength + 2 > (utf8encodingLength = utf8encoding.length)) {
+ System.arraycopy(
+ utf8encoding,
+ 0,
+ (utf8encoding = new byte[Math.min(utf8encodingLength + 100, 65535)]),
+ 0,
+ length);
+ }
+ if ((current >= 0x0001) && (current <= 0x007F)) {
+ // we only need one byte: ASCII table
+ utf8encoding[length++] = (byte) current;
+ } else {
+ if (current > 0x07FF) {
+ // we need 3 bytes
+ utf8encoding[length++] = (byte) (0xE0 | ((current >> 12) & 0x0F));
+ // 0xE0 = 1110 0000
+ utf8encoding[length++] = (byte) (0x80 | ((current >> 6) & 0x3F));
+ // 0x80 = 1000 0000
+ utf8encoding[length++] = (byte) (0x80 | (current & 0x3F)); // 0x80 = 1000 0000
+ } else {
+ // we can be 0 or between 0x0080 and 0x07FF
+ // In that case we only need 2 bytes
+ utf8encoding[length++] = (byte) (0xC0 | ((current >> 6) & 0x1F));
+ // 0xC0 = 1100 0000
+ utf8encoding[length++] = (byte) (0x80 | (current & 0x3F)); // 0x80 = 1000 0000
+ }
+ }
+ i++;
+ }
+ // the next part is done
+ subChars = new char[i - startIndex];
+ System.arraycopy(constantChars, startIndex, subChars, 0, i - startIndex);
+ System.arraycopy(utf8encoding, 0, (utf8encoding = new byte[length]), 0, length);
+ index = constantPool.literalIndex(subChars, utf8encoding);
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ if (index > 255) {
+ // Generate a ldc_w
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ldc_w;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ldc_w);
+ }
+ writeUnsignedShort(index);
+ } else {
+ // Generate a ldc
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ldc;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ldc);
+ }
+ writeUnsignedByte(index);
+ }
+ // now on the stack it should be a StringBuffer and a string.
+ invokeStringBufferAppendForType(T_String);
+ }
+ invokeStringBufferToString();
+ invokeStringIntern();
+ }
+ }
+
+ final public void ldc2_w(double constant) {
+ countLabels = 0;
+ int index = constantPool.literalIndex(constant);
+ stackDepth += 2;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ // Generate a ldc2_w
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ldc2_w;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ldc2_w);
+ }
+ writeUnsignedShort(index);
+ }
+
+ final public void ldc2_w(long constant) {
+ countLabels = 0;
+ int index = constantPool.literalIndex(constant);
+ stackDepth += 2;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ // Generate a ldc2_w
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ldc2_w;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ldc2_w);
+ }
+ writeUnsignedShort(index);
+ }
+
+ final public void ldiv() {
+ countLabels = 0;
+ stackDepth -= 2;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ldiv;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ldiv);
+ }
+ }
+
+ final public void lload(int iArg) {
+ countLabels = 0;
+ stackDepth += 2;
+ if (maxLocals <= iArg + 1) {
+ maxLocals = iArg + 2;
+ }
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ if (iArg > 255) { // Widen
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_wide;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_wide);
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lload;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lload);
+ }
+ writeUnsignedShort(iArg);
+ } else {
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lload;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lload);
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) iArg;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) iArg);
+ }
+ }
+ }
+
+ final public void lload_0() {
+ countLabels = 0;
+ stackDepth += 2;
+ if (maxLocals < 2) {
+ maxLocals = 2;
+ }
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lload_0;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lload_0);
+ }
+ }
+
+ final public void lload_1() {
+ countLabels = 0;
+ stackDepth += 2;
+ if (maxLocals < 3) {
+ maxLocals = 3;
+ }
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lload_1;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lload_1);
+ }
+ }
+
+ final public void lload_2() {
+ countLabels = 0;
+ stackDepth += 2;
+ if (maxLocals < 4) {
+ maxLocals = 4;
+ }
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lload_2;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lload_2);
+ }
+ }
+
+ final public void lload_3() {
+ countLabels = 0;
+ stackDepth += 2;
+ if (maxLocals < 5) {
+ maxLocals = 5;
+ }
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lload_3;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lload_3);
+ }
+ }
+
+ final public void lmul() {
+ countLabels = 0;
+ stackDepth -= 2;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lmul;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lmul);
+ }
+ }
+
+ final public void lneg() {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lneg;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lneg);
+ }
+ }
+
+ public final void load(LocalVariableBinding localBinding) {
+ countLabels = 0;
+ TypeBinding typeBinding = localBinding.type;
+ int resolvedPosition = localBinding.resolvedPosition;
+ // Using dedicated int bytecode
+ if (typeBinding == IntBinding) {
+ switch (resolvedPosition) {
+ case 0 :
+ this.iload_0();
+ break;
+ case 1 :
+ this.iload_1();
+ break;
+ case 2 :
+ this.iload_2();
+ break;
+ case 3 :
+ this.iload_3();
+ break;
+ default :
+ this.iload(resolvedPosition);
+ }
+ return;
+ }
+ // Using dedicated float bytecode
+ if (typeBinding == FloatBinding) {
+ switch (resolvedPosition) {
+ case 0 :
+ this.fload_0();
+ break;
+ case 1 :
+ this.fload_1();
+ break;
+ case 2 :
+ this.fload_2();
+ break;
+ case 3 :
+ this.fload_3();
+ break;
+ default :
+ this.fload(resolvedPosition);
+ }
+ return;
+ }
+ // Using dedicated long bytecode
+ if (typeBinding == LongBinding) {
+ switch (resolvedPosition) {
+ case 0 :
+ this.lload_0();
+ break;
+ case 1 :
+ this.lload_1();
+ break;
+ case 2 :
+ this.lload_2();
+ break;
+ case 3 :
+ this.lload_3();
+ break;
+ default :
+ this.lload(resolvedPosition);
+ }
+ return;
+ }
+ // Using dedicated double bytecode
+ if (typeBinding == DoubleBinding) {
+ switch (resolvedPosition) {
+ case 0 :
+ this.dload_0();
+ break;
+ case 1 :
+ this.dload_1();
+ break;
+ case 2 :
+ this.dload_2();
+ break;
+ case 3 :
+ this.dload_3();
+ break;
+ default :
+ this.dload(resolvedPosition);
+ }
+ return;
+ }
+ // boolean, byte, char and short are handled as int
+ if ((typeBinding == ByteBinding)
+ || (typeBinding == CharBinding)
+ || (typeBinding == BooleanBinding)
+ || (typeBinding == ShortBinding)) {
+ switch (resolvedPosition) {
+ case 0 :
+ this.iload_0();
+ break;
+ case 1 :
+ this.iload_1();
+ break;
+ case 2 :
+ this.iload_2();
+ break;
+ case 3 :
+ this.iload_3();
+ break;
+ default :
+ this.iload(resolvedPosition);
+ }
+ return;
+ }
+
+ // Reference object
+ switch (resolvedPosition) {
+ case 0 :
+ this.aload_0();
+ break;
+ case 1 :
+ this.aload_1();
+ break;
+ case 2 :
+ this.aload_2();
+ break;
+ case 3 :
+ this.aload_3();
+ break;
+ default :
+ this.aload(resolvedPosition);
+ }
+ }
+
+ public final void load(TypeBinding typeBinding, int resolvedPosition) {
+ countLabels = 0;
+ // Using dedicated int bytecode
+ if (typeBinding == IntBinding) {
+ switch (resolvedPosition) {
+ case 0 :
+ this.iload_0();
+ break;
+ case 1 :
+ this.iload_1();
+ break;
+ case 2 :
+ this.iload_2();
+ break;
+ case 3 :
+ this.iload_3();
+ break;
+ default :
+ this.iload(resolvedPosition);
+ }
+ return;
+ }
+ // Using dedicated float bytecode
+ if (typeBinding == FloatBinding) {
+ switch (resolvedPosition) {
+ case 0 :
+ this.fload_0();
+ break;
+ case 1 :
+ this.fload_1();
+ break;
+ case 2 :
+ this.fload_2();
+ break;
+ case 3 :
+ this.fload_3();
+ break;
+ default :
+ this.fload(resolvedPosition);
+ }
+ return;
+ }
+ // Using dedicated long bytecode
+ if (typeBinding == LongBinding) {
+ switch (resolvedPosition) {
+ case 0 :
+ this.lload_0();
+ break;
+ case 1 :
+ this.lload_1();
+ break;
+ case 2 :
+ this.lload_2();
+ break;
+ case 3 :
+ this.lload_3();
+ break;
+ default :
+ this.lload(resolvedPosition);
+ }
+ return;
+ }
+ // Using dedicated double bytecode
+ if (typeBinding == DoubleBinding) {
+ switch (resolvedPosition) {
+ case 0 :
+ this.dload_0();
+ break;
+ case 1 :
+ this.dload_1();
+ break;
+ case 2 :
+ this.dload_2();
+ break;
+ case 3 :
+ this.dload_3();
+ break;
+ default :
+ this.dload(resolvedPosition);
+ }
+ return;
+ }
+ // boolean, byte, char and short are handled as int
+ if ((typeBinding == ByteBinding)
+ || (typeBinding == CharBinding)
+ || (typeBinding == BooleanBinding)
+ || (typeBinding == ShortBinding)) {
+ switch (resolvedPosition) {
+ case 0 :
+ this.iload_0();
+ break;
+ case 1 :
+ this.iload_1();
+ break;
+ case 2 :
+ this.iload_2();
+ break;
+ case 3 :
+ this.iload_3();
+ break;
+ default :
+ this.iload(resolvedPosition);
+ }
+ return;
+ }
+
+ // Reference object
+ switch (resolvedPosition) {
+ case 0 :
+ this.aload_0();
+ break;
+ case 1 :
+ this.aload_1();
+ break;
+ case 2 :
+ this.aload_2();
+ break;
+ case 3 :
+ this.aload_3();
+ break;
+ default :
+ this.aload(resolvedPosition);
+ }
+ }
+
+ public final void loadInt(int resolvedPosition) {
+ // Using dedicated int bytecode
+ switch (resolvedPosition) {
+ case 0 :
+ this.iload_0();
+ break;
+ case 1 :
+ this.iload_1();
+ break;
+ case 2 :
+ this.iload_2();
+ break;
+ case 3 :
+ this.iload_3();
+ break;
+ default :
+ this.iload(resolvedPosition);
+ }
+ }
+
+ public final void loadObject(int resolvedPosition) {
+ switch (resolvedPosition) {
+ case 0 :
+ this.aload_0();
+ break;
+ case 1 :
+ this.aload_1();
+ break;
+ case 2 :
+ this.aload_2();
+ break;
+ case 3 :
+ this.aload_3();
+ break;
+ default :
+ this.aload(resolvedPosition);
+ }
+ }
+
+ final public void lookupswitch(
+ CaseLabel defaultLabel,
+ int[] keys,
+ int[] sortedIndexes,
+ CaseLabel[] casesLabel) {
+ countLabels = 0;
+ stackDepth--;
+ int length = keys.length;
+ int pos = position;
+ defaultLabel.placeInstruction();
+ for (int i = 0; i < length; i++) {
+ casesLabel[i].placeInstruction();
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lookupswitch;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lookupswitch);
+ }
+ for (int i = (3 - (pos % 4)); i > 0; i--) {
+ position++; // Padding
+ classFileOffset++;
+ }
+ defaultLabel.branch();
+ writeSignedWord(length);
+ for (int i = 0; i < length; i++) {
+ writeSignedWord(keys[sortedIndexes[i]]);
+ casesLabel[sortedIndexes[i]].branch();
+ }
+ }
+
+ final public void lor() {
+ countLabels = 0;
+ stackDepth -= 2;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lor;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lor);
+ }
+ }
+
+ final public void lrem() {
+ countLabels = 0;
+ stackDepth -= 2;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lrem;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lrem);
+ }
+ }
+
+ final public void lreturn() {
+ countLabels = 0;
+ stackDepth -= 2;
+ // the stackDepth should be equal to 0
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lreturn;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lreturn);
+ }
+ }
+
+ final public void lshl() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lshl;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lshl);
+ }
+ }
+
+ final public void lshr() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lshr;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lshr);
+ }
+ }
+
+ final public void lstore(int iArg) {
+ countLabels = 0;
+ stackDepth -= 2;
+ if (maxLocals <= iArg + 1) {
+ maxLocals = iArg + 2;
+ }
+ if (iArg > 255) { // Widen
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_wide;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_wide);
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lstore;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lstore);
+ }
+ writeUnsignedShort(iArg);
+ } else {
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lstore;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lstore);
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) iArg;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) iArg);
+ }
+ }
+ }
+
+ final public void lstore_0() {
+ countLabels = 0;
+ stackDepth -= 2;
+ if (maxLocals < 2) {
+ maxLocals = 2;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lstore_0;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lstore_0);
+ }
+ }
+
+ final public void lstore_1() {
+ countLabels = 0;
+ stackDepth -= 2;
+ if (maxLocals < 3) {
+ maxLocals = 3;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lstore_1;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lstore_1);
+ }
+ }
+
+ final public void lstore_2() {
+ countLabels = 0;
+ stackDepth -= 2;
+ if (maxLocals < 4) {
+ maxLocals = 4;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lstore_2;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lstore_2);
+ }
+ }
+
+ final public void lstore_3() {
+ countLabels = 0;
+ stackDepth -= 2;
+ if (maxLocals < 5) {
+ maxLocals = 5;
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lstore_3;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lstore_3);
+ }
+ }
+
+ final public void lsub() {
+ countLabels = 0;
+ stackDepth -= 2;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lsub;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lsub);
+ }
+ }
+
+ final public void lushr() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lushr;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lushr);
+ }
+ }
+
+ final public void lxor() {
+ countLabels = 0;
+ stackDepth -= 2;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_lxor;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_lxor);
+ }
+ }
+
+ final public void monitorenter() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_monitorenter;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_monitorenter);
+ }
+ }
+
+ final public void monitorexit() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_monitorexit;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_monitorexit);
+ }
+ }
+
+ final public void multianewarray(TypeBinding typeBinding, int dimensions) {
+ countLabels = 0;
+ stackDepth += (1 - dimensions);
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_multianewarray;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_multianewarray);
+ }
+ writeUnsignedShort(constantPool.literalIndex(typeBinding));
+ writeUnsignedByte(dimensions);
+ }
+
+ public static void needImplementation() {
+ }
+
+ /**
+ * We didn't call it new, because there is a conflit with the new keyword
+ */
+ final public void new_(TypeBinding typeBinding) {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_new;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_new);
+ }
+ writeUnsignedShort(constantPool.literalIndex(typeBinding));
+ }
+
+ final public void newarray(int array_Type) {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_newarray;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_newarray);
+ }
+ writeUnsignedByte(array_Type);
+ }
+
+ public void newArray(Scope scope, ArrayBinding arrayBinding) {
+ TypeBinding component = arrayBinding.elementsType(scope);
+ switch (component.id) {
+ case T_int :
+ this.newarray(10);
+ break;
+ case T_byte :
+ this.newarray(8);
+ break;
+ case T_boolean :
+ this.newarray(4);
+ break;
+ case T_short :
+ this.newarray(9);
+ break;
+ case T_char :
+ this.newarray(5);
+ break;
+ case T_long :
+ this.newarray(11);
+ break;
+ case T_float :
+ this.newarray(6);
+ break;
+ case T_double :
+ this.newarray(7);
+ break;
+ default :
+ this.anewarray(component);
+ }
+ }
+
+ public void newJavaLangError() {
+ // new: java.lang.Error
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_new;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_new);
+ }
+ writeUnsignedShort(constantPool.literalIndexForJavaLangError());
+ }
+
+ public void newNoClassDefFoundError() { // new: java.lang.NoClassDefFoundError
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_new;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_new);
+ }
+ writeUnsignedShort(constantPool.literalIndexForJavaLangNoClassDefFoundError());
+ }
+
+ public void newStringBuffer() { // new: java.lang.StringBuffer
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_new;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_new);
+ }
+ writeUnsignedShort(constantPool.literalIndexForJavaLangStringBuffer());
+ }
+
+ public void newWrapperFor(int typeID) {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_new;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_new);
+ }
+ switch (typeID) {
+ case T_int : // new: java.lang.Integer
+ writeUnsignedShort(constantPool.literalIndexForJavaLangInteger());
+ break;
+ case T_boolean : // new: java.lang.Boolean
+ writeUnsignedShort(constantPool.literalIndexForJavaLangBoolean());
+ break;
+ case T_byte : // new: java.lang.Byte
+ writeUnsignedShort(constantPool.literalIndexForJavaLangByte());
+ break;
+ case T_char : // new: java.lang.Character
+ writeUnsignedShort(constantPool.literalIndexForJavaLangCharacter());
+ break;
+ case T_float : // new: java.lang.Float
+ writeUnsignedShort(constantPool.literalIndexForJavaLangFloat());
+ break;
+ case T_double : // new: java.lang.Double
+ writeUnsignedShort(constantPool.literalIndexForJavaLangDouble());
+ break;
+ case T_short : // new: java.lang.Short
+ writeUnsignedShort(constantPool.literalIndexForJavaLangShort());
+ break;
+ case T_long : // new: java.lang.Long
+ writeUnsignedShort(constantPool.literalIndexForJavaLangLong());
+ break;
+ case T_void : // new: java.lang.Void
+ writeUnsignedShort(constantPool.literalIndexForJavaLangVoid());
+ }
+ }
+
+ final public void nop() {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_nop;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_nop);
+ }
+ }
+
+ final public void pop() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_pop;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_pop);
+ }
+ }
+
+ final public void pop2() {
+ countLabels = 0;
+ stackDepth -= 2;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_pop2;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_pop2);
+ }
+ }
+
+ final public void putfield(FieldBinding fieldBinding) {
+ countLabels = 0;
+ int id;
+ if (((id = fieldBinding.type.id) == T_double) || (id == T_long))
+ stackDepth -= 3;
+ else
+ stackDepth -= 2;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_putfield;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_putfield);
+ }
+ writeUnsignedShort(constantPool.literalIndex(fieldBinding));
+ }
+
+ final public void putstatic(FieldBinding fieldBinding) {
+ countLabels = 0;
+ int id;
+ if (((id = fieldBinding.type.id) == T_double) || (id == T_long))
+ stackDepth -= 2;
+ else
+ stackDepth -= 1;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_putstatic;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_putstatic);
+ }
+ writeUnsignedShort(constantPool.literalIndex(fieldBinding));
+ }
+
+ public void record(LocalVariableBinding local) {
+ if (!generateLocalVariableTableAttributes)
+ return;
+ if (allLocalsCounter == locals.length) {
+ // resize the collection
+ System.arraycopy(
+ locals,
+ 0,
+ (locals = new LocalVariableBinding[allLocalsCounter + LOCALS_INCREMENT]),
+ 0,
+ allLocalsCounter);
+ }
+ locals[allLocalsCounter++] = local;
+ local.initializationPCs = new int[4];
+ }
+
+ public void recordPositionsFrom(int startPC, AstNode node) {
+
+ /* Record positions in the table, only if nothing has
+ * already been recorded. Since we output them on the way
+ * up (children first for more specific info)
+ * The pcToSourceMap table is always sorted.
+ */
+
+ /** OLD CODE
+ int startPos, endPos;
+ int[] lastEntry;
+ if (!generateLineNumberAttributes && !generateLocalVariableTableAttributes)
+ return;
+ if ((startPos = node.sourceStart()) == 0)
+ return;
+ if ((endPos = node.sourceEnd()) == 0)
+ return;
+
+ // Widening an existing entry that already has the same source positions
+ if ((pcToSourceMapSize > 0) && (pcToSourceMap[pcToSourceMapSize - 1][2] == startPos) && (pcToSourceMap[pcToSourceMapSize - 1][3] == endPos)) {
+ if (pcToSourceMap[pcToSourceMapSize - 1][0] > startPC)
+ pcToSourceMap[pcToSourceMapSize - 1][0] = startPC;
+ pcToSourceMap[pcToSourceMapSize - 1][1] = position;
+ return;
+ }
+ if (pcToSourceMapSize == pcToSourceMap.length) {
+ // resize the array pcToSourceMap
+ System.arraycopy(pcToSourceMap, 0, (pcToSourceMap = new int[pcToSourceMapSize * 2][]), 0, pcToSourceMapSize);
+ }
+ pcToSourceMap[pcToSourceMapSize++] = new int[] {startPC, position, startPos, endPos};
+
+ */
+ int startPos;
+ if (!generateLineNumberAttributes)
+ return;
+ if ((startPos = node.sourceStart()) == 0)
+ return;
+
+ // no code generated for this node. e.g. field without any initialization
+ if (position == startPC)
+ return;
+
+ // Widening an existing entry that already has the same source positions
+ if (pcToSourceMapSize + 4 > pcToSourceMap.length) {
+ // resize the array pcToSourceMap
+ System.arraycopy(
+ pcToSourceMap,
+ 0,
+ (pcToSourceMap = new int[pcToSourceMapSize << 1]),
+ 0,
+ pcToSourceMapSize);
+ }
+ int newLine = ClassFile.searchLineNumber(lineSeparatorPositions, startPos);
+ // lastEntryPC represents the endPC of the lastEntry.
+ if (pcToSourceMapSize > 0) {
+ // in this case there is already an entry in the table
+ if (pcToSourceMap[pcToSourceMapSize - 1] != newLine) {
+ if (startPC < lastEntryPC) {
+ // we forgot to add an entry.
+ // search if an existing entry exists for startPC
+ int insertionIndex = insertionIndex(pcToSourceMap, pcToSourceMapSize, startPC);
+ if (insertionIndex != -1) {
+ // there is no existing entry starting with startPC.
+ int existingEntryIndex = indexOfSameLineEntrySincePC(startPC, newLine);
+ // index for PC
+ /* the existingEntryIndex corresponds to en entry with the same line and a PC >= startPC.
+ in this case it is relevant to widen this entry instead of creating a new one.
+ line1: this(a,
+ b,
+ c);
+ with this code we generate each argument. We generate a aload0 to invoke the constructor. There is no entry for this
+ aload0 bytecode. The first entry is the one for the argument a.
+ But we want the constructor call to start at the aload0 pc and not just at the pc of the first argument.
+ So we widen the existing entry (if there is one) or we create a new entry with the startPC.
+ */
+ if (existingEntryIndex != -1) {
+ // widen existing entry
+ pcToSourceMap[existingEntryIndex] = startPC;
+ } else {
+ // we have to add an entry that won't be sorted. So we sort the pcToSourceMap.
+ System.arraycopy(
+ pcToSourceMap,
+ insertionIndex,
+ pcToSourceMap,
+ insertionIndex + 2,
+ pcToSourceMapSize - insertionIndex);
+ pcToSourceMap[insertionIndex++] = startPC;
+ pcToSourceMap[insertionIndex] = newLine;
+ pcToSourceMapSize += 2;
+ }
+ }
+ if (position != lastEntryPC) { // no bytecode since last entry pc
+ pcToSourceMap[pcToSourceMapSize++] = lastEntryPC;
+ pcToSourceMap[pcToSourceMapSize++] = newLine;
+ }
+ } else {
+ // we can safely add the new entry. The endPC of the previous entry is not in conflit with the startPC of the new entry.
+ pcToSourceMap[pcToSourceMapSize++] = startPC;
+ pcToSourceMap[pcToSourceMapSize++] = newLine;
+ }
+ } else {
+ /* the last recorded entry is on the same line. But it could be relevant to widen this entry.
+ we want to extend this entry forward in case we generated some bytecode before the last entry that are not related to any statement
+ */
+ if (startPC < pcToSourceMap[pcToSourceMapSize - 2]) {
+ int insertionIndex = insertionIndex(pcToSourceMap, pcToSourceMapSize, startPC);
+ if (insertionIndex != -1) {
+ // widen the existing entry
+ // we have to figure out if we need to move the last entry at another location to keep a sorted table
+ if ((pcToSourceMapSize > 4)
+ && (pcToSourceMap[pcToSourceMapSize - 4] > startPC)) {
+ System.arraycopy(
+ pcToSourceMap,
+ insertionIndex,
+ pcToSourceMap,
+ insertionIndex + 2,
+ pcToSourceMapSize - 2 - insertionIndex);
+ pcToSourceMap[insertionIndex++] = startPC;
+ pcToSourceMap[insertionIndex] = newLine;
+ } else {
+ pcToSourceMap[pcToSourceMapSize - 2] = startPC;
+ }
+ }
+ }
+ }
+ lastEntryPC = position;
+ } else {
+ // record the first entry
+ pcToSourceMap[pcToSourceMapSize++] = startPC;
+ pcToSourceMap[pcToSourceMapSize++] = newLine;
+ lastEntryPC = position;
+ }
+ }
+
+ /**
+ * @param anExceptionLabel org.eclipse.jdt.internal.compiler.codegen.ExceptionLabel
+ */
+ public void registerExceptionHandler(ExceptionLabel anExceptionLabel) {
+ int length;
+ if (exceptionHandlersNumber >= (length = exceptionHandlers.length)) {
+ // resize the exception handlers table
+ System.arraycopy(
+ exceptionHandlers,
+ 0,
+ exceptionHandlers = new ExceptionLabel[length + LABELS_INCREMENT],
+ 0,
+ length);
+ }
+ // no need to resize. So just add the new exception label
+ exceptionHandlers[exceptionHandlersNumber++] = anExceptionLabel;
+ }
+
+ public final void removeNotDefinitelyAssignedVariables(
+ Scope scope,
+ int initStateIndex) {
+ // given some flow info, make sure we did not loose some variables initialization
+ // if this happens, then we must update their pc entries to reflect it in debug attributes
+ if (!generateLocalVariableTableAttributes)
+ return;
+ /* if (initStateIndex == lastInitStateIndexWhenRemovingInits)
+ return;
+
+ lastInitStateIndexWhenRemovingInits = initStateIndex;
+ if (lastInitStateIndexWhenAddingInits != initStateIndex){
+ lastInitStateIndexWhenAddingInits = -2;// reinitialize add index
+ // add(1)-remove(1)-add(1) -> ignore second add
+ // add(1)-remove(2)-add(1) -> perform second add
+ }*/
+ for (int i = 0; i < visibleLocalsCount; i++) {
+ LocalVariableBinding localBinding = visibleLocals[i];
+ if (localBinding != null) {
+ if (initStateIndex == -1
+ || !isDefinitelyAssigned(scope, initStateIndex, localBinding)) {
+ if (localBinding.initializationCount > 0) {
+ localBinding.recordInitializationEndPC(position);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @param methodDeclaration org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
+ * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile
+ */
+ public void reset(
+ AbstractMethodDeclaration methodDeclaration,
+ ClassFile classFile) {
+ init(classFile);
+ this.methodDeclaration = methodDeclaration;
+ preserveUnusedLocals =
+ methodDeclaration.scope.problemReporter().options.preserveAllLocalVariables;
+ initializeMaxLocals(methodDeclaration.binding);
+ }
+
+ /**
+ * @param methodDeclaration org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
+ * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile
+ */
+ public void resetForProblemClinit(ClassFile classFile) {
+ init(classFile);
+ maxLocals = 0;
+ }
+
+ protected final void resizeByteArray() {
+ int actualLength = bCodeStream.length;
+ int requiredSize = actualLength + growFactor;
+ if (classFileOffset > requiredSize) {
+ requiredSize = classFileOffset + growFactor;
+ }
+ System.arraycopy(
+ bCodeStream,
+ 0,
+ (bCodeStream = new byte[requiredSize]),
+ 0,
+ actualLength);
+ }
+
+ /**
+ * This method is used to resize the internal byte array in
+ * case of a ArrayOutOfBoundsException when adding the value b.
+ * Resize and add the new byte b inside the array.
+ * @param b byte
+ */
+ protected final void resizeByteArray(byte b) {
+ resizeByteArray();
+ bCodeStream[classFileOffset - 1] = b;
+ }
+
+ final public void ret(int index) {
+ countLabels = 0;
+ if (index > 255) { // Widen
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_wide;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_wide);
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ret;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ret);
+ }
+ writeUnsignedShort(index);
+ } else { // Don't Widen
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_ret;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_ret);
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) index;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) index);
+ }
+ }
+ }
+
+ final public void return_() {
+ countLabels = 0;
+ // the stackDepth should be equal to 0
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_return;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_return);
+ }
+ }
+
+ final public void saload() {
+ countLabels = 0;
+ stackDepth--;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_saload;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_saload);
+ }
+ }
+
+ final public void sastore() {
+ countLabels = 0;
+ stackDepth -= 3;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_sastore;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_sastore);
+ }
+ }
+
+ /**
+ * @param operatorConstant int
+ * @param type_ID int
+ */
+ public void sendOperator(int operatorConstant, int type_ID) {
+ switch (type_ID) {
+ case T_int :
+ case T_boolean :
+ case T_char :
+ case T_byte :
+ case T_short :
+ switch (operatorConstant) {
+ case PLUS :
+ this.iadd();
+ break;
+ case MINUS :
+ this.isub();
+ break;
+ case MULTIPLY :
+ this.imul();
+ break;
+ case DIVIDE :
+ this.idiv();
+ break;
+ case REMAINDER :
+ this.irem();
+ break;
+ case LEFT_SHIFT :
+ this.ishl();
+ break;
+ case RIGHT_SHIFT :
+ this.ishr();
+ break;
+ case UNSIGNED_RIGHT_SHIFT :
+ this.iushr();
+ break;
+ case AND :
+ this.iand();
+ break;
+ case OR :
+ this.ior();
+ break;
+ case XOR :
+ this.ixor();
+ break;
+ }
+ break;
+ case T_long :
+ switch (operatorConstant) {
+ case PLUS :
+ this.ladd();
+ break;
+ case MINUS :
+ this.lsub();
+ break;
+ case MULTIPLY :
+ this.lmul();
+ break;
+ case DIVIDE :
+ this.ldiv();
+ break;
+ case REMAINDER :
+ this.lrem();
+ break;
+ case LEFT_SHIFT :
+ this.lshl();
+ break;
+ case RIGHT_SHIFT :
+ this.lshr();
+ break;
+ case UNSIGNED_RIGHT_SHIFT :
+ this.lushr();
+ break;
+ case AND :
+ this.land();
+ break;
+ case OR :
+ this.lor();
+ break;
+ case XOR :
+ this.lxor();
+ break;
+ }
+ break;
+ case T_float :
+ switch (operatorConstant) {
+ case PLUS :
+ this.fadd();
+ break;
+ case MINUS :
+ this.fsub();
+ break;
+ case MULTIPLY :
+ this.fmul();
+ break;
+ case DIVIDE :
+ this.fdiv();
+ break;
+ case REMAINDER :
+ this.frem();
+ }
+ break;
+ case T_double :
+ switch (operatorConstant) {
+ case PLUS :
+ this.dadd();
+ break;
+ case MINUS :
+ this.dsub();
+ break;
+ case MULTIPLY :
+ this.dmul();
+ break;
+ case DIVIDE :
+ this.ddiv();
+ break;
+ case REMAINDER :
+ this.drem();
+ }
+ }
+ }
+
+ final public void sipush(int s) {
+ countLabels = 0;
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_sipush;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_sipush);
+ }
+ writeSignedShort(s);
+ }
+
+ public static final void sort(int[] tab, int lo0, int hi0, int[] result) {
+ int lo = lo0;
+ int hi = hi0;
+ int mid;
+ if (hi0 > lo0) {
+ /* Arbitrarily establishing partition element as the midpoint of
+ * the array.
+ */
+ mid = tab[(lo0 + hi0) / 2];
+ // loop through the array until indices cross
+ while (lo <= hi) {
+ /* find the first element that is greater than or equal to
+ * the partition element starting from the left Index.
+ */
+ while ((lo < hi0) && (tab[lo] < mid))
+ ++lo;
+ /* find an element that is smaller than or equal to
+ * the partition element starting from the right Index.
+ */
+ while ((hi > lo0) && (tab[hi] > mid))
+ --hi;
+ // if the indexes have not crossed, swap
+ if (lo <= hi) {
+ swap(tab, lo, hi, result);
+ ++lo;
+ --hi;
+ }
+ }
+ /* If the right index has not reached the left side of array
+ * must now sort the left partition.
+ */
+ if (lo0 < hi)
+ sort(tab, lo0, hi, result);
+ /* If the left index has not reached the right side of array
+ * must now sort the right partition.
+ */
+ if (lo < hi0)
+ sort(tab, lo, hi0, result);
+ }
+ }
+
+ public final void store(
+ LocalVariableBinding localBinding,
+ boolean valueRequired) {
+ TypeBinding type = localBinding.type;
+ int position = localBinding.resolvedPosition;
+ // Using dedicated int bytecode
+ if ((type == IntBinding)
+ || (type == CharBinding)
+ || (type == ByteBinding)
+ || (type == ShortBinding)
+ || (type == BooleanBinding)) {
+ if (valueRequired)
+ this.dup();
+ switch (position) {
+ case 0 :
+ this.istore_0();
+ break;
+ case 1 :
+ this.istore_1();
+ break;
+ case 2 :
+ this.istore_2();
+ break;
+ case 3 :
+ this.istore_3();
+ break;
+ default :
+ this.istore(position);
+ }
+ return;
+ }
+ // Using dedicated float bytecode
+ if (type == FloatBinding) {
+ if (valueRequired)
+ this.dup();
+ switch (position) {
+ case 0 :
+ this.fstore_0();
+ break;
+ case 1 :
+ this.fstore_1();
+ break;
+ case 2 :
+ this.fstore_2();
+ break;
+ case 3 :
+ this.fstore_3();
+ break;
+ default :
+ this.fstore(position);
+ }
+ return;
+ }
+ // Using dedicated long bytecode
+ if (type == LongBinding) {
+ if (valueRequired)
+ this.dup2();
+ switch (position) {
+ case 0 :
+ this.lstore_0();
+ break;
+ case 1 :
+ this.lstore_1();
+ break;
+ case 2 :
+ this.lstore_2();
+ break;
+ case 3 :
+ this.lstore_3();
+ break;
+ default :
+ this.lstore(position);
+ }
+ return;
+ }
+ // Using dedicated double bytecode
+ if (type == DoubleBinding) {
+ if (valueRequired)
+ this.dup2();
+ switch (position) {
+ case 0 :
+ this.dstore_0();
+ break;
+ case 1 :
+ this.dstore_1();
+ break;
+ case 2 :
+ this.dstore_2();
+ break;
+ case 3 :
+ this.dstore_3();
+ break;
+ default :
+ this.dstore(position);
+ }
+ return;
+ }
+ // Reference object
+ if (valueRequired)
+ this.dup();
+ switch (position) {
+ case 0 :
+ this.astore_0();
+ break;
+ case 1 :
+ this.astore_1();
+ break;
+ case 2 :
+ this.astore_2();
+ break;
+ case 3 :
+ this.astore_3();
+ break;
+ default :
+ this.astore(position);
+ }
+ }
+
+ public final void store(TypeBinding type, int position) {
+ // Using dedicated int bytecode
+ if ((type == IntBinding)
+ || (type == CharBinding)
+ || (type == ByteBinding)
+ || (type == ShortBinding)
+ || (type == BooleanBinding)) {
+ switch (position) {
+ case 0 :
+ this.istore_0();
+ break;
+ case 1 :
+ this.istore_1();
+ break;
+ case 2 :
+ this.istore_2();
+ break;
+ case 3 :
+ this.istore_3();
+ break;
+ default :
+ this.istore(position);
+ }
+ return;
+ }
+ // Using dedicated float bytecode
+ if (type == FloatBinding) {
+ switch (position) {
+ case 0 :
+ this.fstore_0();
+ break;
+ case 1 :
+ this.fstore_1();
+ break;
+ case 2 :
+ this.fstore_2();
+ break;
+ case 3 :
+ this.fstore_3();
+ break;
+ default :
+ this.fstore(position);
+ }
+ return;
+ }
+ // Using dedicated long bytecode
+ if (type == LongBinding) {
+ switch (position) {
+ case 0 :
+ this.lstore_0();
+ break;
+ case 1 :
+ this.lstore_1();
+ break;
+ case 2 :
+ this.lstore_2();
+ break;
+ case 3 :
+ this.lstore_3();
+ break;
+ default :
+ this.lstore(position);
+ }
+ return;
+ }
+ // Using dedicated double bytecode
+ if (type == DoubleBinding) {
+ switch (position) {
+ case 0 :
+ this.dstore_0();
+ break;
+ case 1 :
+ this.dstore_1();
+ break;
+ case 2 :
+ this.dstore_2();
+ break;
+ case 3 :
+ this.dstore_3();
+ break;
+ default :
+ this.dstore(position);
+ }
+ return;
+ }
+ // Reference object
+ switch (position) {
+ case 0 :
+ this.astore_0();
+ break;
+ case 1 :
+ this.astore_1();
+ break;
+ case 2 :
+ this.astore_2();
+ break;
+ case 3 :
+ this.astore_3();
+ break;
+ default :
+ this.astore(position);
+ }
+ }
+
+ public final void storeInt(int position) {
+ switch (position) {
+ case 0 :
+ this.istore_0();
+ break;
+ case 1 :
+ this.istore_1();
+ break;
+ case 2 :
+ this.istore_2();
+ break;
+ case 3 :
+ this.istore_3();
+ break;
+ default :
+ this.istore(position);
+ }
+ }
+
+ public final void storeObject(int position) {
+ switch (position) {
+ case 0 :
+ this.astore_0();
+ break;
+ case 1 :
+ this.astore_1();
+ break;
+ case 2 :
+ this.astore_2();
+ break;
+ case 3 :
+ this.astore_3();
+ break;
+ default :
+ this.astore(position);
+ }
+ }
+
+ final public void swap() {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_swap;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_swap);
+ }
+ }
+
+ private static final void swap(int a[], int i, int j, int result[]) {
+ int T;
+ T = a[i];
+ a[i] = a[j];
+ a[j] = T;
+ T = result[j];
+ result[j] = result[i];
+ result[i] = T;
+ }
+
+ final public void tableswitch(
+ CaseLabel defaultLabel,
+ int low,
+ int high,
+ int[] keys,
+ int[] sortedIndexes,
+ CaseLabel[] casesLabel) {
+ countLabels = 0;
+ stackDepth--;
+ int length = casesLabel.length;
+ int pos = position;
+ defaultLabel.placeInstruction();
+ for (int i = 0; i < length; i++)
+ casesLabel[i].placeInstruction();
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_tableswitch;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_tableswitch);
+ }
+ for (int i = (3 - (pos % 4)); i > 0; i--) {
+ position++; // Padding
+ classFileOffset++;
+ }
+ defaultLabel.branch();
+ writeSignedWord(low);
+ writeSignedWord(high);
+ int j = low;
+ // the index j is used to know if the index i is one of the missing entries in case of an
+ // optimized tableswitch
+ for (int i = low; i <= high; i++) {
+ int index;
+ int key = keys[index = sortedIndexes[j - low]];
+ if (key == i) {
+ casesLabel[index].branch();
+ j++;
+ } else {
+ defaultLabel.branch();
+ }
+ }
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer("( position:");
+ buffer.append(position);
+ buffer.append(",\nstackDepth:");
+ buffer.append(stackDepth);
+ buffer.append(",\nmaxStack:");
+ buffer.append(stackMax);
+ buffer.append(",\nmaxLocals:");
+ buffer.append(maxLocals);
+ buffer.append(")");
+ return buffer.toString();
+ }
+
+ public void updateLastRecordedEndPC(int pos) {
+
+ /* Tune positions in the table, this is due to some
+ * extra bytecodes being
+ * added to some user code (jumps). */
+ /** OLD CODE
+ if (!generateLineNumberAttributes)
+ return;
+ pcToSourceMap[pcToSourceMapSize - 1][1] = position;
+ // need to update the initialization endPC in case of generation of local variable attributes.
+ updateLocalVariablesAttribute(pos);
+ */
+
+ if (!generateLineNumberAttributes)
+ return;
+ // need to update the initialization endPC in case of generation of local variable attributes.
+ updateLocalVariablesAttribute(pos);
+ }
+
+ public void updateLocalVariablesAttribute(int pos) {
+ // need to update the initialization endPC in case of generation of local variable attributes.
+ if (generateLocalVariableTableAttributes) {
+ for (int i = 0, max = locals.length; i < max; i++) {
+ LocalVariableBinding local = locals[i];
+ if ((local != null) && (local.initializationCount > 0)) {
+ if (local.initializationPCs[((local.initializationCount - 1) << 1) + 1]
+ == pos) {
+ local.initializationPCs[((local.initializationCount - 1) << 1) + 1] = position;
+ }
+ }
+ }
+ }
+ }
+
+ final public void wide() {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_wide;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_wide);
+ }
+ }
+
+ public final void writeByte(byte b) {
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = b;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(b);
+ }
+ }
+
+ public final void writeByteAtPos(int pos, byte b) {
+ try {
+ bCodeStream[pos] = b;
+ } catch (IndexOutOfBoundsException ex) {
+ resizeByteArray();
+ bCodeStream[pos] = b;
+ }
+ }
+
+ /**
+ * Write a unsigned 8 bits value into the byte array
+ * @param
+ */
+ public final void writeSignedByte(int b) {
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) b;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) b);
+ }
+ }
+
+ /**
+ * Write a signed 16 bits value into the byte array
+ * @param
+ */
+ public final void writeSignedShort(int b) {
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) (b >> 8);
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) (b >> 8));
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) b;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) b);
+ }
+ }
+
+ public final void writeSignedShort(int pos, int b) {
+ int currentOffset = startingClassFileOffset + pos;
+ try {
+ bCodeStream[currentOffset] = (byte) (b >> 8);
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray();
+ bCodeStream[currentOffset] = (byte) (b >> 8);
+ }
+ try {
+ bCodeStream[currentOffset + 1] = (byte) b;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray();
+ bCodeStream[currentOffset + 1] = (byte) b;
+ }
+ }
+
+ public final void writeSignedWord(int value) {
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) (value >> 24);
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) (value >> 24));
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) (value >> 16);
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) (value >> 16));
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) (value >> 8);
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) (value >> 8));
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) value;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) value);
+ }
+ }
+
+ public final void writeSignedWord(int pos, int value) {
+ int currentOffset = startingClassFileOffset + pos;
+ try {
+ bCodeStream[currentOffset] = (byte) (value >> 24);
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray();
+ bCodeStream[currentOffset] = (byte) (value >> 24);
+ }
+ try {
+ bCodeStream[currentOffset + 1] = (byte) (value >> 16);
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray();
+ bCodeStream[currentOffset + 1] = (byte) (value >> 16);
+ }
+ try {
+ bCodeStream[currentOffset + 2] = (byte) (value >> 8);
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray();
+ bCodeStream[currentOffset + 2] = (byte) (value >> 8);
+ }
+ try {
+ bCodeStream[currentOffset + 3] = (byte) value;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray();
+ bCodeStream[currentOffset + 3] = (byte) value;
+ }
+ }
+
+ /**
+ * Write a unsigned 8 bits value into the byte array
+ * @param
+ */
+ public final void writeUnsignedByte(int b) {
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) b;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) b);
+ }
+ }
+
+ /**
+ * Write a unsigned 16 bits value into the byte array
+ * @param
+ */
+ public final void writeUnsignedShort(int b) {
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) (b >>> 8);
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) (b >>> 8));
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) b;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) b);
+ }
+ }
+
+ /**
+ * Write a unsigned 32 bits value into the byte array
+ * @param
+ */
+ public final void writeUnsignedWord(int value) {
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) (value >>> 24);
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) (value >>> 24));
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) (value >>> 16);
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) (value >>> 16));
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) (value >>> 8);
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) (value >>> 8));
+ }
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = (byte) value;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray((byte) value);
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ConstantPool.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ConstantPool.java
new file mode 100644
index 0000000000..7fd410eb47
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ConstantPool.java
@@ -0,0 +1,2865 @@
+package org.eclipse.jdt.internal.compiler.codegen;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+
+import org.eclipse.jdt.internal.compiler.ClassFile;
+
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+/**
+ * This type is used to store all the constant pool entries.
+ */
+public class ConstantPool implements ClassFileConstants, TypeIds {
+ public static final int DOUBLE_INITIAL_SIZE = 5;
+ public static final int FLOAT_INITIAL_SIZE = 3;
+ public static final int INT_INITIAL_SIZE = 248;
+ public static final int LONG_INITIAL_SIZE = 5;
+ public static final int UTF8_INITIAL_SIZE = 778;
+ public static final int STRING_INITIAL_SIZE = 761;
+ public static final int FIELD_INITIAL_SIZE = 156;
+ public static final int METHOD_INITIAL_SIZE = 236;
+ public static final int INTERFACE_INITIAL_SIZE = 50;
+ public static final int CLASS_INITIAL_SIZE = 86;
+ public static final int NAMEANDTYPE_INITIAL_SIZE = 272;
+ public static final int CONSTANTPOOL_INITIAL_SIZE = 2000;
+ public static final int CONSTANTPOOL_GROW_SIZE = 6000;
+ protected DoubleCache doubleCache;
+ protected FloatCache floatCache;
+ protected IntegerCache intCache;
+ protected LongCache longCache;
+ public CharArrayCache UTF8Cache;
+ protected CharArrayCache stringCache;
+ protected ObjectCache fieldCache;
+ protected ObjectCache methodCache;
+ protected ObjectCache interfaceMethodCache;
+ protected ObjectCache classCache;
+ protected FieldNameAndTypeCache nameAndTypeCacheForFields;
+ protected MethodNameAndTypeCache nameAndTypeCacheForMethods;
+ int[] wellKnownTypes = new int[20];
+ int[] wellKnownMethods = new int[26];
+ int[] wellKnownFields = new int[10];
+ int[] wellKnownFieldNameAndTypes = new int[2];
+ int[] wellKnownMethodNameAndTypes = new int[24];
+ public byte[] poolContent;
+ public int currentIndex = 1;
+ public int currentOffset;
+ // predefined constant index for well known types
+ final static int JAVA_LANG_BOOLEAN_TYPE = 0;
+ final static int JAVA_LANG_BYTE_TYPE = 1;
+ final static int JAVA_LANG_CHARACTER_TYPE = 2;
+ final static int JAVA_LANG_DOUBLE_TYPE = 3;
+ final static int JAVA_LANG_FLOAT_TYPE = 4;
+ final static int JAVA_LANG_INTEGER_TYPE = 5;
+ final static int JAVA_LANG_LONG_TYPE = 6;
+ final static int JAVA_LANG_SHORT_TYPE = 7;
+ final static int JAVA_LANG_VOID_TYPE = 8;
+ final static int JAVA_LANG_CLASS_TYPE = 9;
+ final static int JAVA_LANG_CLASSNOTFOUNDEXCEPTION_TYPE = 10;
+ final static int JAVA_LANG_NOCLASSDEFFOUNDERROR_TYPE = 11;
+ final static int JAVA_LANG_OBJECT_TYPE = 12;
+ final static int JAVA_LANG_STRING_TYPE = 13;
+ final static int JAVA_LANG_STRINGBUFFER_TYPE = 14;
+ final static int JAVA_LANG_SYSTEM_TYPE = 15;
+ final static int JAVA_LANG_THROWABLE_TYPE = 16;
+ final static int JAVA_LANG_ERROR_TYPE = 17;
+ final static int JAVA_LANG_EXCEPTION_TYPE = 18;
+ final static int JAVA_LANG_REFLECT_CONSTRUCTOR_TYPE = 19;
+ // predefined constant index for well known fields
+ final static int TYPE_BYTE_FIELD = 0;
+ final static int TYPE_SHORT_FIELD = 1;
+ final static int TYPE_CHARACTER_FIELD = 2;
+ final static int TYPE_INTEGER_FIELD = 3;
+ final static int TYPE_LONG_FIELD = 4;
+ final static int TYPE_FLOAT_FIELD = 5;
+ final static int TYPE_DOUBLE_FIELD = 6;
+ final static int TYPE_BOOLEAN_FIELD = 7;
+ final static int TYPE_VOID_FIELD = 8;
+ final static int OUT_SYSTEM_FIELD = 9;
+ // predefined constant index for well known methods
+ final static int FORNAME_CLASS_METHOD = 0;
+ final static int NOCLASSDEFFOUNDERROR_CONSTR_METHOD = 1;
+ final static int APPEND_INT_METHOD = 2;
+ final static int APPEND_FLOAT_METHOD = 3;
+ final static int APPEND_LONG_METHOD = 4;
+ final static int APPEND_OBJECT_METHOD = 5;
+ final static int APPEND_CHAR_METHOD = 6;
+ final static int APPEND_STRING_METHOD = 7;
+ final static int APPEND_BOOLEAN_METHOD = 8;
+ final static int APPEND_DOUBLE_METHOD = 9;
+ final static int STRINGBUFFER_STRING_CONSTR_METHOD = 10;
+ final static int STRINGBUFFER_DEFAULT_CONSTR_METHOD = 11;
+ final static int STRINGBUFFER_TOSTRING_METHOD = 12;
+ final static int SYSTEM_EXIT_METHOD = 13;
+ final static int THROWABLE_GETMESSAGE_METHOD = 14;
+ final static int JAVALANGERROR_CONSTR_METHOD = 15;
+ final static int GETCONSTRUCTOR_CLASS_METHOD = 16;
+ final static int NEWINSTANCE_CONSTRUCTOR_METHOD = 17;
+ final static int STRING_INTERN_METHOD = 18;
+ final static int VALUEOF_INT_METHOD = 19;
+ final static int VALUEOF_FLOAT_METHOD = 20;
+ final static int VALUEOF_LONG_METHOD = 21;
+ final static int VALUEOF_OBJECT_METHOD = 22;
+ final static int VALUEOF_CHAR_METHOD = 23;
+ final static int VALUEOF_BOOLEAN_METHOD = 24;
+ final static int VALUEOF_DOUBLE_METHOD = 25;
+ // predefined constant index for well known name and type for fields
+ final static int TYPE_JAVALANGCLASS_NAME_AND_TYPE = 0;
+ final static int OUT_SYSTEM_NAME_AND_TYPE = 1;
+ // predefined constant index for well known name and type for methods
+ final static int FORNAME_CLASS_METHOD_NAME_AND_TYPE = 0;
+ final static int STRING_CONSTR_METHOD_NAME_AND_TYPE = 1;
+ final static int DEFAULT_CONSTR_METHOD_NAME_AND_TYPE = 2;
+ final static int APPEND_INT_METHOD_NAME_AND_TYPE = 3;
+ final static int APPEND_FLOAT_METHOD_NAME_AND_TYPE = 4;
+ final static int APPEND_LONG_METHOD_NAME_AND_TYPE = 5;
+ final static int APPEND_OBJECT_METHOD_NAME_AND_TYPE = 6;
+ final static int APPEND_CHAR_METHOD_NAME_AND_TYPE = 7;
+ final static int APPEND_STRING_METHOD_NAME_AND_TYPE = 8;
+ final static int APPEND_BOOLEAN_METHOD_NAME_AND_TYPE = 9;
+ final static int APPEND_DOUBLE_METHOD_NAME_AND_TYPE = 10;
+ final static int TOSTRING_METHOD_NAME_AND_TYPE = 11;
+ final static int EXIT_METHOD_NAME_AND_TYPE = 12;
+ final static int GETMESSAGE_METHOD_NAME_AND_TYPE = 13;
+ final static int GETCONSTRUCTOR_METHOD_NAME_AND_TYPE = 14;
+ final static int NEWINSTANCE_METHOD_NAME_AND_TYPE = 15;
+ final static int INTERN_METHOD_NAME_AND_TYPE = 16;
+ final static int VALUEOF_INT_METHOD_NAME_AND_TYPE = 17;
+ final static int VALUEOF_FLOAT_METHOD_NAME_AND_TYPE = 18;
+ final static int VALUEOF_LONG_METHOD_NAME_AND_TYPE = 19;
+ final static int VALUEOF_OBJECT_METHOD_NAME_AND_TYPE = 20;
+ final static int VALUEOF_CHAR_METHOD_NAME_AND_TYPE = 21;
+ final static int VALUEOF_BOOLEAN_METHOD_NAME_AND_TYPE = 22;
+ final static int VALUEOF_DOUBLE_METHOD_NAME_AND_TYPE = 23;
+ /**
+ * ConstantPool constructor comment.
+ */
+ public ConstantPool(ClassFile classFile) {
+ UTF8Cache = new CharArrayCache(UTF8_INITIAL_SIZE);
+ stringCache = new CharArrayCache(STRING_INITIAL_SIZE);
+ fieldCache = new ObjectCache(FIELD_INITIAL_SIZE);
+ methodCache = new ObjectCache(METHOD_INITIAL_SIZE);
+ interfaceMethodCache = new ObjectCache(INTERFACE_INITIAL_SIZE);
+ classCache = new ObjectCache(CLASS_INITIAL_SIZE);
+ nameAndTypeCacheForMethods =
+ new MethodNameAndTypeCache(NAMEANDTYPE_INITIAL_SIZE);
+ nameAndTypeCacheForFields = new FieldNameAndTypeCache(NAMEANDTYPE_INITIAL_SIZE);
+ poolContent = classFile.header;
+ currentOffset = classFile.headerOffset;
+ // currentOffset is initialized to 0 by default
+ currentIndex = 1;
+ }
+
+ /**
+ * Return the content of the receiver
+ */
+ public byte[] dumpBytes() {
+ System.arraycopy(
+ poolContent,
+ 0,
+ (poolContent = new byte[currentOffset]),
+ 0,
+ currentOffset);
+ return poolContent;
+ }
+
+ /**
+ * Return the index of the @fieldBinding.
+ *
+ * Returns -1 if the @fieldBinding is not a predefined fieldBinding,
+ * the right index otherwise.
+ *
+ * @param fieldBinding com.ibm.compiler.namelookup.FieldBinding
+ * @return <CODE>int</CODE>
+ */
+ public int indexOfWellKnownFieldNameAndType(FieldBinding fieldBinding) {
+ if ((fieldBinding.type.id == T_JavaLangClass)
+ && (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE)))
+ return TYPE_JAVALANGCLASS_NAME_AND_TYPE;
+ if ((fieldBinding.type.id == T_JavaIoPrintStream)
+ && (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.Out)))
+ return OUT_SYSTEM_NAME_AND_TYPE;
+ return -1;
+ }
+
+ /**
+ * Return the index of the @fieldBinding.
+ *
+ * Returns -1 if the @fieldBinding is not a predefined fieldBinding,
+ * the right index otherwise.
+ *
+ * @param fieldBinding com.ibm.compiler.namelookup.FieldBinding
+ * @return <CODE>int</CODE>
+ */
+ public int indexOfWellKnownFields(FieldBinding fieldBinding) {
+ switch (fieldBinding.declaringClass.id) {
+ case T_JavaLangByte :
+ if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE))
+ return TYPE_BYTE_FIELD;
+ break;
+ case T_JavaLangShort :
+ if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE))
+ return TYPE_SHORT_FIELD;
+ break;
+ case T_JavaLangCharacter :
+ if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE))
+ return TYPE_CHARACTER_FIELD;
+ break;
+ case T_JavaLangInteger :
+ if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE))
+ return TYPE_INTEGER_FIELD;
+ break;
+ case T_JavaLangLong :
+ if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE))
+ return TYPE_LONG_FIELD;
+ break;
+ case T_JavaLangFloat :
+ if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE))
+ return TYPE_FLOAT_FIELD;
+ break;
+ case T_JavaLangDouble :
+ if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE))
+ return TYPE_DOUBLE_FIELD;
+ break;
+ case T_JavaLangBoolean :
+ if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE))
+ return TYPE_BOOLEAN_FIELD;
+ break;
+ case T_JavaLangVoid :
+ if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.TYPE))
+ return TYPE_VOID_FIELD;
+ break;
+ case T_JavaLangSystem :
+ if (CharOperation.equals(fieldBinding.name, QualifiedNamesConstants.Out))
+ return OUT_SYSTEM_FIELD;
+ }
+ return -1;
+ }
+
+ /**
+ * Return the index of the @methodBinding.
+ *
+ * Returns -1 if the @methodBinding is not a predefined methodBinding,
+ * the right index otherwise.
+ *
+ * @param methodBinding com.ibm.compiler.namelookup.MethodBinding
+ * @return <CODE>int</CODE>
+ */
+ public int indexOfWellKnownMethodNameAndType(MethodBinding methodBinding) {
+ char firstChar = methodBinding.selector[0];
+ switch (firstChar) {
+ case 'f' :
+ if ((methodBinding.parameters.length == 1)
+ && (methodBinding.parameters[0].id == T_JavaLangString)
+ && (methodBinding.returnType.id == T_JavaLangClass)
+ && (CharOperation
+ .equals(methodBinding.selector, QualifiedNamesConstants.ForName))) {
+ // This method binding is forName(java.lang.String)
+ return FORNAME_CLASS_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case '<' :
+ if (CharOperation
+ .equals(methodBinding.selector, QualifiedNamesConstants.Init)) {
+ if (CharOperation
+ .equals(
+ methodBinding.signature(),
+ QualifiedNamesConstants.StringConstructorSignature)) {
+ // This method binding is (java.lang.String)V
+ return STRING_CONSTR_METHOD_NAME_AND_TYPE;
+ } else
+ if (CharOperation
+ .equals(
+ methodBinding.signature(),
+ QualifiedNamesConstants.DefaultConstructorSignature)) {
+ return DEFAULT_CONSTR_METHOD_NAME_AND_TYPE;
+ }
+ }
+ break;
+ case 'a' :
+ if ((methodBinding.parameters.length == 1)
+ && (methodBinding.returnType.id == T_JavaLangStringBuffer)
+ && (CharOperation
+ .equals(methodBinding.selector, QualifiedNamesConstants.Append))) {
+ switch (methodBinding.parameters[0].id) {
+ case T_int :
+ case T_byte :
+ case T_short :
+ // This method binding is append(int)
+ return APPEND_INT_METHOD_NAME_AND_TYPE;
+ case T_float :
+ // This method binding is append(float)
+ return APPEND_FLOAT_METHOD_NAME_AND_TYPE;
+ case T_long :
+ // This method binding is append(long)
+ return APPEND_LONG_METHOD_NAME_AND_TYPE;
+ case T_JavaLangObject :
+ // This method binding is append(java.lang.Object)
+ return APPEND_OBJECT_METHOD_NAME_AND_TYPE;
+ case T_char :
+ // This method binding is append(char)
+ return APPEND_CHAR_METHOD_NAME_AND_TYPE;
+ case T_JavaLangString :
+ // This method binding is append(java.lang.String)
+ return APPEND_STRING_METHOD_NAME_AND_TYPE;
+ case T_boolean :
+ // This method binding is append(boolean)
+ return APPEND_BOOLEAN_METHOD_NAME_AND_TYPE;
+ case T_double :
+ // This method binding is append(double)
+ return APPEND_DOUBLE_METHOD_NAME_AND_TYPE;
+ }
+ }
+ break;
+ case 't' :
+ if ((methodBinding.parameters.length == 0)
+ && (methodBinding.returnType.id == T_JavaLangString)
+ && (CharOperation
+ .equals(methodBinding.selector, QualifiedNamesConstants.ToString))) {
+ // This method binding is toString()
+ return TOSTRING_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case 'v' :
+ if ((methodBinding.parameters.length == 1)
+ && (methodBinding.returnType.id == T_JavaLangString)
+ && (CharOperation
+ .equals(methodBinding.selector, QualifiedNamesConstants.ValueOf))) {
+ switch (methodBinding.parameters[0].id) {
+ case T_Object :
+ return VALUEOF_OBJECT_METHOD_NAME_AND_TYPE;
+ case T_int :
+ case T_short :
+ case T_byte :
+ return VALUEOF_INT_METHOD_NAME_AND_TYPE;
+ case T_long :
+ return VALUEOF_LONG_METHOD_NAME_AND_TYPE;
+ case T_float :
+ return VALUEOF_FLOAT_METHOD_NAME_AND_TYPE;
+ case T_double :
+ return VALUEOF_DOUBLE_METHOD_NAME_AND_TYPE;
+ case T_boolean :
+ return VALUEOF_BOOLEAN_METHOD_NAME_AND_TYPE;
+ case T_char :
+ return VALUEOF_CHAR_METHOD_NAME_AND_TYPE;
+ }
+ }
+ break;
+ case 'e' :
+ if ((methodBinding.parameters.length == 1)
+ && (methodBinding.parameters[0].id == T_int)
+ && (methodBinding.returnType.id == T_void)
+ && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Exit))) {
+ // This method binding is exit(int)
+ return EXIT_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case 'g' :
+ if ((methodBinding.selector.length == 10)
+ && (methodBinding.parameters.length == 0)
+ && (methodBinding.returnType.id == T_JavaLangString)
+ && (CharOperation
+ .equals(methodBinding.selector, QualifiedNamesConstants.GetMessage))) {
+ // This method binding is getMessage()
+ return GETMESSAGE_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case 'i' :
+ if ((methodBinding.parameters.length == 0)
+ && (methodBinding.returnType.id == T_JavaLangString)
+ && (CharOperation
+ .equals(methodBinding.selector, QualifiedNamesConstants.Intern))) {
+ // This method binding is toString()
+ return INTERN_METHOD_NAME_AND_TYPE;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Return the index of the @methodBinding.
+ *
+ * Returns -1 if the @methodBinding is not a predefined methodBinding,
+ * the right index otherwise.
+ *
+ * @param methodBinding com.ibm.compiler.namelookup.MethodBinding
+ * @return <CODE>int</CODE>
+ */
+ public int indexOfWellKnownMethods(MethodBinding methodBinding) {
+ char firstChar = methodBinding.selector[0];
+ switch (methodBinding.declaringClass.id) {
+ case T_JavaLangClass :
+ if ((firstChar == 'f')
+ && (methodBinding.isStatic())
+ && (methodBinding.parameters.length == 1)
+ && (methodBinding.parameters[0].id == T_JavaLangString)
+ && (methodBinding.returnType.id == T_JavaLangClass)
+ && (CharOperation
+ .equals(methodBinding.selector, QualifiedNamesConstants.ForName))) {
+ // This method binding is forName(java.lang.String)
+ return FORNAME_CLASS_METHOD;
+ } else
+ if ((firstChar == 'g')
+ && (methodBinding.parameters.length == 1)
+ && (methodBinding.returnType.id == T_JavaLangReflectConstructor)
+ && CharOperation.equals(
+ methodBinding.selector,
+ QualifiedNamesConstants.GetConstructor)
+ && CharOperation.equals(
+ methodBinding.parameters[0].constantPoolName(),
+ QualifiedNamesConstants.ArrayJavaLangClassConstantPoolName)) {
+ return GETCONSTRUCTOR_CLASS_METHOD;
+ }
+ break;
+ case T_JavaLangNoClassDefError :
+ if ((firstChar == '<')
+ && (methodBinding.parameters.length == 1)
+ && (methodBinding.parameters[0].id == T_JavaLangString)
+ && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Init))) {
+ // This method binding is NoClassDefFoundError(java.lang.String)
+ return NOCLASSDEFFOUNDERROR_CONSTR_METHOD;
+ }
+ break;
+ case T_JavaLangReflectConstructor :
+ if ((firstChar == 'n')
+ && (methodBinding.parameters.length == 1)
+ && (methodBinding.returnType.id == T_JavaLangObject)
+ && CharOperation.equals(
+ methodBinding.selector,
+ QualifiedNamesConstants.NewInstance)
+ && CharOperation.equals(
+ methodBinding.parameters[0].constantPoolName(),
+ QualifiedNamesConstants.ArrayJavaLangObjectConstantPoolName)) {
+ return NEWINSTANCE_CONSTRUCTOR_METHOD;
+ }
+ break;
+ case T_JavaLangStringBuffer :
+ if ((firstChar == 'a')
+ && (methodBinding.parameters.length == 1)
+ && (methodBinding.returnType.id == T_JavaLangStringBuffer)
+ && (CharOperation
+ .equals(methodBinding.selector, QualifiedNamesConstants.Append))) {
+ switch (methodBinding.parameters[0].id) {
+ case T_int :
+ case T_byte :
+ case T_short :
+ // This method binding is append(int)
+ return APPEND_INT_METHOD;
+ case T_float :
+ // This method binding is append(float)
+ return APPEND_FLOAT_METHOD;
+ case T_long :
+ // This method binding is append(long)
+ return APPEND_LONG_METHOD;
+ case T_JavaLangObject :
+ // This method binding is append(java.lang.Object)
+ return APPEND_OBJECT_METHOD;
+ case T_char :
+ // This method binding is append(char)
+ return APPEND_CHAR_METHOD;
+ case T_JavaLangString :
+ // This method binding is append(java.lang.String)
+ return APPEND_STRING_METHOD;
+ case T_boolean :
+ // This method binding is append(boolean)
+ return APPEND_BOOLEAN_METHOD;
+ case T_double :
+ // This method binding is append(double)
+ return APPEND_DOUBLE_METHOD;
+ }
+ } else
+ if ((firstChar == 't')
+ && (methodBinding.parameters.length == 0)
+ && (methodBinding.returnType.id == T_JavaLangString)
+ && (CharOperation
+ .equals(methodBinding.selector, QualifiedNamesConstants.ToString))) {
+ // This method binding is toString()
+ return STRINGBUFFER_TOSTRING_METHOD;
+ } else
+ if ((firstChar == '<')
+ && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Init))) {
+ if ((methodBinding.parameters.length == 1)
+ && (methodBinding.parameters[0].id == T_JavaLangString)) {
+ // This method binding is <init>(String)
+ return STRINGBUFFER_STRING_CONSTR_METHOD;
+ } else {
+ if (methodBinding.parameters.length == 0) {
+ // This method binding is <init>()
+ return STRINGBUFFER_DEFAULT_CONSTR_METHOD;
+ }
+ }
+ }
+ break;
+ case T_JavaLangString :
+ if ((firstChar == 'v')
+ && (methodBinding.parameters.length == 1)
+ && (methodBinding.returnType.id == T_JavaLangString)
+ && (CharOperation
+ .equals(methodBinding.selector, QualifiedNamesConstants.ValueOf))) {
+ // This method binding is valueOf(java.lang.Object)
+ switch (methodBinding.parameters[0].id) {
+ case T_Object :
+ return VALUEOF_OBJECT_METHOD;
+ case T_int :
+ case T_short :
+ case T_byte :
+ return VALUEOF_INT_METHOD;
+ case T_long :
+ return VALUEOF_LONG_METHOD;
+ case T_float :
+ return VALUEOF_FLOAT_METHOD;
+ case T_double :
+ return VALUEOF_DOUBLE_METHOD;
+ case T_boolean :
+ return VALUEOF_BOOLEAN_METHOD;
+ case T_char :
+ return VALUEOF_CHAR_METHOD;
+ }
+ } else
+ if ((firstChar == 'i')
+ && (methodBinding.parameters.length == 0)
+ && (methodBinding.returnType.id == T_JavaLangString)
+ && (CharOperation
+ .equals(methodBinding.selector, QualifiedNamesConstants.Intern))) {
+ // This method binding is valueOf(java.lang.Object)
+ return STRING_INTERN_METHOD;
+ }
+ break;
+ case T_JavaLangSystem :
+ if ((firstChar == 'e')
+ && (methodBinding.parameters.length == 1)
+ && (methodBinding.parameters[0].id == T_int)
+ && (methodBinding.returnType.id == T_void)
+ && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Exit))) {
+ // This method binding is exit(int)
+ return SYSTEM_EXIT_METHOD;
+ }
+ break;
+ case T_JavaLangThrowable :
+ if ((firstChar == 'g')
+ && (methodBinding.selector.length == 10)
+ && (methodBinding.parameters.length == 0)
+ && (methodBinding.returnType.id == T_JavaLangString)
+ && (CharOperation
+ .equals(methodBinding.selector, QualifiedNamesConstants.GetMessage))) {
+ // This method binding is getMessage()
+ return THROWABLE_GETMESSAGE_METHOD;
+ }
+ case T_JavaLangError :
+ if ((firstChar == '<')
+ && (methodBinding.parameters.length == 1)
+ && (CharOperation.equals(methodBinding.selector, QualifiedNamesConstants.Init))
+ && (methodBinding.parameters[0].id == T_String)) {
+ return JAVALANGERROR_CONSTR_METHOD;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Return the index of the @typeBinding
+ *
+ * Returns -1 if the @typeBinding is not a predefined binding, the right index
+ * otherwise.
+ *
+ * @param typeBinding com.ibm.compiler.namelookup.TypeBinding
+ * @return <CODE>int</CODE>
+ */
+ public int indexOfWellKnownTypes(TypeBinding typeBinding) {
+ switch (typeBinding.id) {
+ case T_JavaLangBoolean :
+ return JAVA_LANG_BOOLEAN_TYPE;
+ case T_JavaLangByte :
+ return JAVA_LANG_BYTE_TYPE;
+ case T_JavaLangCharacter :
+ return JAVA_LANG_CHARACTER_TYPE;
+ case T_JavaLangDouble :
+ return JAVA_LANG_DOUBLE_TYPE;
+ case T_JavaLangFloat :
+ return JAVA_LANG_FLOAT_TYPE;
+ case T_JavaLangInteger :
+ return JAVA_LANG_INTEGER_TYPE;
+ case T_JavaLangLong :
+ return JAVA_LANG_LONG_TYPE;
+ case T_JavaLangShort :
+ return JAVA_LANG_SHORT_TYPE;
+ case T_JavaLangVoid :
+ return JAVA_LANG_VOID_TYPE;
+ case T_JavaLangClass :
+ return JAVA_LANG_CLASS_TYPE;
+ case T_JavaLangClassNotFoundException :
+ return JAVA_LANG_CLASSNOTFOUNDEXCEPTION_TYPE;
+ case T_JavaLangNoClassDefError :
+ return JAVA_LANG_NOCLASSDEFFOUNDERROR_TYPE;
+ case T_JavaLangObject :
+ return JAVA_LANG_OBJECT_TYPE;
+ case T_JavaLangString :
+ return JAVA_LANG_STRING_TYPE;
+ case T_JavaLangStringBuffer :
+ return JAVA_LANG_STRINGBUFFER_TYPE;
+ case T_JavaLangSystem :
+ return JAVA_LANG_SYSTEM_TYPE;
+ case T_JavaLangThrowable :
+ return JAVA_LANG_THROWABLE_TYPE;
+ case T_JavaLangError :
+ return JAVA_LANG_ERROR_TYPE;
+ case T_JavaLangException :
+ return JAVA_LANG_EXCEPTION_TYPE;
+ case T_JavaLangReflectConstructor :
+ return JAVA_LANG_REFLECT_CONSTRUCTOR_TYPE;
+ }
+ return -1;
+ }
+
+ public int literalIndex(byte[] utf8encoding, char[] stringCharArray) {
+ int index;
+ if ((index = UTF8Cache.get(stringCharArray)) < 0) {
+ // The entry doesn't exit yet
+ index = UTF8Cache.put(stringCharArray, currentIndex);
+ currentIndex++;
+ // Write the tag first
+ writeU1(Utf8Tag);
+ // Then the size of the stringName array
+ //writeU2(utf8Constant.length);
+ int savedCurrentOffset = currentOffset;
+ if (currentOffset + 2 >= poolContent.length) {
+ // we need to resize the poolContent array because we won't have
+ // enough space to write the length
+ int length = poolContent.length;
+ System.arraycopy(
+ poolContent,
+ 0,
+ (poolContent = new byte[length + CONSTANTPOOL_GROW_SIZE]),
+ 0,
+ length);
+ }
+ currentOffset += 2;
+ // add in once the whole byte array
+ int length = poolContent.length;
+ int utf8encodingLength = utf8encoding.length;
+ if (currentOffset + utf8encodingLength >= length) {
+ System.arraycopy(
+ poolContent,
+ 0,
+ (poolContent = new byte[length + utf8encodingLength + CONSTANTPOOL_GROW_SIZE]),
+ 0,
+ length);
+ }
+ System.arraycopy(
+ utf8encoding,
+ 0,
+ poolContent,
+ currentOffset,
+ utf8encodingLength);
+ currentOffset += utf8encodingLength;
+ // Now we know the length that we have to write in the constant pool
+ // we use savedCurrentOffset to do that
+ poolContent[savedCurrentOffset] = (byte) (utf8encodingLength >> 8);
+ poolContent[savedCurrentOffset + 1] = (byte) utf8encodingLength;
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param char[] stringName
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndex(char[] utf8Constant) {
+ int index;
+ if ((index = UTF8Cache.get(utf8Constant)) < 0) {
+ // The entry doesn't exit yet
+ // Write the tag first
+ writeU1(Utf8Tag);
+ // Then the size of the stringName array
+ int savedCurrentOffset = currentOffset;
+ if (currentOffset + 2 >= poolContent.length) {
+ // we need to resize the poolContent array because we won't have
+ // enough space to write the length
+ int length = poolContent.length;
+ System.arraycopy(
+ poolContent,
+ 0,
+ (poolContent = new byte[length + CONSTANTPOOL_GROW_SIZE]),
+ 0,
+ length);
+ }
+ currentOffset += 2;
+ int length = 0;
+ for (int i = 0; i < utf8Constant.length; i++) {
+ char current = utf8Constant[i];
+ if ((current >= 0x0001) && (current <= 0x007F)) {
+ // we only need one byte: ASCII table
+ writeU1(current);
+ length++;
+ } else
+ if (current > 0x07FF) {
+ // we need 3 bytes
+ length += 3;
+ writeU1(0xE0 | ((current >> 12) & 0x0F)); // 0xE0 = 1110 0000
+ writeU1(0x80 | ((current >> 6) & 0x3F)); // 0x80 = 1000 0000
+ writeU1(0x80 | (current & 0x3F)); // 0x80 = 1000 0000
+ } else {
+ // we can be 0 or between 0x0080 and 0x07FF
+ // In that case we only need 2 bytes
+ length += 2;
+ writeU1(0xC0 | ((current >> 6) & 0x1F)); // 0xC0 = 1100 0000
+ writeU1(0x80 | (current & 0x3F)); // 0x80 = 1000 0000
+ }
+ }
+ if (length >= 65535) {
+ currentOffset = savedCurrentOffset - 1;
+ return -1;
+ }
+ index = UTF8Cache.put(utf8Constant, currentIndex);
+ currentIndex++;
+ // Now we know the length that we have to write in the constant pool
+ // we use savedCurrentOffset to do that
+ poolContent[savedCurrentOffset] = (byte) (length >> 8);
+ poolContent[savedCurrentOffset + 1] = (byte) length;
+ }
+ return index;
+ }
+
+ public int literalIndex(char[] stringCharArray, byte[] utf8encoding) {
+ int index;
+ int stringIndex;
+ if ((index = stringCache.get(stringCharArray)) < 0) {
+ // The entry doesn't exit yet
+ stringIndex = literalIndex(utf8encoding, stringCharArray);
+ index = stringCache.put(stringCharArray, currentIndex++);
+ // Write the tag first
+ writeU1(StringTag);
+ // Then the string index
+ writeU2(stringIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the double
+ * value. If the double is not already present into the pool, it is added. The
+ * double cache is updated and it returns the right index.
+ *
+ * @param <CODE>double</CODE> key
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndex(double key) {
+ //Retrieve the index from the cache
+ // The double constant takes two indexes into the constant pool, but we only store
+ // the first index into the long table
+ int index;
+ // lazy initialization for base type caches
+ // If it is null, initialize it, otherwise use it
+ if (doubleCache == null) {
+ doubleCache = new DoubleCache(DOUBLE_INITIAL_SIZE);
+ }
+ if ((index = doubleCache.get(key)) < 0) {
+ index = doubleCache.put(key, currentIndex++);
+ currentIndex++; // a double needs an extra place into the constant pool
+ // Write the double into the constant pool
+ // First add the tag
+ writeU1(DoubleTag);
+ // Then add the 8 bytes representing the double
+ long temp = java.lang.Double.doubleToLongBits(key);
+ for (int i = 0; i < 8; i++) {
+ try {
+ poolContent[currentOffset++] = (byte) (temp >>> (56 - (i << 3)));
+ } catch (IndexOutOfBoundsException e) { //currentOffset has been ++ already (see the -1)
+ int length = poolContent.length;
+ System.arraycopy(
+ poolContent,
+ 0,
+ (poolContent = new byte[(length << 1) + CONSTANTPOOL_INITIAL_SIZE]),
+ 0,
+ length);
+ poolContent[currentOffset - 1] = (byte) (temp >>> (56 - (i << 3)));
+ }
+ }
+ };
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the float
+ * value. If the float is not already present into the pool, it is added. The
+ * int cache is updated and it returns the right index.
+ *
+ * @param <CODE>float</CODE> key
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndex(float key) {
+ //Retrieve the index from the cache
+ int index;
+ // lazy initialization for base type caches
+ // If it is null, initialize it, otherwise use it
+ if (floatCache == null) {
+ floatCache = new FloatCache(FLOAT_INITIAL_SIZE);
+ }
+ if ((index = floatCache.get(key)) < 0) {
+ index = floatCache.put(key, currentIndex++);
+ // Write the float constant entry into the constant pool
+ // First add the tag
+ writeU1(FloatTag);
+ // Then add the 4 bytes representing the float
+ int temp = java.lang.Float.floatToIntBits(key);
+ for (int i = 0; i < 4; i++) {
+ try {
+ poolContent[currentOffset++] = (byte) (temp >>> (24 - i * 8));
+ } catch (IndexOutOfBoundsException e) { //currentOffset has been ++ already (see the -1)
+ int length = poolContent.length;
+ System.arraycopy(
+ poolContent,
+ 0,
+ (poolContent = new byte[length * 2 + CONSTANTPOOL_INITIAL_SIZE]),
+ 0,
+ length);
+ poolContent[currentOffset - 1] = (byte) (temp >>> (24 - i * 8));
+ }
+ }
+ };
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the int
+ * value. If the int is not already present into the pool, it is added. The
+ * int cache is updated and it returns the right index.
+ *
+ * @param <CODE>int</CODE> key
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndex(int key) {
+ //Retrieve the index from the cache
+ int index;
+ // lazy initialization for base type caches
+ // If it is null, initialize it, otherwise use it
+ if (intCache == null) {
+ intCache = new IntegerCache(INT_INITIAL_SIZE);
+ }
+ if ((index = intCache.get(key)) < 0) {
+ index = intCache.put(key, currentIndex++);
+ // Write the integer constant entry into the constant pool
+ // First add the tag
+ writeU1(IntegerTag);
+ // Then add the 4 bytes representing the int
+ for (int i = 0; i < 4; i++) {
+ try {
+ poolContent[currentOffset++] = (byte) (key >>> (24 - i * 8));
+ } catch (IndexOutOfBoundsException e) { //currentOffset has been ++ already (see the -1)
+ int length = poolContent.length;
+ System.arraycopy(
+ poolContent,
+ 0,
+ (poolContent = new byte[length * 2 + CONSTANTPOOL_INITIAL_SIZE]),
+ 0,
+ length);
+ poolContent[currentOffset - 1] = (byte) (key >>> (24 - i * 8));
+ }
+ }
+ };
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the long
+ * value. If the long is not already present into the pool, it is added. The
+ * long cache is updated and it returns the right index.
+ *
+ * @param <CODE>long</CODE> key
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndex(long key) {
+ // Retrieve the index from the cache
+ // The long constant takes two indexes into the constant pool, but we only store
+ // the first index into the long table
+ int index;
+ // lazy initialization for base type caches
+ // If it is null, initialize it, otherwise use it
+ if (longCache == null) {
+ longCache = new LongCache(LONG_INITIAL_SIZE);
+ }
+ if ((index = longCache.get(key)) < 0) {
+ index = longCache.put(key, currentIndex++);
+ currentIndex++; // long value need an extra place into thwe constant pool
+ // Write the long into the constant pool
+ // First add the tag
+ writeU1(LongTag);
+ // Then add the 8 bytes representing the long
+ for (int i = 0; i < 8; i++) {
+ try {
+ poolContent[currentOffset++] = (byte) (key >>> (56 - (i << 3)));
+ } catch (IndexOutOfBoundsException e) { //currentOffset has been ++ already (see the -1)
+ int length = poolContent.length;
+ System.arraycopy(
+ poolContent,
+ 0,
+ (poolContent = new byte[(length << 1) + CONSTANTPOOL_INITIAL_SIZE]),
+ 0,
+ length);
+ poolContent[currentOffset - 1] = (byte) (key >>> (56 - (i << 3)));
+ }
+ }
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param stringConstant java.lang.String
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndex(String stringConstant) {
+ int index;
+ char[] stringCharArray = stringConstant.toCharArray();
+ if ((index = stringCache.get(stringCharArray)) < 0) {
+ // The entry doesn't exit yet
+ int stringIndex = literalIndex(stringCharArray);
+ index = stringCache.put(stringCharArray, currentIndex++);
+ // Write the tag first
+ writeU1(StringTag);
+ // Then the string index
+ writeU2(stringIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool
+ * corresponding to the field binding aFieldBinding.
+ *
+ * @param FieldBinding aFieldBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndex(FieldBinding aFieldBinding) {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ int indexWellKnownField;
+ if ((indexWellKnownField = indexOfWellKnownFields(aFieldBinding)) == -1) {
+ if ((index = fieldCache.get(aFieldBinding)) < 0) {
+ // The entry doesn't exit yet
+ classIndex = literalIndex(aFieldBinding.declaringClass);
+ nameAndTypeIndex =
+ literalIndexForFields(
+ literalIndex(aFieldBinding.name),
+ literalIndex(aFieldBinding.type.signature()),
+ aFieldBinding);
+ index = fieldCache.put(aFieldBinding, currentIndex++);
+ writeU1(FieldRefTag);
+ writeU2(classIndex);
+ writeU2(nameAndTypeIndex);
+ }
+ } else {
+ if ((index = wellKnownFields[indexWellKnownField]) == 0) {
+ // that field need to be inserted
+ classIndex = literalIndex(aFieldBinding.declaringClass);
+ nameAndTypeIndex =
+ literalIndexForFields(
+ literalIndex(aFieldBinding.name),
+ literalIndex(aFieldBinding.type.signature()),
+ aFieldBinding);
+ index = wellKnownFields[indexWellKnownField] = currentIndex++;
+ writeU1(FieldRefTag);
+ writeU2(classIndex);
+ writeU2(nameAndTypeIndex);
+ }
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @param MethodBinding aMethodBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndex(MethodBinding aMethodBinding) {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ int nameIndex;
+ int indexWellKnownMethod;
+ if ((indexWellKnownMethod = indexOfWellKnownMethods(aMethodBinding)) == -1) {
+ if (aMethodBinding.declaringClass.isInterface()) {
+ // Lookinf into the interface method ref table
+ if ((index = interfaceMethodCache.get(aMethodBinding)) < 0) {
+ classIndex = literalIndex(aMethodBinding.declaringClass);
+ nameAndTypeIndex =
+ literalIndexForMethods(
+ literalIndex(aMethodBinding.constantPoolName()),
+ literalIndex(aMethodBinding.signature()),
+ aMethodBinding);
+ index = interfaceMethodCache.put(aMethodBinding, currentIndex++);
+ // Write the interface method ref constant into the constant pool
+ // First add the tag
+ writeU1(InterfaceMethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ } else {
+ // Lookinf into the method ref table
+ if ((index = methodCache.get(aMethodBinding)) < 0) {
+ classIndex = literalIndex(aMethodBinding.declaringClass);
+ nameAndTypeIndex =
+ literalIndexForMethods(
+ literalIndex(aMethodBinding.constantPoolName()),
+ literalIndex(aMethodBinding.signature()),
+ aMethodBinding);
+ index = methodCache.put(aMethodBinding, currentIndex++);
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ }
+ } else {
+ // This is a well known method
+ if ((index = wellKnownMethods[indexWellKnownMethod]) == 0) {
+ // this methods was not inserted yet
+ if (aMethodBinding.declaringClass.isInterface()) {
+ // Lookinf into the interface method ref table
+ classIndex = literalIndex(aMethodBinding.declaringClass);
+ nameAndTypeIndex =
+ literalIndexForMethods(
+ literalIndex(aMethodBinding.constantPoolName()),
+ literalIndex(aMethodBinding.signature()),
+ aMethodBinding);
+ index = wellKnownMethods[indexWellKnownMethod] = currentIndex++;
+ // Write the interface method ref constant into the constant pool
+ // First add the tag
+ writeU1(InterfaceMethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ } else {
+ // Lookinf into the method ref table
+ classIndex = literalIndex(aMethodBinding.declaringClass);
+ nameAndTypeIndex =
+ literalIndexForMethods(
+ literalIndex(aMethodBinding.constantPoolName()),
+ literalIndex(aMethodBinding.signature()),
+ aMethodBinding);
+ index = wellKnownMethods[indexWellKnownMethod] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ }
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param TypeBinding aTypeBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndex(TypeBinding aTypeBinding) {
+ int index;
+ int nameIndex;
+ int indexWellKnownType;
+ if ((indexWellKnownType = indexOfWellKnownTypes(aTypeBinding)) == -1) {
+ if ((index = classCache.get(aTypeBinding)) < 0) {
+ // The entry doesn't exit yet
+ nameIndex = literalIndex(aTypeBinding.constantPoolName());
+ index = classCache.put(aTypeBinding, currentIndex++);
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ } else {
+ if ((index = wellKnownTypes[indexWellKnownType]) == 0) {
+ // Need to insert that binding
+ nameIndex = literalIndex(aTypeBinding.constantPoolName());
+ index = wellKnownTypes[indexWellKnownType] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding
+ * nameAndType constant with nameIndex, typeIndex.
+ *
+ * @param int nameIndex
+ * @param int nameIndex
+ * @param org.eclipse.jdt.internal.compiler.lookup.FieldBinding a FieldBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForFields(
+ int nameIndex,
+ int typeIndex,
+ FieldBinding key) {
+ int index;
+ int indexOfWellKnownFieldNameAndType;
+ if ((indexOfWellKnownFieldNameAndType = indexOfWellKnownFieldNameAndType(key))
+ == -1) {
+ // check if the entry already exists
+ if ((index = nameAndTypeCacheForFields.get(key)) == -1) {
+ // The entry doesn't exit yet
+ index = nameAndTypeCacheForFields.put(key, currentIndex++);
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ } else {
+ if ((index = wellKnownFieldNameAndTypes[indexOfWellKnownFieldNameAndType])
+ == 0) {
+ index =
+ wellKnownFieldNameAndTypes[indexOfWellKnownFieldNameAndType] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param TypeBinding aTypeBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangBoolean() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_BOOLEAN_TYPE]) == 0) {
+ int nameIndex;
+ // The entry doesn't exit yet
+ nameIndex =
+ literalIndex(QualifiedNamesConstants.JavaLangBooleanConstantPoolName);
+ index = wellKnownTypes[JAVA_LANG_BOOLEAN_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool
+ * corresponding to the field binding aFieldBinding.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangBooleanTYPE() {
+ int index;
+ if ((index = wellKnownFields[TYPE_BOOLEAN_FIELD]) == 0) {
+ int nameAndTypeIndex;
+ int classIndex;
+ // The entry doesn't exit yet
+ classIndex = literalIndexForJavaLangBoolean();
+ if ((nameAndTypeIndex =
+ wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.TYPE);
+ int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature);
+ nameAndTypeIndex =
+ wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownFields[TYPE_BOOLEAN_FIELD] = currentIndex++;
+ writeU1(FieldRefTag);
+ writeU2(classIndex);
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param TypeBinding aTypeBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangByte() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_BYTE_TYPE]) == 0) {
+ int nameIndex;
+ // The entry doesn't exit yet
+ nameIndex = literalIndex(QualifiedNamesConstants.JavaLangByteConstantPoolName);
+ index = wellKnownTypes[JAVA_LANG_BYTE_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool
+ * corresponding to the field binding aFieldBinding.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangByteTYPE() {
+ int index;
+ if ((index = wellKnownFields[TYPE_BYTE_FIELD]) == 0) {
+ int nameAndTypeIndex;
+ int classIndex;
+ // The entry doesn't exit yet
+ classIndex = literalIndexForJavaLangByte();
+ if ((nameAndTypeIndex =
+ wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.TYPE);
+ int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature);
+ nameAndTypeIndex =
+ wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownFields[TYPE_BYTE_FIELD] = currentIndex++;
+ writeU1(FieldRefTag);
+ writeU2(classIndex);
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param TypeBinding aTypeBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangCharacter() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_CHARACTER_TYPE]) == 0) {
+ int nameIndex;
+ // The entry doesn't exit yet
+ nameIndex =
+ literalIndex(QualifiedNamesConstants.JavaLangCharacterConstantPoolName);
+ index = wellKnownTypes[JAVA_LANG_CHARACTER_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool
+ * corresponding to the field binding aFieldBinding.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangCharacterTYPE() {
+ int index;
+ if ((index = wellKnownFields[TYPE_CHARACTER_FIELD]) == 0) {
+ int nameAndTypeIndex;
+ int classIndex;
+ // The entry doesn't exit yet
+ classIndex = literalIndexForJavaLangCharacter();
+ if ((nameAndTypeIndex =
+ wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.TYPE);
+ int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature);
+ nameAndTypeIndex =
+ wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownFields[TYPE_CHARACTER_FIELD] = currentIndex++;
+ writeU1(FieldRefTag);
+ writeU2(classIndex);
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param TypeBinding aTypeBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangClass() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_CLASS_TYPE]) == 0) {
+ int nameIndex;
+ // The entry doesn't exit yet
+ nameIndex = literalIndex(QualifiedNamesConstants.JavaLangClassConstantPoolName);
+ index = wellKnownTypes[JAVA_LANG_CLASS_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangClassForName() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[FORNAME_CLASS_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangClass();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[FORNAME_CLASS_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.ForName);
+ int typeIndex = literalIndex(QualifiedNamesConstants.ForNameSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[FORNAME_CLASS_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[FORNAME_CLASS_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangClassGetConstructor() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[GETCONSTRUCTOR_CLASS_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangClass();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GETCONSTRUCTOR_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.GetConstructor);
+ int typeIndex = literalIndex(QualifiedNamesConstants.GetConstructorSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GETCONSTRUCTOR_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[GETCONSTRUCTOR_CLASS_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param TypeBinding aTypeBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangClassNotFoundException() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_CLASSNOTFOUNDEXCEPTION_TYPE]) == 0) {
+ int nameIndex;
+ // The entry doesn't exit yet
+ nameIndex =
+ literalIndex(
+ QualifiedNamesConstants.JavaLangClassNotFoundExceptionConstantPoolName);
+ index = wellKnownTypes[JAVA_LANG_CLASSNOTFOUNDEXCEPTION_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param TypeBinding aTypeBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangDouble() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_DOUBLE_TYPE]) == 0) {
+ int nameIndex;
+ // The entry doesn't exit yet
+ nameIndex =
+ literalIndex(QualifiedNamesConstants.JavaLangDoubleConstantPoolName);
+ index = wellKnownTypes[JAVA_LANG_DOUBLE_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool
+ * corresponding to the field binding aFieldBinding.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangDoubleTYPE() {
+ int index;
+ if ((index = wellKnownFields[TYPE_DOUBLE_FIELD]) == 0) {
+ int nameAndTypeIndex;
+ int classIndex;
+ // The entry doesn't exit yet
+ classIndex = literalIndexForJavaLangDouble();
+ if ((nameAndTypeIndex =
+ wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.TYPE);
+ int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature);
+ nameAndTypeIndex =
+ wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownFields[TYPE_DOUBLE_FIELD] = currentIndex++;
+ writeU1(FieldRefTag);
+ writeU2(classIndex);
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param TypeBinding aTypeBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangError() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_ERROR_TYPE]) == 0) {
+ int nameIndex;
+ // The entry doesn't exit yet
+ nameIndex = literalIndex(QualifiedNamesConstants.JavaLangErrorConstantPoolName);
+ index = wellKnownTypes[JAVA_LANG_ERROR_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangErrorConstructor() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[JAVALANGERROR_CONSTR_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangError();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[STRING_CONSTR_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.Init);
+ int typeIndex =
+ literalIndex(QualifiedNamesConstants.StringConstructorSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[STRING_CONSTR_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[JAVALANGERROR_CONSTR_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ public int literalIndexForJavaLangException() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_EXCEPTION_TYPE]) == 0) {
+ // The entry doesn't exit yet
+ int nameIndex =
+ literalIndex(QualifiedNamesConstants.JavaLangExceptionConstantPoolName);
+ index = wellKnownTypes[JAVA_LANG_EXCEPTION_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param TypeBinding aTypeBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangFloat() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_FLOAT_TYPE]) == 0) {
+ int nameIndex;
+ // The entry doesn't exit yet
+ nameIndex = literalIndex(QualifiedNamesConstants.JavaLangFloatConstantPoolName);
+ index = wellKnownTypes[JAVA_LANG_FLOAT_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool
+ * corresponding to the field binding aFieldBinding.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangFloatTYPE() {
+ int index;
+ if ((index = wellKnownFields[TYPE_FLOAT_FIELD]) == 0) {
+ int nameAndTypeIndex;
+ int classIndex;
+ // The entry doesn't exit yet
+ classIndex = literalIndexForJavaLangFloat();
+ if ((nameAndTypeIndex =
+ wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.TYPE);
+ int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature);
+ nameAndTypeIndex =
+ wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownFields[TYPE_FLOAT_FIELD] = currentIndex++;
+ writeU1(FieldRefTag);
+ writeU2(classIndex);
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param TypeBinding aTypeBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangInteger() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_INTEGER_TYPE]) == 0) {
+ int nameIndex;
+ // The entry doesn't exit yet
+ nameIndex =
+ literalIndex(QualifiedNamesConstants.JavaLangIntegerConstantPoolName);
+ index = wellKnownTypes[JAVA_LANG_INTEGER_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool
+ * corresponding to the field binding aFieldBinding.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangIntegerTYPE() {
+ int index;
+ if ((index = wellKnownFields[TYPE_INTEGER_FIELD]) == 0) {
+ int nameAndTypeIndex;
+ int classIndex;
+ // The entry doesn't exit yet
+ classIndex = literalIndexForJavaLangInteger();
+ if ((nameAndTypeIndex =
+ wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.TYPE);
+ int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature);
+ nameAndTypeIndex =
+ wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownFields[TYPE_INTEGER_FIELD] = currentIndex++;
+ writeU1(FieldRefTag);
+ writeU2(classIndex);
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param TypeBinding aTypeBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangLong() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_LONG_TYPE]) == 0) {
+ int nameIndex;
+ // The entry doesn't exit yet
+ nameIndex = literalIndex(QualifiedNamesConstants.JavaLangLongConstantPoolName);
+ index = wellKnownTypes[JAVA_LANG_LONG_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool
+ * corresponding to the field binding aFieldBinding.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangLongTYPE() {
+ int index;
+ if ((index = wellKnownFields[TYPE_LONG_FIELD]) == 0) {
+ int nameAndTypeIndex;
+ int classIndex;
+ // The entry doesn't exit yet
+ classIndex = literalIndexForJavaLangLong();
+ if ((nameAndTypeIndex =
+ wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.TYPE);
+ int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature);
+ nameAndTypeIndex =
+ wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownFields[TYPE_LONG_FIELD] = currentIndex++;
+ writeU1(FieldRefTag);
+ writeU2(classIndex);
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param TypeBinding aTypeBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangNoClassDefFoundError() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_NOCLASSDEFFOUNDERROR_TYPE]) == 0) {
+ int nameIndex;
+ // The entry doesn't exit yet
+ nameIndex =
+ literalIndex(
+ QualifiedNamesConstants.JavaLangNoClassDefFoundErrorConstantPoolName);
+ index = wellKnownTypes[JAVA_LANG_NOCLASSDEFFOUNDERROR_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangNoClassDefFoundErrorStringConstructor() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[NOCLASSDEFFOUNDERROR_CONSTR_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangNoClassDefFoundError();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[STRING_CONSTR_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.Init);
+ int typeIndex =
+ literalIndex(QualifiedNamesConstants.StringConstructorSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[STRING_CONSTR_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[NOCLASSDEFFOUNDERROR_CONSTR_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param TypeBinding aTypeBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangObject() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_OBJECT_TYPE]) == 0) {
+ int nameIndex;
+ // The entry doesn't exit yet
+ nameIndex =
+ literalIndex(QualifiedNamesConstants.JavaLangObjectConstantPoolName);
+ index = wellKnownTypes[JAVA_LANG_OBJECT_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param TypeBinding aTypeBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangReflectConstructor() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_REFLECT_CONSTRUCTOR_TYPE]) == 0) {
+ int nameIndex;
+ // The entry doesn't exit yet
+ nameIndex = literalIndex(QualifiedNamesConstants.JavaLangReflectConstructor);
+ index = wellKnownTypes[JAVA_LANG_REFLECT_CONSTRUCTOR_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ public int literalIndexForJavaLangReflectConstructorNewInstance() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[NEWINSTANCE_CONSTRUCTOR_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangReflectConstructor();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[NEWINSTANCE_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.NewInstance);
+ int typeIndex = literalIndex(QualifiedNamesConstants.NewInstanceSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[NEWINSTANCE_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[NEWINSTANCE_CONSTRUCTOR_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param TypeBinding aTypeBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangShort() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_SHORT_TYPE]) == 0) {
+ int nameIndex;
+ // The entry doesn't exit yet
+ nameIndex = literalIndex(QualifiedNamesConstants.JavaLangShortConstantPoolName);
+ index = wellKnownTypes[JAVA_LANG_SHORT_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool
+ * corresponding to the field binding aFieldBinding.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangShortTYPE() {
+ int index;
+ if ((index = wellKnownFields[TYPE_SHORT_FIELD]) == 0) {
+ int nameAndTypeIndex;
+ int classIndex;
+ // The entry doesn't exit yet
+ classIndex = literalIndexForJavaLangShort();
+ if ((nameAndTypeIndex =
+ wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.TYPE);
+ int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature);
+ nameAndTypeIndex =
+ wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownFields[TYPE_SHORT_FIELD] = currentIndex++;
+ writeU1(FieldRefTag);
+ writeU2(classIndex);
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param TypeBinding aTypeBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangString() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_STRING_TYPE]) == 0) {
+ int nameIndex;
+ // The entry doesn't exit yet
+ nameIndex =
+ literalIndex(QualifiedNamesConstants.JavaLangStringConstantPoolName);
+ index = wellKnownTypes[JAVA_LANG_STRING_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param TypeBinding aTypeBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangStringBuffer() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_STRINGBUFFER_TYPE]) == 0) {
+ int nameIndex;
+ // The entry doesn't exit yet
+ nameIndex =
+ literalIndex(QualifiedNamesConstants.JavaLangStringBufferConstantPoolName);
+ index = wellKnownTypes[JAVA_LANG_STRINGBUFFER_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangStringBufferAppend(int typeID) {
+ int index = 0;
+ int nameAndTypeIndex = 0;
+ int classIndex = 0;
+ switch (typeID) {
+ case T_int :
+ case T_byte :
+ case T_short :
+ if ((index = wellKnownMethods[APPEND_INT_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangStringBuffer();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[APPEND_INT_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.Append);
+ int typeIndex = literalIndex(QualifiedNamesConstants.AppendIntSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[APPEND_INT_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[APPEND_INT_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_long :
+ if ((index = wellKnownMethods[APPEND_LONG_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangStringBuffer();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[APPEND_LONG_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.Append);
+ int typeIndex = literalIndex(QualifiedNamesConstants.AppendLongSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[APPEND_LONG_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[APPEND_LONG_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_float :
+ if ((index = wellKnownMethods[APPEND_FLOAT_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangStringBuffer();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[APPEND_FLOAT_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.Append);
+ int typeIndex = literalIndex(QualifiedNamesConstants.AppendFloatSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[APPEND_FLOAT_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[APPEND_FLOAT_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_double :
+ if ((index = wellKnownMethods[APPEND_DOUBLE_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangStringBuffer();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[APPEND_DOUBLE_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.Append);
+ int typeIndex = literalIndex(QualifiedNamesConstants.AppendDoubleSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[APPEND_DOUBLE_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[APPEND_DOUBLE_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_char :
+ if ((index = wellKnownMethods[APPEND_CHAR_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangStringBuffer();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[APPEND_CHAR_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.Append);
+ int typeIndex = literalIndex(QualifiedNamesConstants.AppendCharSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[APPEND_CHAR_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[APPEND_CHAR_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_boolean :
+ if ((index = wellKnownMethods[APPEND_BOOLEAN_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangStringBuffer();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[APPEND_BOOLEAN_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.Append);
+ int typeIndex = literalIndex(QualifiedNamesConstants.AppendBooleanSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[APPEND_BOOLEAN_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[APPEND_BOOLEAN_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_Object :
+ if ((index = wellKnownMethods[APPEND_OBJECT_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangStringBuffer();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[APPEND_OBJECT_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.Append);
+ int typeIndex = literalIndex(QualifiedNamesConstants.AppendObjectSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[APPEND_OBJECT_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[APPEND_OBJECT_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_String :
+ case T_null :
+ if ((index = wellKnownMethods[APPEND_STRING_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangStringBuffer();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[APPEND_STRING_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.Append);
+ int typeIndex = literalIndex(QualifiedNamesConstants.AppendStringSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[APPEND_STRING_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[APPEND_STRING_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangStringBufferConstructor() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[STRINGBUFFER_STRING_CONSTR_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangStringBuffer();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[STRING_CONSTR_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.Init);
+ int typeIndex =
+ literalIndex(QualifiedNamesConstants.StringConstructorSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[STRING_CONSTR_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[STRINGBUFFER_STRING_CONSTR_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangStringBufferDefaultConstructor() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[STRINGBUFFER_DEFAULT_CONSTR_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangStringBuffer();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[DEFAULT_CONSTR_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.Init);
+ int typeIndex =
+ literalIndex(QualifiedNamesConstants.DefaultConstructorSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[DEFAULT_CONSTR_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[STRINGBUFFER_DEFAULT_CONSTR_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangStringBufferToString() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[STRINGBUFFER_TOSTRING_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangStringBuffer();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[TOSTRING_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.ToString);
+ int typeIndex = literalIndex(QualifiedNamesConstants.ToStringSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[TOSTRING_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[STRINGBUFFER_TOSTRING_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangStringIntern() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[STRING_INTERN_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangString();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[INTERN_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.Intern);
+ int typeIndex = literalIndex(QualifiedNamesConstants.InternSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[INTERN_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[STRING_INTERN_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangStringValueOf(int typeID) {
+ int index = 0;
+ int nameAndTypeIndex = 0;
+ int classIndex = literalIndexForJavaLangString();
+ switch (typeID) {
+ case T_int :
+ case T_byte :
+ case T_short :
+ if ((index = wellKnownMethods[VALUEOF_INT_METHOD]) == 0) {
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[VALUEOF_INT_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.ValueOf);
+ int typeIndex = literalIndex(QualifiedNamesConstants.ValueOfIntSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[VALUEOF_INT_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[VALUEOF_INT_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_long :
+ if ((index = wellKnownMethods[VALUEOF_LONG_METHOD]) == 0) {
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[VALUEOF_LONG_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.ValueOf);
+ int typeIndex = literalIndex(QualifiedNamesConstants.ValueOfLongSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[VALUEOF_LONG_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[VALUEOF_LONG_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_float :
+ if ((index = wellKnownMethods[VALUEOF_FLOAT_METHOD]) == 0) {
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[VALUEOF_FLOAT_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.ValueOf);
+ int typeIndex = literalIndex(QualifiedNamesConstants.ValueOfFloatSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[VALUEOF_FLOAT_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[VALUEOF_FLOAT_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_double :
+ if ((index = wellKnownMethods[VALUEOF_DOUBLE_METHOD]) == 0) {
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[VALUEOF_DOUBLE_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.ValueOf);
+ int typeIndex = literalIndex(QualifiedNamesConstants.ValueOfDoubleSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[VALUEOF_DOUBLE_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[VALUEOF_DOUBLE_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_char :
+ if ((index = wellKnownMethods[VALUEOF_CHAR_METHOD]) == 0) {
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[VALUEOF_CHAR_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.ValueOf);
+ int typeIndex = literalIndex(QualifiedNamesConstants.ValueOfCharSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[VALUEOF_CHAR_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[VALUEOF_CHAR_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_boolean :
+ if ((index = wellKnownMethods[VALUEOF_BOOLEAN_METHOD]) == 0) {
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[VALUEOF_BOOLEAN_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.ValueOf);
+ int typeIndex = literalIndex(QualifiedNamesConstants.ValueOfBooleanSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[VALUEOF_BOOLEAN_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[VALUEOF_BOOLEAN_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_Object :
+ if ((index = wellKnownMethods[VALUEOF_OBJECT_METHOD]) == 0) {
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[VALUEOF_OBJECT_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.ValueOf);
+ int typeIndex = literalIndex(QualifiedNamesConstants.ValueOfObjectSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[VALUEOF_OBJECT_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[VALUEOF_OBJECT_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param TypeBinding aTypeBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangSystem() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_SYSTEM_TYPE]) == 0) {
+ int nameIndex;
+ // The entry doesn't exit yet
+ nameIndex =
+ literalIndex(QualifiedNamesConstants.JavaLangSystemConstantPoolName);
+ index = wellKnownTypes[JAVA_LANG_SYSTEM_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangSystemExitInt() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[SYSTEM_EXIT_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangSystem();
+ if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[EXIT_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.Exit);
+ int typeIndex = literalIndex(QualifiedNamesConstants.ExitIntSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[EXIT_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[SYSTEM_EXIT_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool
+ * corresponding to the field binding aFieldBinding.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangSystemOut() {
+ int index;
+ if ((index = wellKnownFields[OUT_SYSTEM_FIELD]) == 0) {
+ int nameAndTypeIndex;
+ int classIndex;
+ // The entry doesn't exit yet
+ classIndex = literalIndexForJavaLangSystem();
+ if ((nameAndTypeIndex = wellKnownMethodNameAndTypes[OUT_SYSTEM_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.Out);
+ int typeIndex =
+ literalIndex(QualifiedNamesConstants.JavaIoPrintStreamSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[OUT_SYSTEM_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownFields[OUT_SYSTEM_FIELD] = currentIndex++;
+ writeU1(FieldRefTag);
+ writeU2(classIndex);
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param TypeBinding aTypeBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangThrowable() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_THROWABLE_TYPE]) == 0) {
+ int nameIndex;
+ // The entry doesn't exit yet
+ nameIndex =
+ literalIndex(QualifiedNamesConstants.JavaLangThrowableConstantPoolName);
+ index = wellKnownTypes[JAVA_LANG_THROWABLE_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangThrowableGetMessage() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[THROWABLE_GETMESSAGE_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangThrowable();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GETMESSAGE_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.GetMessage);
+ int typeIndex = literalIndex(QualifiedNamesConstants.GetMessageSignature);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GETMESSAGE_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[THROWABLE_GETMESSAGE_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param TypeBinding aTypeBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangVoid() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_VOID_TYPE]) == 0) {
+ int nameIndex;
+ // The entry doesn't exit yet
+ nameIndex = literalIndex(QualifiedNamesConstants.JavaLangVoidConstantPoolName);
+ index = wellKnownTypes[JAVA_LANG_VOID_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool
+ * corresponding to the field binding aFieldBinding.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangVoidTYPE() {
+ int index;
+ if ((index = wellKnownFields[TYPE_VOID_FIELD]) == 0) {
+ int nameAndTypeIndex;
+ int classIndex;
+ // The entry doesn't exit yet
+ classIndex = literalIndexForJavaLangVoid();
+ if ((nameAndTypeIndex =
+ wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(QualifiedNamesConstants.TYPE);
+ int typeIndex = literalIndex(QualifiedNamesConstants.JavaLangClassSignature);
+ nameAndTypeIndex =
+ wellKnownFieldNameAndTypes[TYPE_JAVALANGCLASS_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownFields[TYPE_VOID_FIELD] = currentIndex++;
+ writeU1(FieldRefTag);
+ writeU2(classIndex);
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param char[] stringName
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForLdc(char[] stringCharArray) {
+ int index;
+ if ((index = stringCache.get(stringCharArray)) < 0) {
+ int stringIndex;
+ // The entry doesn't exit yet
+ if ((stringIndex = UTF8Cache.get(stringCharArray)) < 0) {
+ // The entry doesn't exit yet
+ // Write the tag first
+ writeU1(Utf8Tag);
+ // Then the size of the stringName array
+ int savedCurrentOffset = currentOffset;
+ if (currentOffset + 2 >= poolContent.length) {
+ // we need to resize the poolContent array because we won't have
+ // enough space to write the length
+ int length = poolContent.length;
+ System.arraycopy(
+ poolContent,
+ 0,
+ (poolContent = new byte[length + CONSTANTPOOL_GROW_SIZE]),
+ 0,
+ length);
+ }
+ currentOffset += 2;
+ int length = 0;
+ for (int i = 0; i < stringCharArray.length; i++) {
+ char current = stringCharArray[i];
+ if ((current >= 0x0001) && (current <= 0x007F)) {
+ // we only need one byte: ASCII table
+ writeU1(current);
+ length++;
+ } else
+ if (current > 0x07FF) {
+ // we need 3 bytes
+ length += 3;
+ writeU1(0xE0 | ((current >> 12) & 0x0F)); // 0xE0 = 1110 0000
+ writeU1(0x80 | ((current >> 6) & 0x3F)); // 0x80 = 1000 0000
+ writeU1(0x80 | (current & 0x3F)); // 0x80 = 1000 0000
+ } else {
+ // we can be 0 or between 0x0080 and 0x07FF
+ // In that case we only need 2 bytes
+ length += 2;
+ writeU1(0xC0 | ((current >> 6) & 0x1F)); // 0xC0 = 1100 0000
+ writeU1(0x80 | (current & 0x3F)); // 0x80 = 1000 0000
+ }
+ }
+ if (length >= 65535) {
+ currentOffset = savedCurrentOffset - 1;
+ return -1;
+ }
+ stringIndex = UTF8Cache.put(stringCharArray, currentIndex++);
+ // Now we know the length that we have to write in the constant pool
+ // we use savedCurrentOffset to do that
+ if (length > 65535) {
+ return 0;
+ }
+ poolContent[savedCurrentOffset] = (byte) (length >> 8);
+ poolContent[savedCurrentOffset + 1] = (byte) length;
+ }
+ index = stringCache.put(stringCharArray, currentIndex++);
+ // Write the tag first
+ writeU1(StringTag);
+ // Then the string index
+ writeU2(stringIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding
+ * nameAndType constant with nameIndex, typeIndex.
+ *
+ * @param int nameIndex
+ * @param int nameIndex
+ * @param org.eclipse.jdt.internal.compiler.lookup.MethodBinding a methodBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForMethods(
+ int nameIndex,
+ int typeIndex,
+ MethodBinding key) {
+ int index;
+ int indexOfWellKnownMethodNameAndType;
+ if ((indexOfWellKnownMethodNameAndType =
+ indexOfWellKnownMethodNameAndType(key))
+ == -1) {
+ // check if the entry exists
+ if ((index = nameAndTypeCacheForMethods.get(key)) == -1) {
+ // The entry doesn't exit yet
+ index = nameAndTypeCacheForMethods.put(key, currentIndex++);
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ } else {
+ if ((index = wellKnownMethodNameAndTypes[indexOfWellKnownMethodNameAndType])
+ == 0) {
+ index =
+ wellKnownMethodNameAndTypes[indexOfWellKnownMethodNameAndType] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ }
+ return index;
+ }
+
+ /**
+ * This method is used to clean the receiver in case of a clinit header is generated, but the
+ * clinit has no code.
+ * This implementation assumes that the clinit is the first method to be generated.
+ * @see org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.addClinit()
+ */
+ public void resetForClinit(int constantPoolIndex, int constantPoolOffset) {
+ currentIndex = constantPoolIndex;
+ currentOffset = constantPoolOffset;
+ if (UTF8Cache.get(AttributeNamesConstants.CodeName) >= constantPoolIndex) {
+ UTF8Cache.remove(AttributeNamesConstants.CodeName);
+ }
+ if (UTF8Cache.get(QualifiedNamesConstants.ClinitSignature)
+ >= constantPoolIndex) {
+ UTF8Cache.remove(QualifiedNamesConstants.ClinitSignature);
+ }
+ if (UTF8Cache.get(QualifiedNamesConstants.Clinit) >= constantPoolIndex) {
+ UTF8Cache.remove(QualifiedNamesConstants.Clinit);
+ }
+ }
+
+ /**
+ * Write a unsigned byte into the byte array
+ *
+ * @param <CODE>int</CODE> The value to write into the byte array
+ */
+ protected final void writeU1(int value) {
+ try {
+ poolContent[currentOffset++] = (byte) value;
+ } catch (IndexOutOfBoundsException e) {
+ //currentOffset has been ++ already (see the -1)
+ int length = poolContent.length;
+ System.arraycopy(
+ poolContent,
+ 0,
+ (poolContent = new byte[length + CONSTANTPOOL_GROW_SIZE]),
+ 0,
+ length);
+ poolContent[currentOffset - 1] = (byte) value;
+ }
+ }
+
+ /**
+ * Write a unsigned byte into the byte array
+ *
+ * @param <CODE>int</CODE> The value to write into the byte array
+ */
+ protected final void writeU2(int value) {
+ //first byte
+ try {
+ poolContent[currentOffset++] = (byte) (value >> 8);
+ } catch (IndexOutOfBoundsException e) {
+ //currentOffset has been ++ already (see the -1)
+ int length = poolContent.length;
+ System.arraycopy(
+ poolContent,
+ 0,
+ (poolContent = new byte[length + CONSTANTPOOL_GROW_SIZE]),
+ 0,
+ length);
+ poolContent[currentOffset - 1] = (byte) (value >> 8);
+ }
+ try {
+ poolContent[currentOffset++] = (byte) value;
+ } catch (IndexOutOfBoundsException e) {
+ //currentOffset has been ++ already (see the -1)
+ int length = poolContent.length;
+ System.arraycopy(
+ poolContent,
+ 0,
+ (poolContent = new byte[length + CONSTANTPOOL_GROW_SIZE]),
+ 0,
+ length);
+ poolContent[currentOffset - 1] = (byte) value;
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/DoubleCache.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/DoubleCache.java
new file mode 100644
index 0000000000..327124b31a
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/DoubleCache.java
@@ -0,0 +1,147 @@
+package org.eclipse.jdt.internal.compiler.codegen;
+
+public class DoubleCache {
+ private double keyTable[];
+ private int valueTable[];
+ private int elementSize;
+ /**
+ * Constructs a new, empty hashtable. A default capacity and
+ * load factor is used. Note that the hashtable will automatically
+ * grow when it gets full.
+ */
+ public DoubleCache() {
+ this(13);
+ }
+
+ /**
+ * Constructs a new, empty hashtable with the specified initial
+ * capacity.
+ * @param initialCapacity int
+ * the initial number of buckets
+ */
+ public DoubleCache(int initialCapacity) {
+ elementSize = 0;
+ keyTable = new double[initialCapacity];
+ valueTable = new int[initialCapacity];
+ }
+
+ /**
+ * Clears the hash table so that it has no more elements in it.
+ */
+ public void clear() {
+ for (int i = keyTable.length; --i >= 0;) {
+ keyTable[i] = 0.0;
+ valueTable[i] = 0;
+ }
+ elementSize = 0;
+ }
+
+ /** Returns true if the collection contains an element for the key.
+ *
+ * @param key <CODE>double</CODE> the key that we are looking for
+ * @return boolean
+ * @see ConstantPoolCache#contains
+ */
+ public boolean containsKey(double key) {
+ if (key == 0.0) {
+ for (int i = 0, max = elementSize; i < max; i++) {
+ if (keyTable[i] == 0.0) {
+ long value1 = Double.doubleToLongBits(key);
+ long value2 = Double.doubleToLongBits(keyTable[i]);
+ if (value1 == -9223372036854775808L && value2 == -9223372036854775808L)
+ return true;
+ if (value1 == 0 && value2 == 0)
+ return true;
+ }
+ }
+ } else {
+ for (int i = 0, max = elementSize; i < max; i++) {
+ if (keyTable[i] == key) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /** Gets the object associated with the specified key in the
+ * hashtable.
+ * @param key <CODE>double</CODE> the specified key
+ * @return int the element for the key or -1 if the key is not
+ * defined in the hash table.
+ * @see ConstantPoolCache#put
+ */
+ public int get(double key) {
+ if (key == 0.0) {
+ for (int i = 0, max = elementSize; i < max; i++) {
+ if (keyTable[i] == 0.0) {
+ long value1 = Double.doubleToLongBits(key);
+ long value2 = Double.doubleToLongBits(keyTable[i]);
+ if (value1 == -9223372036854775808L && value2 == -9223372036854775808L)
+ return valueTable[i];
+ if (value1 == 0 && value2 == 0)
+ return valueTable[i];
+ }
+ }
+ } else {
+ for (int i = 0, max = elementSize; i < max; i++) {
+ if (keyTable[i] == key) {
+ return valueTable[i];
+ }
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Puts the specified element into the hashtable, using the specified
+ * key. The element may be retrieved by doing a get() with the same key.
+ *
+ * @param key <CODE>double</CODE> the specified key in the hashtable
+ * @param value <CODE>int</CODE> the specified element
+ * @return int value
+ */
+ public int put(double key, int value) {
+ if (elementSize == keyTable.length) {
+ // resize
+ System.arraycopy(
+ keyTable,
+ 0,
+ (keyTable = new double[elementSize * 2]),
+ 0,
+ elementSize);
+ System.arraycopy(
+ valueTable,
+ 0,
+ (valueTable = new int[elementSize * 2]),
+ 0,
+ elementSize);
+ }
+ keyTable[elementSize] = key;
+ valueTable[elementSize] = value;
+ elementSize++;
+ return value;
+ }
+
+ /**
+ * Converts to a rather lengthy String.
+ *
+ * return String the ascii representation of the receiver
+ */
+ public String toString() {
+ int max = elementSize;
+ StringBuffer buf = new StringBuffer();
+ buf.append("{");
+ for (int i = 0; i < max; ++i) {
+ if ((keyTable[i] != 0) || ((keyTable[i] == 0) && (valueTable[i] != 0))) {
+ buf.append(keyTable[i]).append("->").append(valueTable[i]);
+ }
+ if (i < max) {
+ buf.append(", ");
+ }
+ }
+ buf.append("}");
+ return buf.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ExceptionLabel.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ExceptionLabel.java
new file mode 100644
index 0000000000..fe761760e0
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ExceptionLabel.java
@@ -0,0 +1,34 @@
+package org.eclipse.jdt.internal.compiler.codegen;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class ExceptionLabel extends Label {
+ public int start = POS_NOT_SET;
+ public int end = POS_NOT_SET;
+ public TypeBinding exceptionType;
+ public ExceptionLabel(CodeStream codeStream, TypeBinding exceptionType) {
+ super(codeStream);
+ this.exceptionType = exceptionType;
+ this.start = codeStream.position;
+ }
+
+ public boolean isStandardLabel() {
+ return false;
+ }
+
+ public void place() {
+ // register the handler inside the codeStream then normal place
+ codeStream.registerExceptionHandler(this);
+ super.place();
+
+ }
+
+ public void placeEnd() {
+ end = codeStream.position;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/FieldNameAndTypeCache.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/FieldNameAndTypeCache.java
new file mode 100644
index 0000000000..458dba9df2
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/FieldNameAndTypeCache.java
@@ -0,0 +1,172 @@
+package org.eclipse.jdt.internal.compiler.codegen;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class FieldNameAndTypeCache {
+ public FieldBinding keyTable[];
+ public int valueTable[];
+ int elementSize;
+ int threshold;
+ /**
+ * Constructs a new, empty hashtable. A default capacity is used.
+ * Note that the hashtable will automatically grow when it gets full.
+ */
+ public FieldNameAndTypeCache() {
+ this(13);
+ }
+
+ /**
+ * Constructs a new, empty hashtable with the specified initial
+ * capacity.
+ * @param initialCapacity int
+ * the initial number of buckets
+ */
+ public FieldNameAndTypeCache(int initialCapacity) {
+ this.elementSize = 0;
+ this.threshold = (int) (initialCapacity * 0.66f);
+ this.keyTable = new FieldBinding[initialCapacity];
+ this.valueTable = new int[initialCapacity];
+ }
+
+ /**
+ * Clears the hash table so that it has no more elements in it.
+ */
+ public void clear() {
+ for (int i = keyTable.length; --i >= 0;) {
+ keyTable[i] = null;
+ valueTable[i] = 0;
+ }
+ elementSize = 0;
+ }
+
+ /** Returns true if the collection contains an element for the key.
+ *
+ * @param char[] key the key that we are looking for
+ * @return boolean
+ * @see ConstantPoolCache#contains
+ */
+ public boolean containsKey(FieldBinding key) {
+ int index = hashCode(key);
+ while (keyTable[index] != null) {
+ if (equalsForNameAndType(keyTable[index], key))
+ return true;
+ index = (index + 1) % keyTable.length;
+ }
+ return false;
+ }
+
+ /**
+ * Return true if the two field binding are consider like equals.
+ */
+ public boolean equalsForNameAndType(FieldBinding field1, FieldBinding field2) {
+ return (
+ (field1.type == field2.type) && CharOperation.equals(field1.name, field2.name));
+ }
+
+ /** Gets the object associated with the specified key in the
+ * hashtable.
+ * @param key <CODE>char[]</CODE> the specified key
+ * @return int the element for the key or -1 if the key is not
+ * defined in the hash table.
+ * @see ConstantPoolCache#put
+ */
+ public int get(FieldBinding key) {
+ int index = hashCode(key);
+ while (keyTable[index] != null) {
+ if (equalsForNameAndType(keyTable[index], key))
+ return valueTable[index];
+ index = (index + 1) % keyTable.length;
+ }
+ return -1;
+ }
+
+ /**
+ * Return the hashcode for the key parameter
+ *
+ * @param key org.eclipse.jdt.internal.compiler.lookup.MethodBinding
+ * @return int
+ */
+ public int hashCode(FieldBinding key) {
+ return ((CharOperation.hashCode(key.name) + key.type.hashCode()) & 0x7FFFFFFF)
+ % keyTable.length;
+ }
+
+ /**
+ * Puts the specified element into the hashtable, using the specified
+ * key. The element may be retrieved by doing a get() with the same key.
+ * The key and the element cannot be null.
+ *
+ * @param key <CODE>Object</CODE> the specified key in the hashtable
+ * @param value <CODE>int</CODE> the specified element
+ * @see ConstantPoolCache#get
+ * @return int the old value of the key, or -1 if it did not have one.
+ */
+ public int put(FieldBinding key, int value) {
+ int index = hashCode(key);
+ while (keyTable[index] != null) {
+ if (equalsForNameAndType(keyTable[index], key))
+ return valueTable[index] = value;
+ index = (index + 1) % keyTable.length;
+ }
+ keyTable[index] = key;
+ valueTable[index] = value;
+
+ // assumes the threshold is never equal to the size of the table
+ if (++elementSize > threshold)
+ rehash();
+ return value;
+ }
+
+ /**
+ * Rehashes the content of the table into a bigger table.
+ * This method is called automatically when the hashtable's
+ * size exceeds the threshold.
+ */
+ private void rehash() {
+ FieldNameAndTypeCache newHashtable =
+ new FieldNameAndTypeCache(keyTable.length * 2);
+ for (int i = keyTable.length; --i >= 0;)
+ if (keyTable[i] != null)
+ newHashtable.put(keyTable[i], valueTable[i]);
+
+ this.keyTable = newHashtable.keyTable;
+ this.valueTable = newHashtable.valueTable;
+ this.threshold = newHashtable.threshold;
+ }
+
+ /**
+ * Returns the number of elements contained in the hashtable.
+ *
+ * @return <CODE>int</CODE> The size of the table
+ */
+ public int size() {
+ return elementSize;
+ }
+
+ /**
+ * Converts to a rather lengthy String.
+ *
+ * return String the ascii representation of the receiver
+ */
+ public String toString() {
+ int max = size();
+ StringBuffer buf = new StringBuffer();
+ buf.append("{");
+ for (int i = 0; i < max; ++i) {
+ if (keyTable[i] != null) {
+ buf.append(keyTable[i]).append("->").append(valueTable[i]);
+ }
+ if (i < max) {
+ buf.append(", ");
+ }
+ }
+ buf.append("}");
+ return buf.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/FloatCache.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/FloatCache.java
new file mode 100644
index 0000000000..340e600060
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/FloatCache.java
@@ -0,0 +1,147 @@
+package org.eclipse.jdt.internal.compiler.codegen;
+
+public class FloatCache {
+ private float keyTable[];
+ private int valueTable[];
+ private int elementSize;
+ /**
+ * Constructs a new, empty hashtable. A default capacity and
+ * load factor is used. Note that the hashtable will automatically
+ * grow when it gets full.
+ */
+ public FloatCache() {
+ this(13);
+ }
+
+ /**
+ * Constructs a new, empty hashtable with the specified initial
+ * capacity.
+ * @param initialCapacity int
+ * the initial number of buckets
+ */
+ public FloatCache(int initialCapacity) {
+ elementSize = 0;
+ keyTable = new float[initialCapacity];
+ valueTable = new int[initialCapacity];
+ }
+
+ /**
+ * Clears the hash table so that it has no more elements in it.
+ */
+ public void clear() {
+ for (int i = keyTable.length; --i >= 0;) {
+ keyTable[i] = 0.0f;
+ valueTable[i] = 0;
+ }
+ elementSize = 0;
+ }
+
+ /** Returns true if the collection contains an element for the key.
+ *
+ * @param key <CODE>float</CODE> the key that we are looking for
+ * @return boolean
+ * @see ConstantPoolCache#contains
+ */
+ public boolean containsKey(float key) {
+ if (key == 0.0f) {
+ for (int i = 0, max = elementSize; i < max; i++) {
+ if (keyTable[i] == 0.0f) {
+ int value1 = Float.floatToIntBits(key);
+ int value2 = Float.floatToIntBits(keyTable[i]);
+ if (value1 == -2147483648 && value2 == -2147483648)
+ return true;
+ if (value1 == 0 && value2 == 0)
+ return true;
+ }
+ }
+ } else {
+ for (int i = 0, max = elementSize; i < max; i++) {
+ if (keyTable[i] == key) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /** Gets the object associated with the specified key in the
+ * hashtable.
+ * @param key <CODE>float</CODE> the specified key
+ * @return int the element for the key or -1 if the key is not
+ * defined in the hash table.
+ * @see ConstantPoolCache#put
+ */
+ public int get(float key) {
+ if (key == 0.0f) {
+ for (int i = 0, max = elementSize; i < max; i++) {
+ if (keyTable[i] == 0.0f) {
+ int value1 = Float.floatToIntBits(key);
+ int value2 = Float.floatToIntBits(keyTable[i]);
+ if (value1 == -2147483648 && value2 == -2147483648)
+ return valueTable[i];
+ if (value1 == 0 && value2 == 0)
+ return valueTable[i];
+ }
+ }
+ } else {
+ for (int i = 0, max = elementSize; i < max; i++) {
+ if (keyTable[i] == key) {
+ return valueTable[i];
+ }
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Puts the specified element into the hashtable, using the specified
+ * key. The element may be retrieved by doing a get() with the same key.
+ *
+ * @param key <CODE>float</CODE> the specified key in the hashtable
+ * @param value <CODE>int</CODE> the specified element
+ * @return int value
+ */
+ public int put(float key, int value) {
+ if (elementSize == keyTable.length) {
+ // resize
+ System.arraycopy(
+ keyTable,
+ 0,
+ (keyTable = new float[elementSize * 2]),
+ 0,
+ elementSize);
+ System.arraycopy(
+ valueTable,
+ 0,
+ (valueTable = new int[elementSize * 2]),
+ 0,
+ elementSize);
+ }
+ keyTable[elementSize] = key;
+ valueTable[elementSize] = value;
+ elementSize++;
+ return value;
+ }
+
+ /**
+ * Converts to a rather lengthy String.
+ *
+ * return String the ascii representation of the receiver
+ */
+ public String toString() {
+ int max = elementSize;
+ StringBuffer buf = new StringBuffer();
+ buf.append("{");
+ for (int i = 0; i < max; ++i) {
+ if ((keyTable[i] != 0) || ((keyTable[i] == 0) && (valueTable[i] != 0))) {
+ buf.append(keyTable[i]).append("->").append(valueTable[i]);
+ }
+ if (i < max) {
+ buf.append(", ");
+ }
+ }
+ buf.append("}");
+ return buf.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/IntegerCache.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/IntegerCache.java
new file mode 100644
index 0000000000..ff42997869
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/IntegerCache.java
@@ -0,0 +1,161 @@
+package org.eclipse.jdt.internal.compiler.codegen;
+
+public class IntegerCache {
+ public int keyTable[];
+ public int valueTable[];
+ int elementSize;
+ int threshold;
+ /**
+ * Constructs a new, empty hashtable. A default capacity and
+ * load factor is used. Note that the hashtable will automatically
+ * grow when it gets full.
+ */
+ public IntegerCache() {
+ this(13);
+ }
+
+ /**
+ * Constructs a new, empty hashtable with the specified initial
+ * capacity.
+ * @param initialCapacity int
+ * the initial number of buckets
+ */
+ public IntegerCache(int initialCapacity) {
+ elementSize = 0;
+ threshold = (int) (initialCapacity * 0.66);
+ keyTable = new int[initialCapacity];
+ valueTable = new int[initialCapacity];
+ }
+
+ /**
+ * Clears the hash table so that it has no more elements in it.
+ */
+ public void clear() {
+ for (int i = keyTable.length; --i >= 0;) {
+ keyTable[i] = 0;
+ valueTable[i] = 0;
+ }
+ elementSize = 0;
+ }
+
+ /** Returns true if the collection contains an element for the key.
+ *
+ * @param key <CODE>double</CODE> the key that we are looking for
+ * @return boolean
+ * @see ConstantPoolCache#contains
+ */
+ public boolean containsKey(int key) {
+ int index = hash(key);
+ while ((keyTable[index] != 0)
+ || ((keyTable[index] == 0) && (valueTable[index] != 0))) {
+ if (keyTable[index] == key)
+ return true;
+ index = (index + 1) % keyTable.length;
+ }
+ return false;
+ }
+
+ /** Gets the object associated with the specified key in the
+ * hashtable.
+ * @param key <CODE>double</CODE> the specified key
+ * @return int the element for the key or -1 if the key is not
+ * defined in the hash table.
+ * @see ConstantPoolCache#put
+ */
+ public int get(int key) {
+ int index = hash(key);
+ while ((keyTable[index] != 0)
+ || ((keyTable[index] == 0) && (valueTable[index] != 0))) {
+ if (keyTable[index] == key)
+ return valueTable[index];
+ index = (index + 1) % keyTable.length;
+ }
+ return -1;
+ }
+
+ /**
+ * Return a hashcode for the value of the key parameter.
+ * @param key int
+ * @return int the hash code corresponding to the key value
+ * @see ConstantPoolCache#put
+ */
+ public int hash(int key) {
+ return (key & 0x7FFFFFFF) % keyTable.length;
+ }
+
+ /**
+ * Puts the specified element into the hashtable, using the specified
+ * key. The element may be retrieved by doing a get() with the same key.
+ *
+ * @param key <CODE>int</CODE> the specified key in the hashtable
+ * @param value <CODE>int</CODE> the specified element
+ * @return int value
+ */
+ public int put(int key, int value) {
+ int index = hash(key);
+ while ((keyTable[index] != 0)
+ || ((keyTable[index] == 0) && (valueTable[index] != 0))) {
+ if (keyTable[index] == key)
+ return valueTable[index] = value;
+ index = (index + 1) % keyTable.length;
+ }
+ keyTable[index] = key;
+ valueTable[index] = value;
+
+ // assumes the threshold is never equal to the size of the table
+ if (++elementSize > threshold) {
+ rehash();
+ }
+ return value;
+ }
+
+ /**
+ * Rehashes the content of the table into a bigger table.
+ * This method is called automatically when the hashtable's
+ * size exceeds the threshold.
+ */
+ private void rehash() {
+ IntegerCache newHashtable = new IntegerCache(keyTable.length * 2);
+ for (int i = keyTable.length; --i >= 0;) {
+ int key = keyTable[i];
+ int value = valueTable[i];
+ if ((key != 0) || ((key == 0) && (value != 0))) {
+ newHashtable.put(key, value);
+ }
+ }
+ this.keyTable = newHashtable.keyTable;
+ this.valueTable = newHashtable.valueTable;
+ this.threshold = newHashtable.threshold;
+ }
+
+ /**
+ * Returns the number of elements contained in the hashtable.
+ *
+ * @return <CODE>int</CODE> The size of the table
+ */
+ public int size() {
+ return elementSize;
+ }
+
+ /**
+ * Converts to a rather lengthy String.
+ *
+ * return String the ascii representation of the receiver
+ */
+ public String toString() {
+ int max = size();
+ StringBuffer buf = new StringBuffer();
+ buf.append("{");
+ for (int i = 0; i < max; ++i) {
+ if ((keyTable[i] != 0) || ((keyTable[i] == 0) && (valueTable[i] != 0))) {
+ buf.append(keyTable[i]).append("->").append(valueTable[i]);
+ }
+ if (i < max) {
+ buf.append(", ");
+ }
+ }
+ buf.append("}");
+ return buf.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/Label.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/Label.java
new file mode 100644
index 0000000000..4a8b34de6c
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/Label.java
@@ -0,0 +1,239 @@
+package org.eclipse.jdt.internal.compiler.codegen;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+/**
+ * This type is a port of smalltalks JavaLabel
+ */
+public class Label {
+ public CodeStream codeStream;
+ final static int POS_NOT_SET = -1;
+ public int position = POS_NOT_SET;
+ // iPOS=POS_NOT_SET Then it's pos is not set.
+ int[] forwardReferences = new int[10]; // Add an overflow check here.
+ int forwardReferenceCount = 0;
+ public Label() {
+ }
+
+ /**
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ */
+ public Label(CodeStream codeStream) {
+ this.codeStream = codeStream;
+ }
+
+ /**
+ * Add a forward refrence for the array.
+ */
+ void addForwardReference(int iPos) {
+ int length;
+ if (forwardReferenceCount >= (length = forwardReferences.length))
+ System.arraycopy(
+ forwardReferences,
+ 0,
+ (forwardReferences = new int[2 * length]),
+ 0,
+ length);
+ forwardReferences[forwardReferenceCount++] = iPos;
+ }
+
+ /**
+ * Add a forward refrence for the array.
+ */
+ void appendForwardReferencesFrom(Label otherLabel) {
+ int otherCount = otherLabel.forwardReferenceCount;
+ if (otherCount == 0)
+ return;
+ int length = forwardReferences.length;
+ int neededSpace = otherCount + forwardReferenceCount;
+ if (neededSpace >= length) {
+ System.arraycopy(
+ forwardReferences,
+ 0,
+ (forwardReferences = new int[neededSpace]),
+ 0,
+ forwardReferenceCount);
+ }
+ // append other forward references at the end, so they will get updated as well
+ System.arraycopy(
+ otherLabel.forwardReferences,
+ 0,
+ forwardReferences,
+ forwardReferenceCount,
+ otherCount);
+ forwardReferenceCount = neededSpace;
+ }
+
+ /*
+ * Put down a refernece to the array at the location in the codestream.
+ */
+ void branch() {
+ if (position == POS_NOT_SET) {
+ addForwardReference(codeStream.position);
+ // Leave two bytes free to generate the jump afterwards
+ codeStream.position += 2;
+ codeStream.classFileOffset += 2;
+ } else { //Position is set. Write it!
+ codeStream.writeSignedShort((short) (position - codeStream.position + 1));
+ }
+ }
+
+ /*
+ * No support for wide branches yet
+ */
+ void branchWide() {
+ if (position == POS_NOT_SET) {
+ addForwardReference(codeStream.position);
+ // Leave 4 bytes free to generate the jump offset afterwards
+ codeStream.position += 4;
+ codeStream.classFileOffset += 4;
+ } else { //Position is set. Write it!
+ codeStream.writeSignedWord(position - codeStream.position + 1);
+ }
+ }
+
+ /**
+ * @return boolean
+ */
+ public boolean hasForwardReferences() {
+ return forwardReferenceCount != 0;
+ }
+
+ /*
+ * Some placed labels might be branching to a goto bytecode which we can optimize better.
+ */
+ public void inlineForwardReferencesFromLabelsTargeting(int gotoLocation) {
+ /*
+ Code required to optimized unreachable gotos.
+ public boolean isBranchTarget(int location) {
+ Label[] labels = codeStream.labels;
+ for (int i = codeStream.countLabels - 1; i >= 0; i--){
+ Label label = labels[i];
+ if ((label.position == location) && label.isStandardLabel()){
+ return true;
+ }
+ }
+ return false;
+ }
+ */
+
+ Label[] labels = codeStream.labels;
+ for (int i = codeStream.countLabels - 1; i >= 0; i--) {
+ Label label = labels[i];
+ if ((label.position == gotoLocation) && label.isStandardLabel()) {
+ this.appendForwardReferencesFrom(label);
+ /*
+ Code required to optimized unreachable gotos.
+ label.position = POS_NOT_SET;
+ */
+ } else {
+ break; // same target labels should be contiguous
+ }
+ }
+ }
+
+ public boolean isStandardLabel() {
+ return true;
+ }
+
+ /*
+ * Place the label. If we have forward references resolve them.
+ */
+ public void place() { // Currently lacking wide support.
+ if (position == POS_NOT_SET) {
+ position = codeStream.position;
+ codeStream.addLabel(this);
+ int oldPosition = position;
+ boolean optimizedBranch = false;
+ // TURNED OFF since fail on 1F4IRD9
+ if (forwardReferenceCount != 0) {
+ if (optimizedBranch =
+ (forwardReferences[forwardReferenceCount - 1] + 2 == position)
+ && (codeStream.bCodeStream[codeStream.classFileOffset - 3]
+ == CodeStream.OPC_goto)) {
+ codeStream.position = (position -= 3);
+ codeStream.classFileOffset -= 3;
+ forwardReferenceCount--;
+ // also update the PCs in the related debug attributes
+ /** OLD CODE
+ int index = codeStream.pcToSourceMapSize - 1;
+ while ((index >= 0) && (codeStream.pcToSourceMap[index][1] == oldPosition)) {
+ codeStream.pcToSourceMap[index--][1] = position;
+ }
+ */
+ // Beginning of new code
+ int index = codeStream.pcToSourceMapSize - 2;
+ if (codeStream.lastEntryPC == oldPosition) {
+ codeStream.lastEntryPC = position;
+ }
+ if ((index >= 0) && (codeStream.pcToSourceMap[index] == position)) {
+ codeStream.pcToSourceMapSize -= 2;
+ }
+ // end of new code
+ if (codeStream.generateLocalVariableTableAttributes) {
+ LocalVariableBinding locals[] = codeStream.locals;
+ for (int i = 0, max = locals.length; i < max; i++) {
+ LocalVariableBinding local = locals[i];
+ if ((local != null) && (local.initializationCount > 0)) {
+ if (local.initializationPCs[((local.initializationCount - 1) << 1) + 1]
+ == oldPosition) {
+ local.initializationPCs[((local.initializationCount - 1) << 1) + 1] = position;
+ }
+ }
+ }
+ }
+ }
+ }
+ for (int i = 0; i < forwardReferenceCount; i++) {
+ codeStream.writeSignedShort(
+ forwardReferences[i],
+ (short) (position - forwardReferences[i] + 1));
+ }
+ // For all labels placed at that position we check if we need to rewrite the jump
+ // offset. It is the case each time a label had a forward reference to the current position.
+ // Like we change the current position, we have to change the jump offset. See 1F4IRD9 for more details.
+ if (optimizedBranch) {
+ for (int i = 0; i < codeStream.countLabels; i++) {
+ Label label = codeStream.labels[i];
+ if (oldPosition == label.position) {
+ label.position = position;
+ if (label instanceof CaseLabel) {
+ int offset = position - ((CaseLabel) label).instructionPosition;
+ for (int j = 0; j < label.forwardReferenceCount; j++) {
+ int forwardPosition = label.forwardReferences[j];
+ codeStream.writeSignedWord(forwardPosition, offset);
+ }
+ } else {
+ for (int j = 0; j < label.forwardReferenceCount; j++) {
+ int forwardPosition = label.forwardReferences[j];
+ codeStream.writeSignedShort(
+ forwardPosition,
+ (short) (position - forwardPosition + 1));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Print out the receiver
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer("(position=");
+ buffer.append(position);
+ buffer.append(", forwards = [");
+ for (int i = 0; i < forwardReferenceCount - 1; i++)
+ buffer.append(forwardReferences[i] + ", ");
+ if (forwardReferenceCount >= 1)
+ buffer.append(forwardReferences[forwardReferenceCount - 1]);
+ buffer.append("] )");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/LongCache.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/LongCache.java
new file mode 100644
index 0000000000..eb1b12a75c
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/LongCache.java
@@ -0,0 +1,161 @@
+package org.eclipse.jdt.internal.compiler.codegen;
+
+public class LongCache {
+ public long keyTable[];
+ public int valueTable[];
+ int elementSize;
+ int threshold;
+ /**
+ * Constructs a new, empty hashtable. A default capacity and
+ * load factor is used. Note that the hashtable will automatically
+ * grow when it gets full.
+ */
+ public LongCache() {
+ this(13);
+ }
+
+ /**
+ * Constructs a new, empty hashtable with the specified initial
+ * capacity.
+ * @param initialCapacity int
+ * the initial number of buckets
+ */
+ public LongCache(int initialCapacity) {
+ elementSize = 0;
+ threshold = (int) (initialCapacity * 0.66);
+ keyTable = new long[initialCapacity];
+ valueTable = new int[initialCapacity];
+ }
+
+ /**
+ * Clears the hash table so that it has no more elements in it.
+ */
+ public void clear() {
+ for (int i = keyTable.length; --i >= 0;) {
+ keyTable[i] = 0;
+ valueTable[i] = 0;
+ }
+ elementSize = 0;
+ }
+
+ /** Returns true if the collection contains an element for the key.
+ *
+ * @param key <CODE>long</CODE> the key that we are looking for
+ * @return boolean
+ * @see ConstantPoolCache#contains
+ */
+ public boolean containsKey(long key) {
+ int index = hash(key);
+ while ((keyTable[index] != 0)
+ || ((keyTable[index] == 0) && (valueTable[index] != 0))) {
+ if (keyTable[index] == key)
+ return true;
+ index = (index + 1) % keyTable.length;
+ }
+ return false;
+ }
+
+ /** Gets the object associated with the specified key in the
+ * hashtable.
+ * @param key <CODE>long</CODE> the specified key
+ * @return int the element for the key or -1 if the key is not
+ * defined in the hash table.
+ * @see ConstantPoolCache#put
+ */
+ public int get(long key) {
+ int index = hash(key);
+ while ((keyTable[index] != 0)
+ || ((keyTable[index] == 0) && (valueTable[index] != 0))) {
+ if (keyTable[index] == key)
+ return valueTable[index];
+ index = (index + 1) % keyTable.length;
+ }
+ return -1;
+ }
+
+ /**
+ * Return a hashcode for the value of the key parameter.
+ * @param key long
+ * @return int the hash code corresponding to the key value
+ * @see ConstantPoolCache#put
+ */
+ public int hash(long key) {
+ return ((int) key & 0x7FFFFFFF) % keyTable.length;
+ }
+
+ /**
+ * Puts the specified element into the hashtable, using the specified
+ * key. The element may be retrieved by doing a get() with the same key.
+ *
+ * @param key <CODE>long</CODE> the specified key in the hashtable
+ * @param value <CODE>int</CODE> the specified element
+ * @return int value
+ */
+ public int put(long key, int value) {
+ int index = hash(key);
+ while ((keyTable[index] != 0)
+ || ((keyTable[index] == 0) && (valueTable[index] != 0))) {
+ if (keyTable[index] == key)
+ return valueTable[index] = value;
+ index = (index + 1) % keyTable.length;
+ }
+ keyTable[index] = key;
+ valueTable[index] = value;
+
+ // assumes the threshold is never equal to the size of the table
+ if (++elementSize > threshold) {
+ rehash();
+ }
+ return value;
+ }
+
+ /**
+ * Rehashes the content of the table into a bigger table.
+ * This method is called automatically when the hashtable's
+ * size exceeds the threshold.
+ */
+ private void rehash() {
+ LongCache newHashtable = new LongCache(keyTable.length * 2);
+ for (int i = keyTable.length; --i >= 0;) {
+ long key = keyTable[i];
+ int value = valueTable[i];
+ if ((key != 0) || ((key == 0) && (value != 0))) {
+ newHashtable.put(key, value);
+ }
+ }
+ this.keyTable = newHashtable.keyTable;
+ this.valueTable = newHashtable.valueTable;
+ this.threshold = newHashtable.threshold;
+ }
+
+ /**
+ * Returns the number of elements contained in the hashtable.
+ *
+ * @return <CODE>int</CODE> The size of the table
+ */
+ public int size() {
+ return elementSize;
+ }
+
+ /**
+ * Converts to a rather lengthy String.
+ *
+ * return String the ascii representation of the receiver
+ */
+ public String toString() {
+ int max = size();
+ StringBuffer buf = new StringBuffer();
+ buf.append("{");
+ for (int i = 0; i < max; ++i) {
+ if ((keyTable[i] != 0) || ((keyTable[i] == 0) && (valueTable[i] != 0))) {
+ buf.append(keyTable[i]).append("->").append(valueTable[i]);
+ }
+ if (i < max) {
+ buf.append(", ");
+ }
+ }
+ buf.append("}");
+ return buf.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/MethodNameAndTypeCache.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/MethodNameAndTypeCache.java
new file mode 100644
index 0000000000..b5c047e315
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/MethodNameAndTypeCache.java
@@ -0,0 +1,174 @@
+package org.eclipse.jdt.internal.compiler.codegen;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class MethodNameAndTypeCache {
+ public MethodBinding keyTable[];
+ public int valueTable[];
+ int elementSize;
+ int threshold;
+ /**
+ * Constructs a new, empty hashtable. A default capacity is used.
+ * Note that the hashtable will automatically grow when it gets full.
+ */
+ public MethodNameAndTypeCache() {
+ this(13);
+ }
+
+ /**
+ * Constructs a new, empty hashtable with the specified initial
+ * capacity.
+ * @param initialCapacity int
+ * the initial number of buckets
+ */
+ public MethodNameAndTypeCache(int initialCapacity) {
+ this.elementSize = 0;
+ this.threshold = (int) (initialCapacity * 0.66f);
+ this.keyTable = new MethodBinding[initialCapacity];
+ this.valueTable = new int[initialCapacity];
+ }
+
+ /**
+ * Clears the hash table so that it has no more elements in it.
+ */
+ public void clear() {
+ for (int i = keyTable.length; --i >= 0;) {
+ keyTable[i] = null;
+ valueTable[i] = 0;
+ }
+ elementSize = 0;
+ }
+
+ /** Returns true if the collection contains an element for the key.
+ *
+ * @param char[] key the key that we are looking for
+ * @return boolean
+ * @see ConstantPoolCache#contains
+ */
+ public boolean containsKey(MethodBinding key) {
+ int index = hashCode(key);
+ while (keyTable[index] != null) {
+ if (equalsForNameAndType(keyTable[index], key))
+ return true;
+ index = (index + 1) % keyTable.length;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the two methodBinding are consider to be equal for the name and type
+ * purpose
+ */
+ public boolean equalsForNameAndType(
+ MethodBinding method1,
+ MethodBinding method2) {
+ return CharOperation.equals(method1.selector, method2.selector)
+ && CharOperation.equals(method1.signature(), method2.signature());
+ }
+
+ /** Gets the object associated with the specified key in the
+ * hashtable.
+ * @param key <CODE>char[]</CODE> the specified key
+ * @return int the element for the key or -1 if the key is not
+ * defined in the hash table.
+ * @see ConstantPoolCache#put
+ */
+ public int get(MethodBinding key) {
+ int index = hashCode(key);
+ while (keyTable[index] != null) {
+ if (equalsForNameAndType(keyTable[index], key))
+ return valueTable[index];
+ index = (index + 1) % keyTable.length;
+ }
+ return -1;
+ }
+
+ /**
+ * Return the hashcode for the key parameter
+ *
+ * @param key org.eclipse.jdt.internal.compiler.lookup.MethodBinding
+ * @return int
+ */
+ public int hashCode(MethodBinding key) {
+ return CharOperation.hashCode(key.selector) % keyTable.length;
+ }
+
+ /**
+ * Puts the specified element into the hashtable, using the specified
+ * key. The element may be retrieved by doing a get() with the same key.
+ * The key and the element cannot be null.
+ *
+ * @param key <CODE>Object</CODE> the specified key in the hashtable
+ * @param value <CODE>int</CODE> the specified element
+ * @see ConstantPoolCache#get
+ * @return int the old value of the key, or -1 if it did not have one.
+ */
+ public int put(MethodBinding key, int value) {
+ int index = hashCode(key);
+ while (keyTable[index] != null) {
+ if (equalsForNameAndType(keyTable[index], key))
+ return valueTable[index] = value;
+ index = (index + 1) % keyTable.length;
+ }
+ keyTable[index] = key;
+ valueTable[index] = value;
+
+ // assumes the threshold is never equal to the size of the table
+ if (++elementSize > threshold)
+ rehash();
+ return value;
+ }
+
+ /**
+ * Rehashes the content of the table into a bigger table.
+ * This method is called automatically when the hashtable's
+ * size exceeds the threshold.
+ */
+ private void rehash() {
+ MethodNameAndTypeCache newHashtable =
+ new MethodNameAndTypeCache(keyTable.length * 2);
+ for (int i = keyTable.length; --i >= 0;)
+ if (keyTable[i] != null)
+ newHashtable.put(keyTable[i], valueTable[i]);
+
+ this.keyTable = newHashtable.keyTable;
+ this.valueTable = newHashtable.valueTable;
+ this.threshold = newHashtable.threshold;
+ }
+
+ /**
+ * Returns the number of elements contained in the hashtable.
+ *
+ * @return <CODE>int</CODE> The size of the table
+ */
+ public int size() {
+ return elementSize;
+ }
+
+ /**
+ * Converts to a rather lengthy String.
+ *
+ * return String the ascii representation of the receiver
+ */
+ public String toString() {
+ int max = size();
+ StringBuffer buf = new StringBuffer();
+ buf.append("{");
+ for (int i = 0; i < max; ++i) {
+ if (keyTable[i] != null) {
+ buf.append(keyTable[i]).append("->").append(valueTable[i]);
+ }
+ if (i < max) {
+ buf.append(", ");
+ }
+ }
+ buf.append("}");
+ return buf.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ObjectCache.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ObjectCache.java
new file mode 100644
index 0000000000..03b06e022a
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ObjectCache.java
@@ -0,0 +1,155 @@
+package org.eclipse.jdt.internal.compiler.codegen;
+
+public class ObjectCache {
+ public Object keyTable[];
+ public int valueTable[];
+ int elementSize;
+ int threshold;
+ /**
+ * Constructs a new, empty hashtable. A default capacity is used.
+ * Note that the hashtable will automatically grow when it gets full.
+ */
+ public ObjectCache() {
+ this(13);
+ }
+
+ /**
+ * Constructs a new, empty hashtable with the specified initial
+ * capacity.
+ * @param initialCapacity int
+ * the initial number of buckets
+ */
+ public ObjectCache(int initialCapacity) {
+ this.elementSize = 0;
+ this.threshold = (int) (initialCapacity * 0.66f);
+ this.keyTable = new Object[initialCapacity];
+ this.valueTable = new int[initialCapacity];
+ }
+
+ /**
+ * Clears the hash table so that it has no more elements in it.
+ */
+ public void clear() {
+ for (int i = keyTable.length; --i >= 0;) {
+ keyTable[i] = null;
+ valueTable[i] = 0;
+ }
+ elementSize = 0;
+ }
+
+ /** Returns true if the collection contains an element for the key.
+ *
+ * @param char[] key the key that we are looking for
+ * @return boolean
+ * @see ConstantPoolCache#contains
+ */
+ public boolean containsKey(Object key) {
+ int index = hashCode(key);
+ while (keyTable[index] != null) {
+ if (keyTable[index] == key)
+ return true;
+ index = (index + 1) % keyTable.length;
+ }
+ return false;
+ }
+
+ /** Gets the object associated with the specified key in the
+ * hashtable.
+ * @param key <CODE>char[]</CODE> the specified key
+ * @return int the element for the key or -1 if the key is not
+ * defined in the hash table.
+ * @see ConstantPoolCache#put
+ */
+ public int get(Object key) {
+ int index = hashCode(key);
+ while (keyTable[index] != null) {
+ if (keyTable[index] == key)
+ return valueTable[index];
+ index = (index + 1) % keyTable.length;
+ }
+ return -1;
+ }
+
+ /**
+ * Return the hashcode for the key parameter
+ *
+ * @param key org.eclipse.jdt.internal.compiler.lookup.MethodBinding
+ * @return int
+ */
+ public int hashCode(Object key) {
+ return (key.hashCode() & 0x7FFFFFFF) % keyTable.length;
+ }
+
+ /**
+ * Puts the specified element into the hashtable, using the specified
+ * key. The element may be retrieved by doing a get() with the same key.
+ * The key and the element cannot be null.
+ *
+ * @param key <CODE>Object</CODE> the specified key in the hashtable
+ * @param value <CODE>int</CODE> the specified element
+ * @see ConstantPoolCache#get
+ * @return int the old value of the key, or -1 if it did not have one.
+ */
+ public int put(Object key, int value) {
+ int index = hashCode(key);
+ while (keyTable[index] != null) {
+ if (keyTable[index] == key)
+ return valueTable[index] = value;
+ index = (index + 1) % keyTable.length;
+ }
+ keyTable[index] = key;
+ valueTable[index] = value;
+
+ // assumes the threshold is never equal to the size of the table
+ if (++elementSize > threshold)
+ rehash();
+ return value;
+ }
+
+ /**
+ * Rehashes the content of the table into a bigger table.
+ * This method is called automatically when the hashtable's
+ * size exceeds the threshold.
+ */
+ private void rehash() {
+ ObjectCache newHashtable = new ObjectCache(keyTable.length * 2);
+ for (int i = keyTable.length; --i >= 0;)
+ if (keyTable[i] != null)
+ newHashtable.put(keyTable[i], valueTable[i]);
+
+ this.keyTable = newHashtable.keyTable;
+ this.valueTable = newHashtable.valueTable;
+ this.threshold = newHashtable.threshold;
+ }
+
+ /**
+ * Returns the number of elements contained in the hashtable.
+ *
+ * @return <CODE>int</CODE> The size of the table
+ */
+ public int size() {
+ return elementSize;
+ }
+
+ /**
+ * Converts to a rather lengthy String.
+ *
+ * return String the ascii representation of the receiver
+ */
+ public String toString() {
+ int max = size();
+ StringBuffer buf = new StringBuffer();
+ buf.append("{");
+ for (int i = 0; i < max; ++i) {
+ if (keyTable[i] != null) {
+ buf.append(keyTable[i]).append("->").append(valueTable[i]);
+ }
+ if (i < max) {
+ buf.append(", ");
+ }
+ }
+ buf.append("}");
+ return buf.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/Opcodes.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/Opcodes.java
new file mode 100644
index 0000000000..224cdd1909
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/Opcodes.java
@@ -0,0 +1,206 @@
+package org.eclipse.jdt.internal.compiler.codegen;
+
+public interface Opcodes {
+
+ public static final byte OPC_nop = 0;
+ public static final byte OPC_aconst_null = 1;
+ public static final byte OPC_iconst_m1 = 2;
+ public static final byte OPC_iconst_0 = 3;
+ public static final byte OPC_iconst_1 = 4;
+ public static final byte OPC_iconst_2 = 5;
+ public static final byte OPC_iconst_3 = 6;
+ public static final byte OPC_iconst_4 = 7;
+ public static final byte OPC_iconst_5 = 8;
+ public static final byte OPC_lconst_0 = 9;
+ public static final byte OPC_lconst_1 = 10;
+ public static final byte OPC_fconst_0 = 11;
+ public static final byte OPC_fconst_1 = 12;
+ public static final byte OPC_fconst_2 = 13;
+ public static final byte OPC_dconst_0 = 14;
+ public static final byte OPC_dconst_1 = 15;
+ public static final byte OPC_bipush = 16;
+ public static final byte OPC_sipush = 17;
+ public static final byte OPC_ldc = 18;
+ public static final byte OPC_ldc_w = 19;
+ public static final byte OPC_ldc2_w = 20;
+ public static final byte OPC_iload = 21;
+ public static final byte OPC_lload = 22;
+ public static final byte OPC_fload = 23;
+ public static final byte OPC_dload = 24;
+ public static final byte OPC_aload = 25;
+ public static final byte OPC_iload_0 = 26;
+ public static final byte OPC_iload_1 = 27;
+ public static final byte OPC_iload_2 = 28;
+ public static final byte OPC_iload_3 = 29;
+ public static final byte OPC_lload_0 = 30;
+ public static final byte OPC_lload_1 = 31;
+ public static final byte OPC_lload_2 = 32;
+ public static final byte OPC_lload_3 = 33;
+ public static final byte OPC_fload_0 = 34;
+ public static final byte OPC_fload_1 = 35;
+ public static final byte OPC_fload_2 = 36;
+ public static final byte OPC_fload_3 = 37;
+ public static final byte OPC_dload_0 = 38;
+ public static final byte OPC_dload_1 = 39;
+ public static final byte OPC_dload_2 = 40;
+ public static final byte OPC_dload_3 = 41;
+ public static final byte OPC_aload_0 = 42;
+ public static final byte OPC_aload_1 = 43;
+ public static final byte OPC_aload_2 = 44;
+ public static final byte OPC_aload_3 = 45;
+ public static final byte OPC_iaload = 46;
+ public static final byte OPC_laload = 47;
+ public static final byte OPC_faload = 48;
+ public static final byte OPC_daload = 49;
+ public static final byte OPC_aaload = 50;
+ public static final byte OPC_baload = 51;
+ public static final byte OPC_caload = 52;
+ public static final byte OPC_saload = 53;
+ public static final byte OPC_istore = 54;
+ public static final byte OPC_lstore = 55;
+ public static final byte OPC_fstore = 56;
+ public static final byte OPC_dstore = 57;
+ public static final byte OPC_astore = 58;
+ public static final byte OPC_istore_0 = 59;
+ public static final byte OPC_istore_1 = 60;
+ public static final byte OPC_istore_2 = 61;
+ public static final byte OPC_istore_3 = 62;
+ public static final byte OPC_lstore_0 = 63;
+ public static final byte OPC_lstore_1 = 64;
+ public static final byte OPC_lstore_2 = 65;
+ public static final byte OPC_lstore_3 = 66;
+ public static final byte OPC_fstore_0 = 67;
+ public static final byte OPC_fstore_1 = 68;
+ public static final byte OPC_fstore_2 = 69;
+ public static final byte OPC_fstore_3 = 70;
+ public static final byte OPC_dstore_0 = 71;
+ public static final byte OPC_dstore_1 = 72;
+ public static final byte OPC_dstore_2 = 73;
+ public static final byte OPC_dstore_3 = 74;
+ public static final byte OPC_astore_0 = 75;
+ public static final byte OPC_astore_1 = 76;
+ public static final byte OPC_astore_2 = 77;
+ public static final byte OPC_astore_3 = 78;
+ public static final byte OPC_iastore = 79;
+ public static final byte OPC_lastore = 80;
+ public static final byte OPC_fastore = 81;
+ public static final byte OPC_dastore = 82;
+ public static final byte OPC_aastore = 83;
+ public static final byte OPC_bastore = 84;
+ public static final byte OPC_castore = 85;
+ public static final byte OPC_sastore = 86;
+ public static final byte OPC_pop = 87;
+ public static final byte OPC_pop2 = 88;
+ public static final byte OPC_dup = 89;
+ public static final byte OPC_dup_x1 = 90;
+ public static final byte OPC_dup_x2 = 91;
+ public static final byte OPC_dup2 = 92;
+ public static final byte OPC_dup2_x1 = 93;
+ public static final byte OPC_dup2_x2 = 94;
+ public static final byte OPC_swap = 95;
+ public static final byte OPC_iadd = 96;
+ public static final byte OPC_ladd = 97;
+ public static final byte OPC_fadd = 98;
+ public static final byte OPC_dadd = 99;
+ public static final byte OPC_isub = 100;
+ public static final byte OPC_lsub = 101;
+ public static final byte OPC_fsub = 102;
+ public static final byte OPC_dsub = 103;
+ public static final byte OPC_imul = 104;
+ public static final byte OPC_lmul = 105;
+ public static final byte OPC_fmul = 106;
+ public static final byte OPC_dmul = 107;
+ public static final byte OPC_idiv = 108;
+ public static final byte OPC_ldiv = 109;
+ public static final byte OPC_fdiv = 110;
+ public static final byte OPC_ddiv = 111;
+ public static final byte OPC_irem = 112;
+ public static final byte OPC_lrem = 113;
+ public static final byte OPC_frem = 114;
+ public static final byte OPC_drem = 115;
+ public static final byte OPC_ineg = 116;
+ public static final byte OPC_lneg = 117;
+ public static final byte OPC_fneg = 118;
+ public static final byte OPC_dneg = 119;
+ public static final byte OPC_ishl = 120;
+ public static final byte OPC_lshl = 121;
+ public static final byte OPC_ishr = 122;
+ public static final byte OPC_lshr = 123;
+ public static final byte OPC_iushr = 124;
+ public static final byte OPC_lushr = 125;
+ public static final byte OPC_iand = 126;
+ public static final byte OPC_land = 127;
+ public static final byte OPC_ior = (byte) 128;
+ public static final byte OPC_lor = (byte) 129;
+ public static final byte OPC_ixor = (byte) 130;
+ public static final byte OPC_lxor = (byte) 131;
+ public static final byte OPC_iinc = (byte) 132;
+ public static final byte OPC_i2l = (byte) 133;
+ public static final byte OPC_i2f = (byte) 134;
+ public static final byte OPC_i2d = (byte) 135;
+ public static final byte OPC_l2i = (byte) 136;
+ public static final byte OPC_l2f = (byte) 137;
+ public static final byte OPC_l2d = (byte) 138;
+ public static final byte OPC_f2i = (byte) 139;
+ public static final byte OPC_f2l = (byte) 140;
+ public static final byte OPC_f2d = (byte) 141;
+ public static final byte OPC_d2i = (byte) 142;
+ public static final byte OPC_d2l = (byte) 143;
+ public static final byte OPC_d2f = (byte) 144;
+ public static final byte OPC_i2b = (byte) 145;
+ public static final byte OPC_i2c = (byte) 146;
+ public static final byte OPC_i2s = (byte) 147;
+ public static final byte OPC_lcmp = (byte) 148;
+ public static final byte OPC_fcmpl = (byte) 149;
+ public static final byte OPC_fcmpg = (byte) 150;
+ public static final byte OPC_dcmpl = (byte) 151;
+ public static final byte OPC_dcmpg = (byte) 152;
+ public static final byte OPC_ifeq = (byte) 153;
+ public static final byte OPC_ifne = (byte) 154;
+ public static final byte OPC_iflt = (byte) 155;
+ public static final byte OPC_ifge = (byte) 156;
+ public static final byte OPC_ifgt = (byte) 157;
+ public static final byte OPC_ifle = (byte) 158;
+ public static final byte OPC_if_icmpeq = (byte) 159;
+ public static final byte OPC_if_icmpne = (byte) 160;
+ public static final byte OPC_if_icmplt = (byte) 161;
+ public static final byte OPC_if_icmpge = (byte) 162;
+ public static final byte OPC_if_icmpgt = (byte) 163;
+ public static final byte OPC_if_icmple = (byte) 164;
+ public static final byte OPC_if_acmpeq = (byte) 165;
+ public static final byte OPC_if_acmpne = (byte) 166;
+ public static final byte OPC_goto = (byte) 167;
+ public static final byte OPC_jsr = (byte) 168;
+ public static final byte OPC_ret = (byte) 169;
+ public static final byte OPC_tableswitch = (byte) 170;
+ public static final byte OPC_lookupswitch = (byte) 171;
+ public static final byte OPC_ireturn = (byte) 172;
+ public static final byte OPC_lreturn = (byte) 173;
+ public static final byte OPC_freturn = (byte) 174;
+ public static final byte OPC_dreturn = (byte) 175;
+ public static final byte OPC_areturn = (byte) 176;
+ public static final byte OPC_return = (byte) 177;
+ public static final byte OPC_getstatic = (byte) 178;
+ public static final byte OPC_putstatic = (byte) 179;
+ public static final byte OPC_getfield = (byte) 180;
+ public static final byte OPC_putfield = (byte) 181;
+ public static final byte OPC_invokevirtual = (byte) 182;
+ public static final byte OPC_invokespecial = (byte) 183;
+ public static final byte OPC_invokestatic = (byte) 184;
+ public static final byte OPC_invokeinterface = (byte) 185;
+ public static final byte OPC_new = (byte) 187;
+ public static final byte OPC_newarray = (byte) 188;
+ public static final byte OPC_anewarray = (byte) 189;
+ public static final byte OPC_arraylength = (byte) 190;
+ public static final byte OPC_athrow = (byte) 191;
+ public static final byte OPC_checkcast = (byte) 192;
+ public static final byte OPC_instanceof = (byte) 193;
+ public static final byte OPC_monitorenter = (byte) 194;
+ public static final byte OPC_monitorexit = (byte) 195;
+ public static final byte OPC_wide = (byte) 196;
+ public static final byte OPC_multianewarray = (byte) 197;
+ public static final byte OPC_ifnull = (byte) 198;
+ public static final byte OPC_ifnonnull = (byte) 199;
+ public static final byte OPC_goto_w = (byte) 200;
+ public static final byte OPC_jsr_w = (byte) 201;
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/QualifiedNamesConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/QualifiedNamesConstants.java
new file mode 100644
index 0000000000..34bbfd2b4a
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/QualifiedNamesConstants.java
@@ -0,0 +1,102 @@
+package org.eclipse.jdt.internal.compiler.codegen;
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+public interface QualifiedNamesConstants {
+ char[] JavaLangObjectConstantPoolName = "java/lang/Object".toCharArray();
+ char[] JavaLangStringConstantPoolName = "java/lang/String".toCharArray();
+ char[] JavaLangStringBufferConstantPoolName =
+ "java/lang/StringBuffer".toCharArray();
+ char[] JavaLangClassConstantPoolName = "java/lang/Class".toCharArray();
+ char[] JavaLangThrowableConstantPoolName = "java/lang/Throwable".toCharArray();
+ char[] JavaLangClassNotFoundExceptionConstantPoolName =
+ "java/lang/ClassNotFoundException".toCharArray();
+ char[] JavaLangNoClassDefFoundErrorConstantPoolName =
+ "java/lang/NoClassDefFoundError".toCharArray();
+ char[] JavaLangIntegerConstantPoolName = "java/lang/Integer".toCharArray();
+ char[] JavaLangFloatConstantPoolName = "java/lang/Float".toCharArray();
+ char[] JavaLangDoubleConstantPoolName = "java/lang/Double".toCharArray();
+ char[] JavaLangLongConstantPoolName = "java/lang/Long".toCharArray();
+ char[] JavaLangShortConstantPoolName = "java/lang/Short".toCharArray();
+ char[] JavaLangByteConstantPoolName = "java/lang/Byte".toCharArray();
+ char[] JavaLangCharacterConstantPoolName = "java/lang/Character".toCharArray();
+ char[] JavaLangVoidConstantPoolName = "java/lang/Void".toCharArray();
+ char[] JavaLangBooleanConstantPoolName = "java/lang/Boolean".toCharArray();
+ char[] JavaLangSystemConstantPoolName = "java/lang/System".toCharArray();
+ char[] JavaLangErrorConstantPoolName = "java/lang/Error".toCharArray();
+ char[] JavaLangExceptionConstantPoolName = "java/lang/Exception".toCharArray();
+ char[] JavaLangReflectConstructor =
+ "java/lang/reflect/Constructor".toCharArray();
+ char[] Append = new char[] { 'a', 'p', 'p', 'e', 'n', 'd' };
+ char[] ToString = new char[] { 't', 'o', 'S', 't', 'r', 'i', 'n', 'g' };
+ char[] Init = new char[] { '<', 'i', 'n', 'i', 't', '>' };
+ char[] Clinit = new char[] { '<', 'c', 'l', 'i', 'n', 'i', 't', '>' };
+ char[] ValueOf = new char[] { 'v', 'a', 'l', 'u', 'e', 'O', 'f' };
+ char[] ForName = new char[] { 'f', 'o', 'r', 'N', 'a', 'm', 'e' };
+ char[] GetMessage =
+ new char[] { 'g', 'e', 't', 'M', 'e', 's', 's', 'a', 'g', 'e' };
+ char[] NewInstance = "newInstance".toCharArray();
+ char[] GetConstructor = "getConstructor".toCharArray();
+ char[] Exit = new char[] { 'e', 'x', 'i', 't' };
+ char[] Intern = "intern".toCharArray();
+ char[] Out = new char[] { 'o', 'u', 't' };
+ char[] TYPE = new char[] { 'T', 'Y', 'P', 'E' };
+ char[] This = new char[] { 't', 'h', 'i', 's' };
+ char[] JavaLangClassSignature =
+ new char[] {
+ 'L',
+ 'j',
+ 'a',
+ 'v',
+ 'a',
+ '/',
+ 'l',
+ 'a',
+ 'n',
+ 'g',
+ '/',
+ 'C',
+ 'l',
+ 'a',
+ 's',
+ 's',
+ ';' };
+ char[] ForNameSignature = "(Ljava/lang/String;)Ljava/lang/Class;".toCharArray();
+ char[] GetMessageSignature = "()Ljava/lang/String;".toCharArray();
+ char[] GetConstructorSignature =
+ "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;".toCharArray();
+ char[] StringConstructorSignature = "(Ljava/lang/String;)V".toCharArray();
+ char[] NewInstanceSignature =
+ "([Ljava/lang/Object;)Ljava/lang/Object;".toCharArray();
+ char[] DefaultConstructorSignature = { '(', ')', 'V' };
+ char[] ClinitSignature = DefaultConstructorSignature;
+ char[] ToStringSignature = GetMessageSignature;
+ char[] InternSignature = GetMessageSignature;
+ char[] AppendIntSignature = "(I)Ljava/lang/StringBuffer;".toCharArray();
+ char[] AppendLongSignature = "(J)Ljava/lang/StringBuffer;".toCharArray();
+ char[] AppendFloatSignature = "(F)Ljava/lang/StringBuffer;".toCharArray();
+ char[] AppendDoubleSignature = "(D)Ljava/lang/StringBuffer;".toCharArray();
+ char[] AppendCharSignature = "(C)Ljava/lang/StringBuffer;".toCharArray();
+ char[] AppendBooleanSignature = "(Z)Ljava/lang/StringBuffer;".toCharArray();
+ char[] AppendObjectSignature =
+ "(Ljava/lang/Object;)Ljava/lang/StringBuffer;".toCharArray();
+ char[] AppendStringSignature =
+ "(Ljava/lang/String;)Ljava/lang/StringBuffer;".toCharArray();
+ char[] ValueOfObjectSignature =
+ "(Ljava/lang/Object;)Ljava/lang/String;".toCharArray();
+ char[] ValueOfIntSignature = "(I)Ljava/lang/String;".toCharArray();
+ char[] ValueOfLongSignature = "(J)Ljava/lang/String;".toCharArray();
+ char[] ValueOfCharSignature = "(C)Ljava/lang/String;".toCharArray();
+ char[] ValueOfBooleanSignature = "(Z)Ljava/lang/String;".toCharArray();
+ char[] ValueOfDoubleSignature = "(D)Ljava/lang/String;".toCharArray();
+ char[] ValueOfFloatSignature = "(F)Ljava/lang/String;".toCharArray();
+ char[] JavaIoPrintStreamSignature = "Ljava/io/PrintStream;".toCharArray();
+ char[] ExitIntSignature = new char[] { '(', 'I', ')', 'V' };
+ char[] ArrayJavaLangObjectConstantPoolName =
+ "[Ljava/lang/Object;".toCharArray();
+ char[] ArrayJavaLangClassConstantPoolName = "[Ljava/lang/Class;".toCharArray();
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryField.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryField.java
new file mode 100644
index 0000000000..3513d1d7da
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryField.java
@@ -0,0 +1,27 @@
+package org.eclipse.jdt.internal.compiler.env;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.impl.*;
+
+public interface IBinaryField extends IGenericField {
+ /**
+ *
+ * @return org.eclipse.jdt.internal.compiler.Constant
+ */
+ Constant getConstant();
+ /**
+ * Answer the resolved name of the receiver's type in the
+ * class file format as specified in section 4.3.2 of the Java 2 VM spec.
+ *
+ * For example:
+ * - java.lang.String is Ljava/lang/String;
+ * - an int is I
+ * - a 2 dimensional array of strings is [[Ljava/lang/String;
+ * - an array of floats is [F
+ */
+
+ char[] getTypeName();
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryMethod.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryMethod.java
new file mode 100644
index 0000000000..6892cc7ae9
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryMethod.java
@@ -0,0 +1,28 @@
+package org.eclipse.jdt.internal.compiler.env;
+
+public interface IBinaryMethod extends IGenericMethod {
+ /**
+ * Answer the resolved names of the exception types in the
+ * class file format as specified in section 4.2 of the Java 2 VM spec
+ * or null if the array is empty.
+ *
+ * For example, java.lang.String is java/lang/String.
+ */
+
+ char[][] getExceptionTypeNames();
+ /**
+ * Answer the receiver's method descriptor which describes the parameter &
+ * return types as specified in section 4.3.3 of the Java 2 VM spec.
+ *
+ * For example:
+ * - int foo(String) is (Ljava/lang/String;)I
+ * - Object[] foo(int) is (I)[Ljava/lang/Object;
+ */
+
+ char[] getMethodDescriptor();
+ /**
+ * Answer whether the receiver represents a class initializer method.
+ */
+
+ boolean isClinit();
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryNestedType.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryNestedType.java
new file mode 100644
index 0000000000..4d38cf1679
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryNestedType.java
@@ -0,0 +1,28 @@
+package org.eclipse.jdt.internal.compiler.env;
+
+public interface IBinaryNestedType {
+ /**
+ * Answer the resolved name of the enclosing type in the
+ * class file format as specified in section 4.2 of the Java 2 VM spec.
+ *
+ * For example, java.lang.String is java/lang/String.
+ */
+
+ char[] getEnclosingTypeName();
+ /**
+ * Answer an int whose bits are set according the access constants
+ * defined by the VM spec.
+ */
+
+ // We have added AccDeprecated & AccSynthetic.
+
+ int getModifiers();
+ /**
+ * Answer the resolved name of the member type in the
+ * class file format as specified in section 4.2 of the Java 2 VM spec.
+ *
+ * For example, p1.p2.A.M is p1/p2/A$M.
+ */
+
+ char[] getName();
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryType.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryType.java
new file mode 100644
index 0000000000..5f4f64b7ec
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryType.java
@@ -0,0 +1,65 @@
+package org.eclipse.jdt.internal.compiler.env;
+
+public interface IBinaryType extends IGenericType {
+
+ char[][] NoInterface = new char[0][];
+ IBinaryNestedType[] NoNestedType = new IBinaryNestedType[0];
+ IBinaryField[] NoField = new IBinaryField[0];
+ IBinaryMethod[] NoMethod = new IBinaryMethod[0];
+ /**
+ * Answer the resolved name of the enclosing type in the
+ * class file format as specified in section 4.2 of the Java 2 VM spec
+ * or null if the receiver is a top level type.
+ *
+ * For example, java.lang.String is java/lang/String.
+ */
+
+ char[] getEnclosingTypeName();
+ /**
+ * Answer the receiver's fields or null if the array is empty.
+ */
+
+ IBinaryField[] getFields();
+ /**
+ * Answer the resolved names of the receiver's interfaces in the
+ * class file format as specified in section 4.2 of the Java 2 VM spec
+ * or null if the array is empty.
+ *
+ * For example, java.lang.String is java/lang/String.
+ */
+
+ char[][] getInterfaceNames();
+ /**
+ * Answer the receiver's nested types or null if the array is empty.
+ *
+ * This nested type info is extracted from the inner class attributes.
+ * Ask the name environment to find a member type using its compound name.
+ */
+
+ // NOTE: The compiler examines the nested type info & ignores the local types
+ // so the local types do not have to be included.
+
+ IBinaryNestedType[] getMemberTypes();
+ /**
+ * Answer the receiver's methods or null if the array is empty.
+ */
+
+ IBinaryMethod[] getMethods();
+ /**
+ * Answer the resolved name of the type in the
+ * class file format as specified in section 4.2 of the Java 2 VM spec.
+ *
+ * For example, java.lang.String is java/lang/String.
+ */
+
+ char[] getName();
+ /**
+ * Answer the resolved name of the receiver's superclass in the
+ * class file format as specified in section 4.2 of the Java 2 VM spec
+ * or null if it does not have one.
+ *
+ * For example, java.lang.String is java/lang/String.
+ */
+
+ char[] getSuperclassName();
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java
new file mode 100644
index 0000000000..6e9f420d89
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java
@@ -0,0 +1,19 @@
+package org.eclipse.jdt.internal.compiler.env;
+
+public interface ICompilationUnit extends IDependent {
+ /**
+ * Answer the contents of the compilation unit.
+ *
+ * In normal use, the contents are requested twice.
+ * Once during the initial lite parsing step, then again for the
+ * more detailed parsing step.
+ */
+
+ char[] getContents();
+ /**
+ * Answer the name of the top level public type.
+ * For example, {Hashtable}.
+ */
+
+ char[] getMainTypeName();
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IConstants.java
new file mode 100644
index 0000000000..ff189d051e
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IConstants.java
@@ -0,0 +1,31 @@
+package org.eclipse.jdt.internal.compiler.env;
+
+public interface IConstants {
+
+ /*
+ * Modifiers
+ */
+ int AccPublic = 0x0001;
+ int AccPrivate = 0x0002;
+ int AccProtected = 0x0004;
+ int AccStatic = 0x0008;
+ int AccFinal = 0x0010;
+ int AccSynchronized = 0x0020;
+ int AccVolatile = 0x0040;
+ int AccTransient = 0x0080;
+ int AccNative = 0x0100;
+ int AccInterface = 0x0200;
+ int AccAbstract = 0x0400;
+ int AccStrictfp = 0x0800;
+
+ /*
+ * Other VM flags.
+ */
+ int AccSuper = 0x0020;
+
+ /**
+ * Extra flags for types and members.
+ */
+ int AccSynthetic = 0x20000;
+ int AccDeprecated = 0x100000;
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IDependent.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IDependent.java
new file mode 100644
index 0000000000..8156e0eee4
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IDependent.java
@@ -0,0 +1,16 @@
+package org.eclipse.jdt.internal.compiler.env;
+
+public interface IDependent {
+ /**
+ * Answer the file name which defines the type.
+ *
+ * The path part (optional) must be separated from the actual
+ * file proper name by a java.io.File.separator.
+ *
+ * The proper file name includes the suffix extension (e.g. ".java")
+ *
+ * e.g. "c:/com/ibm/compiler/java/api/Compiler.java"
+ */
+
+ char[] getFileName();
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IGenericField.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IGenericField.java
new file mode 100644
index 0000000000..4f04c725d5
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IGenericField.java
@@ -0,0 +1,17 @@
+package org.eclipse.jdt.internal.compiler.env;
+
+public interface IGenericField {
+ /**
+ * Answer an int whose bits are set according the access constants
+ * defined by the VM spec.
+ */
+
+ // We have added AccDeprecated & AccSynthetic.
+
+ int getModifiers();
+ /**
+ * Answer the name of the field.
+ */
+
+ char[] getName();
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IGenericMethod.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IGenericMethod.java
new file mode 100644
index 0000000000..2b297ea916
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IGenericMethod.java
@@ -0,0 +1,20 @@
+package org.eclipse.jdt.internal.compiler.env;
+
+public interface IGenericMethod {
+ /**
+ * Answer an int whose bits are set according the access constants
+ * defined by the VM spec.
+ */
+
+ // We have added AccDeprecated & AccSynthetic.
+
+ int getModifiers();
+ /**
+ * Answer the name of the method.
+ *
+ * For a constructor, answer <init> & <clinit> for a clinit method.
+ */
+
+ char[] getSelector();
+ boolean isConstructor();
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IGenericType.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IGenericType.java
new file mode 100644
index 0000000000..2fe07b6d56
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IGenericType.java
@@ -0,0 +1,22 @@
+package org.eclipse.jdt.internal.compiler.env;
+
+public interface IGenericType extends IDependent {
+ /**
+ * Answer an int whose bits are set according the access constants
+ * defined by the VM spec.
+ */
+
+ // We have added AccDeprecated & AccSynthetic.
+
+ // NOTE: If the receiver represents a member type, the modifiers are extracted from its inner class attributes.
+
+ int getModifiers();
+ /**
+ * Answer whether the receiver contains the resolved binary form
+ * or the unresolved source form of the type.
+ */
+
+ boolean isBinaryType();
+ boolean isClass();
+ boolean isInterface();
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/INameEnvironment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/INameEnvironment.java
new file mode 100644
index 0000000000..3fb3d4c207
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/INameEnvironment.java
@@ -0,0 +1,45 @@
+package org.eclipse.jdt.internal.compiler.env;
+
+public interface INameEnvironment {
+ /**
+ * Find a type with the given compound name.
+ * Answer the binary form of the type if it is known to be consistent.
+ * Otherwise, answer the compilation unit which defines the type
+ * or null if the type does not exist.
+ * Types in the default package are specified as {{typeName}}.
+ *
+ * It is unknown whether the package containing the type actually exists.
+ *
+ * NOTE: This method can be used to find a member type using its
+ * internal name A$B, but the source file for A is answered if the binary
+ * file is inconsistent.
+ */
+
+ NameEnvironmentAnswer findType(char[][] compoundTypeName);
+ /**
+ * Find a type named <typeName> in the package <packageName>.
+ * Answer the binary form of the type if it is known to be consistent.
+ * Otherwise, answer the compilation unit which defines the type
+ * or null if the type does not exist.
+ * The default package is indicated by char[0][].
+ *
+ * It is known that the package containing the type exists.
+ *
+ * NOTE: This method can be used to find a member type using its
+ * internal name A$B, but the source file for A is answered if the binary
+ * file is inconsistent.
+ */
+
+ NameEnvironmentAnswer findType(char[] typeName, char[][] packageName);
+ /**
+ * Answer whether packageName is the name of a known subpackage inside
+ * the package parentPackageName. A top level package is found relative to null.
+ * The default package is always assumed to exist.
+ *
+ * For example:
+ * isPackage({{java}, {awt}}, {event});
+ * isPackage(null, {java});
+ */
+
+ boolean isPackage(char[][] parentPackageName, char[] packageName);
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ISourceField.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ISourceField.java
new file mode 100644
index 0000000000..5d72822234
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ISourceField.java
@@ -0,0 +1,32 @@
+package org.eclipse.jdt.internal.compiler.env;
+
+public interface ISourceField extends IGenericField {
+ /**
+ * Answer the source end position of the field's declaration.
+ */
+
+ int getDeclarationSourceEnd();
+ /**
+ * Answer the source start position of the field's declaration.
+ */
+
+ int getDeclarationSourceStart();
+ /**
+ * Answer the source end position of the field's name.
+ */
+
+ int getNameSourceEnd();
+ /**
+ * Answer the source start position of the field's name.
+ */
+
+ int getNameSourceStart();
+ /**
+ * Answer the type name of the field.
+ *
+ * The name is a simple name or a qualified, dot separated name.
+ * For example, Hashtable or java.util.Hashtable.
+ */
+
+ char[] getTypeName();
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ISourceMethod.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ISourceMethod.java
new file mode 100644
index 0000000000..22428b6141
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ISourceMethod.java
@@ -0,0 +1,57 @@
+package org.eclipse.jdt.internal.compiler.env;
+
+public interface ISourceMethod extends IGenericMethod {
+ /**
+ * Answer the names of the argument
+ * or null if the array is empty.
+ */
+
+ char[][] getArgumentNames();
+ /**
+ * Answer the unresolved names of the argument types
+ * or null if the array is empty.
+ *
+ * A name is a simple name or a qualified, dot separated name.
+ * For example, Hashtable or java.util.Hashtable.
+ */
+
+ char[][] getArgumentTypeNames();
+ /**
+ * Answer the source end position of the method's declaration.
+ */
+
+ int getDeclarationSourceEnd();
+ /**
+ * Answer the source start position of the method's declaration.
+ */
+
+ int getDeclarationSourceStart();
+ /**
+ * Answer the unresolved names of the exception types
+ * or null if the array is empty.
+ *
+ * A name is a simple name or a qualified, dot separated name.
+ * For example, Hashtable or java.util.Hashtable.
+ */
+
+ char[][] getExceptionTypeNames();
+ /**
+ * Answer the source end position of the method's selector.
+ */
+
+ int getNameSourceEnd();
+ /**
+ * Answer the source start position of the method's selector.
+ */
+
+ int getNameSourceStart();
+ /**
+ * Answer the unresolved name of the return type
+ * or null if receiver is a constructor or clinit.
+ *
+ * The name is a simple name or a qualified, dot separated name.
+ * For example, Hashtable or java.util.Hashtable.
+ */
+
+ char[] getReturnTypeName();
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ISourceType.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ISourceType.java
new file mode 100644
index 0000000000..06d8450d22
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ISourceType.java
@@ -0,0 +1,98 @@
+package org.eclipse.jdt.internal.compiler.env;
+
+public interface ISourceType extends IGenericType {
+ /**
+ * Answer the source end position of the type's declaration.
+ */
+
+ int getDeclarationSourceEnd();
+ /**
+ * Answer the source start position of the type's declaration.
+ */
+
+ int getDeclarationSourceStart();
+ /**
+ * Answer the enclosing type
+ * or null if the receiver is a top level type.
+ */
+
+ ISourceType getEnclosingType();
+ /**
+ * Answer the receiver's fields or null if the array is empty.
+ *
+ * NOTE: Multiple fields with the same name can exist in the result.
+ */
+
+ ISourceField[] getFields();
+ /**
+ * Answer the unresolved names of the receiver's imports
+ * or null if the array is empty.
+ *
+ * An import is a qualified, dot separated name.
+ * For example, java.util.Hashtable or java.lang.*.
+ */
+
+ char[][] getImports();
+ /**
+ * Answer the unresolved names of the receiver's interfaces
+ * or null if the array is empty.
+ *
+ * A name is a simple name or a qualified, dot separated name.
+ * For example, Hashtable or java.util.Hashtable.
+ */
+
+ char[][] getInterfaceNames();
+ /**
+ * Answer the receiver's member types
+ * or null if the array is empty.
+ */
+
+ ISourceType[] getMemberTypes();
+ /**
+ * Answer the receiver's methods or null if the array is empty.
+ *
+ * NOTE: Multiple methods with the same name & parameter types can exist in the result.
+ */
+
+ ISourceMethod[] getMethods();
+ /**
+ * Answer the simple source name of the receiver.
+ */
+
+ char[] getName();
+ /**
+ * Answer the source end position of the type's name.
+ */
+
+ int getNameSourceEnd();
+ /**
+ * Answer the source start position of the type's name.
+ */
+
+ int getNameSourceStart();
+ /**
+ * Answer the qualified name of the receiver's package separated by periods
+ * or null if its the default package.
+ *
+ * For example, {java.util.Hashtable}.
+ */
+
+ char[] getPackageName();
+ /**
+ * Answer the qualified name of the receiver.
+ *
+ * The name is a qualified, dot separated name.
+ * For example, java.util.Hashtable.
+ */
+
+ char[] getQualifiedName();
+ /**
+ * Answer the unresolved name of the receiver's superclass
+ * or null if it does not have one.
+ *
+ * The name is a simple name or a qualified, dot separated name.
+ * For example, Hashtable or java.util.Hashtable.
+ */
+
+ char[] getSuperclassName();
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/NameEnvironmentAnswer.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/NameEnvironmentAnswer.java
new file mode 100644
index 0000000000..7a782ab7d5
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/NameEnvironmentAnswer.java
@@ -0,0 +1,71 @@
+package org.eclipse.jdt.internal.compiler.env;
+
+public class NameEnvironmentAnswer {
+ // only one of the three can be set
+ IBinaryType binaryType;
+ ICompilationUnit compilationUnit;
+ ISourceType sourceType;
+ public NameEnvironmentAnswer(IBinaryType binaryType) {
+ this.binaryType = binaryType;
+ }
+
+ public NameEnvironmentAnswer(ICompilationUnit compilationUnit) {
+ this.compilationUnit = compilationUnit;
+ }
+
+ public NameEnvironmentAnswer(ISourceType sourceType) {
+ this.sourceType = sourceType;
+ }
+
+ /**
+ * Answer the resolved binary form for the type or null if the
+ * receiver represents a compilation unit or source type.
+ */
+
+ public IBinaryType getBinaryType() {
+ return binaryType;
+ }
+
+ /**
+ * Answer the compilation unit or null if the
+ * receiver represents a binary or source type.
+ */
+
+ public ICompilationUnit getCompilationUnit() {
+ return compilationUnit;
+ }
+
+ /**
+ * Answer the unresolved source form for the type or null if the
+ * receiver represents a compilation unit or binary type.
+ */
+
+ public ISourceType getSourceType() {
+ return sourceType;
+ }
+
+ /**
+ * Answer whether the receiver contains the resolved binary form of the type.
+ */
+
+ public boolean isBinaryType() {
+ return binaryType != null;
+ }
+
+ /**
+ * Answer whether the receiver contains the compilation unit which defines the type.
+ */
+
+ public boolean isCompilationUnit() {
+ return compilationUnit != null;
+ }
+
+ /**
+ * Answer whether the receiver contains the unresolved source form of the type.
+ */
+
+ public boolean isSourceType() {
+ return sourceType != null;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java
new file mode 100644
index 0000000000..8ae429d659
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java
@@ -0,0 +1,147 @@
+package org.eclipse.jdt.internal.compiler.flow;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+/**
+ * Record conditional initialization status during definite assignment analysis
+ *
+ */
+public class ConditionalFlowInfo extends FlowInfo {
+ public FlowInfo initsWhenTrue;
+ public FlowInfo initsWhenFalse;
+ ConditionalFlowInfo(FlowInfo initsWhenTrue, FlowInfo initsWhenFalse) {
+ this.initsWhenTrue = initsWhenTrue;
+ this.initsWhenFalse = initsWhenFalse;
+ }
+
+ public UnconditionalFlowInfo addInitializationsFrom(UnconditionalFlowInfo otherInits) {
+ return unconditionalInits().addInitializationsFrom(otherInits);
+ }
+
+ public UnconditionalFlowInfo addPotentialInitializationsFrom(UnconditionalFlowInfo otherInits) {
+ return unconditionalInits().addPotentialInitializationsFrom(otherInits);
+ }
+
+ public FlowInfo asNegatedCondition() {
+ FlowInfo extra = initsWhenTrue;
+ initsWhenTrue = initsWhenFalse;
+ initsWhenFalse = extra;
+ return this;
+ }
+
+ public FlowInfo copy() {
+ return new ConditionalFlowInfo(initsWhenTrue.copy(), initsWhenFalse.copy());
+ }
+
+ public FlowInfo initsWhenFalse() {
+ return initsWhenFalse;
+ }
+
+ public FlowInfo initsWhenTrue() {
+ return initsWhenTrue;
+ }
+
+ /**
+ * Check status of definite assignment for a field.
+ */
+ public boolean isDefinitelyAssigned(FieldBinding field) {
+ return initsWhenTrue.isDefinitelyAssigned(field)
+ && initsWhenFalse.isDefinitelyAssigned(field);
+
+ }
+
+ /**
+ * Check status of definite assignment for a local variable.
+ */
+ public boolean isDefinitelyAssigned(LocalVariableBinding local) {
+ return initsWhenTrue.isDefinitelyAssigned(local)
+ && initsWhenFalse.isDefinitelyAssigned(local);
+
+ }
+
+ public boolean isFakeReachable() {
+ return unconditionalInits().isFakeReachable();
+ //should maybe directly be: false
+ }
+
+ /**
+ * Check status of potential assignment for a field.
+ */
+ public boolean isPotentiallyAssigned(FieldBinding field) {
+ return initsWhenTrue.isPotentiallyAssigned(field)
+ || initsWhenFalse.isPotentiallyAssigned(field);
+
+ }
+
+ /**
+ * Check status of potential assignment for a local variable.
+ */
+ public boolean isPotentiallyAssigned(LocalVariableBinding local) {
+ return initsWhenTrue.isPotentiallyAssigned(local)
+ || initsWhenFalse.isPotentiallyAssigned(local);
+
+ }
+
+ /**
+ * Record a field got definitely assigned.
+ */
+ public void markAsDefinitelyAssigned(FieldBinding field) {
+ initsWhenTrue.markAsDefinitelyAssigned(field);
+ initsWhenFalse.markAsDefinitelyAssigned(field);
+ }
+
+ /**
+ * Record a field got definitely assigned.
+ */
+ public void markAsDefinitelyAssigned(LocalVariableBinding local) {
+ initsWhenTrue.markAsDefinitelyAssigned(local);
+ initsWhenFalse.markAsDefinitelyAssigned(local);
+ }
+
+ /**
+ * Clear the initialization info for a field
+ */
+ public void markAsDefinitelyNotAssigned(FieldBinding field) {
+ initsWhenTrue.markAsDefinitelyNotAssigned(field);
+ initsWhenFalse.markAsDefinitelyNotAssigned(field);
+ }
+
+ /**
+ * Clear the initialization info for a local variable
+ */
+ public void markAsDefinitelyNotAssigned(LocalVariableBinding local) {
+ initsWhenTrue.markAsDefinitelyNotAssigned(local);
+ initsWhenFalse.markAsDefinitelyNotAssigned(local);
+ }
+
+ public FlowInfo markAsFakeReachable(boolean isFakeReachable) {
+ initsWhenTrue.markAsFakeReachable(isFakeReachable);
+ initsWhenFalse.markAsFakeReachable(isFakeReachable);
+ return this;
+ }
+
+ public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) {
+ return unconditionalInits().mergedWith(otherInits);
+ }
+
+ public String toString() {
+ return "FlowInfo<true: "
+ + initsWhenTrue.toString()
+ + ", false: "
+ + initsWhenFalse.toString()
+ + ">";
+ }
+
+ public UnconditionalFlowInfo unconditionalInits() {
+ return initsWhenTrue.unconditionalInits().copy().mergedWith(
+ initsWhenFalse.unconditionalInits());
+ }
+
+}
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
new file mode 100644
index 0000000000..44cc983863
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java
@@ -0,0 +1,149 @@
+package org.eclipse.jdt.internal.compiler.flow;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+
+/**
+ * Reflects the context of code analysis, keeping track of enclosing
+ * try statements, exception handlers, etc...
+ */
+public class ExceptionHandlingFlowContext extends FlowContext {
+ ReferenceBinding[] handledExceptions;
+
+ public final static int BitCacheSize = 32; // 32 bits per int
+ int[] isReached;
+ int[] isNeeded;
+ UnconditionalFlowInfo[] initsOnExceptions;
+ ObjectCache indexes = new ObjectCache();
+ boolean isMethodContext;
+ public ExceptionHandlingFlowContext(
+ FlowContext parent,
+ AstNode associatedNode,
+ ReferenceBinding[] handledExceptions,
+ BlockScope scope,
+ UnconditionalFlowInfo flowInfo) {
+
+ super(parent, associatedNode);
+ isMethodContext = scope == scope.methodScope();
+ /*
+ // for a method, append the unchecked exceptions to the handled exceptions collection
+
+ if (scope.methodScope() == scope) {
+ int length;
+ System.arraycopy(
+ handledExceptions,
+ 0,
+ (handledExceptions =
+ new ReferenceBinding[(length = handledExceptions.length) + 2]),
+ 0,
+ length);
+ handledExceptions[length] = scope.getJavaLangRuntimeException();
+ handledExceptions[length + 1] = scope.getJavaLangError();
+ }
+ */
+ this.handledExceptions = handledExceptions;
+ int count = handledExceptions.length, cacheSize = (count / BitCacheSize) + 1;
+ isReached = new int[cacheSize]; // none is reached by default
+ isNeeded = new int[cacheSize]; // none is needed by default
+ initsOnExceptions = new UnconditionalFlowInfo[count];
+ for (int i = 0; i < count; i++) {
+ indexes.put(handledExceptions[i], i); // key type -> value index
+ boolean isUnchecked =
+ (scope.compareUncheckedException(handledExceptions[i]) != NotRelated);
+ int cacheIndex = i / BitCacheSize, bitMask = 1 << (i % BitCacheSize);
+ if (isUnchecked) {
+ isReached[cacheIndex] |= bitMask;
+ initsOnExceptions[i] = flowInfo.copy().unconditionalInits();
+ } else {
+ initsOnExceptions[i] = FlowInfo.DeadEnd;
+ }
+ }
+ System.arraycopy(isReached, 0, isNeeded, 0, cacheSize);
+ }
+
+ public void complainIfUnusedExceptionHandlers(
+ AstNode[] exceptionHandlers,
+ BlockScope scope,
+ TryStatement tryStatement) {
+
+ // report errors for unreachable exception handlers
+
+ for (int i = 0, count = handledExceptions.length; i < count; i++) {
+ int index = indexes.get(handledExceptions[i]);
+ int cacheIndex = index / BitCacheSize;
+ int bitMask = 1 << (index % BitCacheSize);
+ if ((isReached[cacheIndex] & bitMask) == 0) {
+ scope.problemReporter().unreachableExceptionHandler(
+ handledExceptions[index],
+ exceptionHandlers[index]);
+ } else {
+ if ((isNeeded[cacheIndex] & bitMask) == 0) {
+ scope.problemReporter().maskedExceptionHandler(
+ handledExceptions[index],
+ exceptionHandlers[index]);
+ }
+ }
+ }
+ // will optimized out unnecessary catch block during code gen
+ tryStatement.preserveExceptionHandler = isNeeded;
+ }
+
+ public String individualToString() {
+ StringBuffer buffer = new StringBuffer("Exception flow context");
+ int length = handledExceptions.length;
+ for (int i = 0; i < length; i++) {
+ int cacheIndex = i / BitCacheSize;
+ int bitMask = 1 << (i % BitCacheSize);
+ buffer.append('[').append(handledExceptions[i].readableName());
+ if ((isReached[cacheIndex] & bitMask) != 0) {
+ if ((isNeeded[cacheIndex] & bitMask) == 0) {
+ buffer.append("-masked");
+ } else {
+ buffer.append("-reached");
+ }
+ } else {
+ buffer.append("-not reached");
+ }
+ buffer.append('-').append(initsOnExceptions[i].toString()).append(']');
+ }
+ return buffer.toString();
+ }
+
+ public UnconditionalFlowInfo initsOnException(ReferenceBinding exceptionType) {
+
+ int index;
+ if ((index = indexes.get(exceptionType)) < 0) {
+ return FlowInfo.DeadEnd;
+ }
+ return initsOnExceptions[index];
+ }
+
+ public void recordHandlingException(
+ ReferenceBinding exceptionType,
+ UnconditionalFlowInfo flowInfo,
+ TypeBinding raisedException,
+ AstNode invocationSite,
+ boolean wasAlreadyDefinitelyCaught) {
+
+ int index = indexes.get(exceptionType);
+ // if already flagged as being reached (unchecked exception handler)
+ int cacheIndex = index / BitCacheSize;
+ int bitMask = 1 << (index % BitCacheSize);
+ if (!wasAlreadyDefinitelyCaught) {
+ this.isNeeded[cacheIndex] |= bitMask;
+ }
+ this.isReached[cacheIndex] |= bitMask;
+ initsOnExceptions[index] =
+ initsOnExceptions[index] == FlowInfo.DeadEnd
+ ? flowInfo.copy().unconditionalInits()
+ : initsOnExceptions[index].mergedWith(flowInfo);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java
new file mode 100644
index 0000000000..98e4291b5b
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java
@@ -0,0 +1,85 @@
+package org.eclipse.jdt.internal.compiler.flow;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+/**
+ * Reflects the context of code analysis, keeping track of enclosing
+ * try statements, exception handlers, etc...
+ */
+public class FinallyFlowContext extends FlowContext {
+ Reference finalAssignments[];
+ int assignCount;
+ public FinallyFlowContext(FlowContext parent, AstNode associatedNode) {
+ super(parent, associatedNode);
+ }
+
+ /**
+ * Given some contextual initialization info (derived from a try block or a catch block), this
+ * code will check that the subroutine context does not also initialize a final variable potentially set
+ * redundantly.
+ */
+
+ public void complainOnRedundantFinalAssignments(
+ FlowInfo flowInfo,
+ BlockScope scope) {
+ for (int i = 0; i < assignCount; i++) {
+ Reference ref;
+ if (((ref = finalAssignments[i]).bits & BindingIds.FIELD) != 0) {
+ // final field
+ if (flowInfo
+ .isPotentiallyAssigned((FieldBinding) ((NameReference) ref).binding)) {
+ scope.problemReporter().duplicateInitializationOfBlankFinalField(
+ (FieldBinding) ((NameReference) ref).binding,
+ (NameReference) ref);
+ }
+ } else {
+ // final local variable
+ if (flowInfo
+ .isPotentiallyAssigned((LocalVariableBinding) ((NameReference) ref).binding)) {
+ scope.problemReporter().duplicateInitializationOfFinalLocal(
+ (LocalVariableBinding) ((NameReference) ref).binding,
+ (NameReference) ref);
+ }
+ }
+ // any reference reported at this level is removed from the parent context
+ // where it could also be reported again
+ FlowContext currentContext = parent;
+ while (currentContext != null) {
+ if (currentContext.isSubRoutine()) {
+ currentContext.removeFinalAssignmentIfAny(ref);
+ }
+ currentContext = currentContext.parent;
+ }
+ }
+ }
+
+ public boolean isSubRoutine() {
+ return true;
+ }
+
+ boolean recordFinalAssignment(
+ VariableBinding binding,
+ Reference finalAssignment) {
+ if (assignCount == 0) {
+ finalAssignments = new Reference[5];
+ } else {
+ if (assignCount == finalAssignments.length)
+ System.arraycopy(
+ finalAssignments,
+ 0,
+ (finalAssignments = new Reference[assignCount * 2]),
+ 0,
+ assignCount);
+ };
+ finalAssignments[assignCount++] = finalAssignment;
+ return true;
+ }
+
+}
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
new file mode 100644
index 0000000000..249e9863a5
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java
@@ -0,0 +1,470 @@
+package org.eclipse.jdt.internal.compiler.flow;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.*;
+
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+/**
+ * Reflects the context of code analysis, keeping track of enclosing
+ * try statements, exception handlers, etc...
+ */
+public class FlowContext implements TypeConstants {
+ public AstNode associatedNode;
+ public FlowContext parent;
+
+ public final static FlowContext NotContinuableContext =
+ new FlowContext(null, null);
+ public FlowContext(FlowContext parent, AstNode associatedNode) {
+ this.parent = parent;
+ this.associatedNode = associatedNode;
+ }
+
+ public Label breakLabel() {
+ return null;
+ }
+
+ public void checkExceptionHandlers(
+ TypeBinding[] raisedExceptions,
+ AstNode location,
+ FlowInfo flowInfo,
+ BlockScope scope) {
+
+ // check that all the argument exception types are handled
+
+ // JDK Compatible implementation - when an exception type is thrown,
+ // all related catch blocks are marked as reachable... instead of those only
+ // until the point where it is safely handled (Smarter - see comment at the end)
+
+ int remainingCount; // counting the number of remaining unhandled exceptions
+ int raisedCount; // total number of exceptions raised
+ if ((raisedExceptions == null)
+ || ((raisedCount = raisedExceptions.length) == 0))
+ return;
+ remainingCount = raisedCount;
+
+ // duplicate the array of raised exceptions since it will be updated
+ // (null replaces any handled exception)
+ System.arraycopy(
+ raisedExceptions,
+ 0,
+ (raisedExceptions = new TypeBinding[raisedCount]),
+ 0,
+ raisedCount);
+ FlowContext traversedContext = this;
+ while (traversedContext != null) {
+ AstNode sub;
+ if (((sub = traversedContext.subRoutine()) != null) && sub.cannotReturn()) {
+ // traversing a non-returning subroutine means that all unhandled
+ // exceptions will actually never get sent...
+ return;
+ }
+
+ // filter exceptions that are locally caught from the most enclosing
+ // try statement to the outer ones.
+ if (traversedContext instanceof ExceptionHandlingFlowContext) {
+ ExceptionHandlingFlowContext exceptionContext =
+ (ExceptionHandlingFlowContext) traversedContext;
+ ReferenceBinding[] caughtExceptions;
+ if ((caughtExceptions = exceptionContext.handledExceptions) != NoExceptions) {
+ int caughtCount = caughtExceptions.length;
+ boolean[] locallyCaught = new boolean[raisedCount]; // at most
+
+ for (int caughtIndex = 0; caughtIndex < caughtCount; caughtIndex++) {
+ ReferenceBinding caughtException = caughtExceptions[caughtIndex];
+ for (int raisedIndex = 0; raisedIndex < raisedCount; raisedIndex++) {
+ TypeBinding raisedException;
+ if ((raisedException = raisedExceptions[raisedIndex]) != null) {
+ switch (scope.compareTypes(raisedException, caughtException)) {
+ case EqualOrMoreSpecific :
+ exceptionContext.recordHandlingException(
+ caughtException,
+ flowInfo.unconditionalInits(),
+ raisedException,
+ location,
+ locallyCaught[raisedIndex]);
+ // was already definitely caught ?
+ if (!locallyCaught[raisedIndex]) {
+ locallyCaught[raisedIndex] = true;
+ // remember that this exception has been definitely caught
+ remainingCount--;
+ }
+ break;
+ case MoreGeneric :
+ exceptionContext.recordHandlingException(
+ caughtException,
+ flowInfo.unconditionalInits(),
+ raisedException,
+ location,
+ false);
+ // was not caught already per construction
+ }
+ }
+ }
+ }
+ // remove locally caught exceptions from the remaining ones
+ for (int i = 0; i < raisedCount; i++) {
+ if (locallyCaught[i]) {
+ raisedExceptions[i] = null; // removed from the remaining ones.
+ }
+ }
+ }
+ // method treatment for unchecked exceptions
+ if (exceptionContext.isMethodContext) {
+ for (int i = 0; i < raisedCount; i++) {
+ TypeBinding raisedException;
+ if ((raisedException = raisedExceptions[i]) != null) {
+ if (scope
+ .areTypesCompatible(raisedException, scope.getJavaLangRuntimeException())
+ || scope.areTypesCompatible(raisedException, scope.getJavaLangError())) {
+ remainingCount--;
+ raisedExceptions[i] = null;
+ }
+ }
+ }
+ }
+ }
+ if (remainingCount == 0)
+ return;
+ traversedContext = traversedContext.parent;
+ }
+
+ // if reaches this point, then there are some remaining unhandled exception types.
+ for (int i = 0; i < raisedCount; i++) {
+ TypeBinding exception;
+ if ((exception = raisedExceptions[i]) != null) {
+ scope.problemReporter().unhandledException(exception, location, scope);
+ }
+ }
+ }
+
+ /*
+ " - SMARTER VERSION -
+ | unhandledExceptionTypes nameEnv traversedContext |
+
+ someExceptionTypes isEmpty ifTrue: [^self].
+
+ unhandledExceptionTypes := someExceptionTypes asOrderedCollection.
+ nameEnv := scope enclosingMethod nameEnvironment.
+
+ traversedContext := self.
+ [traversedContext isNil] whileFalse: [| caughtExceptions sub |
+
+ ((sub := traversedContext subRoutine) notNil and: [sub cannotReturn])
+ ifTrue: [
+ " "Traversing a non-returning subroutine means that all unhandled exceptions will actually
+ never get sent..." "
+ ^self].
+ " "Filter exceptions that are locally caught from the most enclosing try statement to the outer ones." "
+ (caughtExceptions := traversedContext handledExceptions) isNil
+ ifFalse: [
+ caughtExceptions do: [:handledExceptionAssoc | | handledException |
+ handledException := handledExceptionAssoc key.
+ unhandledExceptionTypes copy do: [:raisedException | | safe |
+ " "Any exception recognized as being caught is removed from the exceptions list" "
+ ((safe := raisedException isCompatibleWith: handledException in: nameEnv)
+ or: [handledException isCompatibleWith: raisedException in: nameEnv])
+ ifTrue: [
+ traversedContext
+ recordInitializationInfo: initInfo
+ onException: handledException.
+ handledExceptionAssoc value: true.
+ safe ifTrue: [unhandledExceptionTypes remove: raisedException]]]]].
+ unhandledExceptionTypes isEmpty ifTrue: [^self].
+ traversedContext := traversedContext parent].
+
+ scope enclosingMethod errorInterface
+ unexpectedExceptionsError: unhandledExceptionTypes
+ from: invocationSite
+
+ */
+ public void checkExceptionHandlers(
+ TypeBinding raisedException,
+ AstNode location,
+ FlowInfo flowInfo,
+ BlockScope scope) {
+
+ // LIGHT-VERSION OF THE EQUIVALENT WITH AN ARRAY OF EXCEPTIONS
+
+ // check that all the argument exception types are handled
+ // JDK Compatible implementation - when an exception type is thrown,
+ // all related catch blocks are marked as reachable... instead of those only
+ // until the point where it is safely handled (Smarter - see comment at the end)
+
+ FlowContext traversedContext = this;
+ while (traversedContext != null) {
+ AstNode sub;
+ if (((sub = traversedContext.subRoutine()) != null) && sub.cannotReturn()) {
+ // traversing a non-returning subroutine means that all unhandled
+ // exceptions will actually never get sent...
+ return;
+ }
+
+ // filter exceptions that are locally caught from the most enclosing
+ // try statement to the outer ones.
+ if (traversedContext instanceof ExceptionHandlingFlowContext) {
+ ExceptionHandlingFlowContext exceptionContext =
+ (ExceptionHandlingFlowContext) traversedContext;
+ ReferenceBinding[] caughtExceptions;
+ if ((caughtExceptions = exceptionContext.handledExceptions) != NoExceptions) {
+ boolean definitelyCaught = false;
+ for (int caughtIndex = 0, caughtCount = caughtExceptions.length;
+ caughtIndex < caughtCount;
+ caughtIndex++) {
+ ReferenceBinding caughtException = caughtExceptions[caughtIndex];
+ switch (scope.compareTypes(raisedException, caughtException)) {
+ case EqualOrMoreSpecific :
+ exceptionContext.recordHandlingException(
+ caughtException,
+ flowInfo.unconditionalInits(),
+ raisedException,
+ location,
+ definitelyCaught);
+ // was it already definitely caught ?
+ definitelyCaught = true;
+ break;
+ case MoreGeneric :
+ exceptionContext.recordHandlingException(
+ caughtException,
+ flowInfo.unconditionalInits(),
+ raisedException,
+ location,
+ false);
+ // was not caught already per construction
+ }
+ }
+ if (definitelyCaught)
+ return;
+ }
+ // method treatment for unchecked exceptions
+ if (exceptionContext.isMethodContext) {
+ if (scope
+ .areTypesCompatible(raisedException, scope.getJavaLangRuntimeException())
+ || scope.areTypesCompatible(raisedException, scope.getJavaLangError()))
+ return;
+ break; // not handled anywhere, thus jump to error handling
+ }
+ }
+ traversedContext = traversedContext.parent;
+ }
+
+ // if reaches this point, then there are some remaining unhandled exception types.
+ scope.problemReporter().unhandledException(raisedException, location, scope);
+ }
+
+ public Label continueLabel() {
+ return null;
+ }
+
+ public FlowContext getTargetContextForBreakLabel(char[] labelName) {
+
+ // lookup through break labels
+
+ FlowContext current = this, lastNonReturningSubRoutine = null;
+ while (current != null) {
+ if (current.isNonReturningContext()) {
+ lastNonReturningSubRoutine = current;
+ }
+ char[] currentLabelName;
+ if (((currentLabelName = current.labelName()) != null)
+ && CharOperation.equals(currentLabelName, labelName)) {
+ if (lastNonReturningSubRoutine == null) {
+ return current;
+ } else {
+ return lastNonReturningSubRoutine;
+ }
+ }
+ current = current.parent;
+ }
+
+ // not found
+ return null;
+ }
+
+ public FlowContext getTargetContextForContinueLabel(char[] labelName) {
+
+ // lookup through continue labels
+
+ FlowContext current = this,
+ lastContinuable = null,
+ lastNonReturningSubRoutine = null;
+ while (current != null) {
+ if (current.isNonReturningContext()) {
+ lastNonReturningSubRoutine = current;
+ } else {
+ if (current.isContinuable()) {
+ lastContinuable = current;
+ }
+ }
+ char[] currentLabelName;
+ if (((currentLabelName = current.labelName()) != null)
+ && CharOperation.equals(currentLabelName, labelName)) {
+ if ((lastContinuable != null)
+ && (current.associatedNode.concreteStatement()
+ == lastContinuable.associatedNode)) {
+ if (lastNonReturningSubRoutine == null) {
+ return lastContinuable;
+ } else {
+ return lastNonReturningSubRoutine;
+ }
+ } else {
+ // label is found, but not a continuable location
+ return NotContinuableContext;
+ }
+ }
+ current = current.parent;
+ }
+
+ // not found
+ return null;
+ }
+
+ public FlowContext getTargetContextForDefaultBreak() {
+
+ // lookup through break labels
+
+ FlowContext current = this, lastNonReturningSubRoutine = null;
+ while (current != null) {
+ if (current.isNonReturningContext()) {
+ lastNonReturningSubRoutine = current;
+ }
+ if (current.isBreakable()) {
+ if (lastNonReturningSubRoutine == null) {
+ return current;
+ } else {
+ return lastNonReturningSubRoutine;
+ }
+ }
+ current = current.parent;
+ }
+
+ // not found
+ return null;
+ }
+
+ public FlowContext getTargetContextForDefaultContinue() {
+
+ // lookup through continue labels
+
+ FlowContext current = this, lastNonReturningSubRoutine = null;
+ while (current != null) {
+ if (current.isNonReturningContext()) {
+ lastNonReturningSubRoutine = current;
+ }
+ if (current.isContinuable()) {
+ if (lastNonReturningSubRoutine == null) {
+ return current;
+ } else {
+ return lastNonReturningSubRoutine;
+ }
+ }
+ current = current.parent;
+ }
+
+ // not found
+ return null;
+ }
+
+ public String individualToString() {
+ return "Flow context";
+ }
+
+ public FlowInfo initsOnBreak() {
+ return FlowInfo.DeadEnd;
+ }
+
+ public boolean isBreakable() {
+ return false;
+ }
+
+ public boolean isContinuable() {
+ return false;
+ }
+
+ public boolean isNonReturningContext() {
+ return false;
+ }
+
+ public boolean isSubRoutine() {
+ return false;
+ }
+
+ public char[] labelName() {
+ return null;
+ }
+
+ public void recordBreakFrom(FlowInfo flowInfo) {
+ }
+
+ public void recordContinueFrom(FlowInfo flowInfo) {
+ }
+
+ boolean recordFinalAssignment(
+ VariableBinding variable,
+ Reference finalReference) {
+ return true; // keep going
+ }
+
+ public void recordReturnFrom(UnconditionalFlowInfo flowInfo) {
+ }
+
+ public void recordSettingFinal(
+ VariableBinding variable,
+ Reference finalReference) {
+
+ // for initialization inside looping statement that effectively loops
+
+ FlowContext context = this;
+ while (context != null) {
+ if (!context.recordFinalAssignment(variable, finalReference)) {
+ break; // no need to keep going
+ }
+ context = context.parent;
+ }
+ }
+
+ void removeFinalAssignmentIfAny(Reference reference) {
+ }
+
+ public AstNode subRoutine() {
+ return null;
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ FlowContext current = this;
+
+ int parentsCount = 0;
+ while ((current = current.parent) != null) {
+ parentsCount++;
+ }
+
+ FlowContext[] parents = new FlowContext[parentsCount + 1];
+ current = this;
+ int index = parentsCount;
+ while (index >= 0) {
+ parents[index--] = current;
+ current = current.parent;
+ }
+
+ for (int i = 0; i < parentsCount; i++) {
+ for (int j = 0; j < i; j++)
+ buffer.append('\t');
+ buffer.append(parents[i].individualToString()).append('\n');
+ }
+ buffer.append('*');
+ for (int j = 0; j < parentsCount + 1; j++)
+ buffer.append('\t');
+ buffer.append(individualToString()).append('\n');
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java
new file mode 100644
index 0000000000..0a361ce54f
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java
@@ -0,0 +1,88 @@
+package org.eclipse.jdt.internal.compiler.flow;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public abstract class FlowInfo {
+ public static final UnconditionalFlowInfo DeadEnd = new UnconditionalFlowInfo();
+ // Represents a dead branch status of initialization
+ abstract public UnconditionalFlowInfo addInitializationsFrom(UnconditionalFlowInfo otherInits);
+ abstract public UnconditionalFlowInfo addPotentialInitializationsFrom(UnconditionalFlowInfo otherInits);
+ public FlowInfo asNegatedCondition() {
+ return this;
+ }
+
+ public boolean complainIfUnreachable(Statement statement, BlockScope scope) {
+ // Report an error if necessary
+
+ return false;
+ }
+
+ public static FlowInfo conditional(
+ FlowInfo initsWhenTrue,
+ FlowInfo initsWhenFalse) {
+ return new ConditionalFlowInfo(initsWhenTrue, initsWhenFalse);
+ }
+
+ abstract public FlowInfo copy();
+ public static UnconditionalFlowInfo initial(int maxFieldCount) {
+ UnconditionalFlowInfo info = new UnconditionalFlowInfo();
+ info.maxFieldCount = maxFieldCount;
+ return info;
+ }
+
+ abstract public FlowInfo initsWhenFalse();
+ abstract public FlowInfo initsWhenTrue();
+ final public boolean isDeadEnd() {
+ return this == DeadEnd;
+ }
+
+ /**
+ * Check status of definite assignment for a field.
+ */
+ abstract public boolean isDefinitelyAssigned(FieldBinding field);
+ /**
+ * Check status of definite assignment for a local.
+ */
+ public abstract boolean isDefinitelyAssigned(LocalVariableBinding local);
+ abstract public boolean isFakeReachable();
+ /**
+ * Check status of potential assignment for a field.
+ */
+ abstract public boolean isPotentiallyAssigned(FieldBinding field);
+ /**
+ * Check status of potential assignment for a local variable.
+ */
+ abstract public boolean isPotentiallyAssigned(LocalVariableBinding field);
+ /**
+ * Record a field got definitely assigned.
+ */
+ abstract public void markAsDefinitelyAssigned(FieldBinding field);
+ /**
+ * Record a local got definitely assigned.
+ */
+ abstract public void markAsDefinitelyAssigned(LocalVariableBinding local);
+ /**
+ * Clear the initialization info for a field
+ */
+ abstract public void markAsDefinitelyNotAssigned(FieldBinding field);
+ /**
+ * Clear the initialization info for a local variable
+ */
+ abstract public void markAsDefinitelyNotAssigned(LocalVariableBinding local);
+ abstract public FlowInfo markAsFakeReachable(boolean isFakeReachable);
+ abstract public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits);
+ public String toString() {
+ if (this == DeadEnd) {
+ return "FlowInfo.DeadEnd";
+ }
+ return super.toString();
+ }
+
+ abstract public UnconditionalFlowInfo unconditionalInits();
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/InitializationFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/InitializationFlowContext.java
new file mode 100644
index 0000000000..167cb403bf
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/InitializationFlowContext.java
@@ -0,0 +1,84 @@
+package org.eclipse.jdt.internal.compiler.flow;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+import java.util.*;
+
+/**
+ * Reflects the context of code analysis, keeping track of enclosing
+ * try statements, exception handlers, etc...
+ */
+public class InitializationFlowContext extends ExceptionHandlingFlowContext {
+ public UnconditionalFlowInfo initsOnReturn;
+
+ public int exceptionCount;
+ public TypeBinding[] thrownExceptions = new TypeBinding[5];
+ public AstNode[] exceptionThrowers = new AstNode[5];
+ public InitializationFlowContext(
+ FlowContext parent,
+ AstNode associatedNode,
+ BlockScope scope) {
+ super(
+ parent,
+ associatedNode,
+ new ReferenceBinding[] { scope.getJavaLangThrowable()},
+ // tolerate any kind of exception, but record them
+ scope, FlowInfo.DeadEnd);
+
+ this.initsOnReturn = FlowInfo.DeadEnd;
+ }
+
+ public void checkInitializerExceptions(
+ BlockScope currentScope,
+ FlowContext initializerContext,
+ FlowInfo flowInfo) {
+ for (int i = 0; i < exceptionCount; i++) {
+ initializerContext.checkExceptionHandlers(
+ thrownExceptions[i],
+ exceptionThrowers[i],
+ flowInfo,
+ currentScope);
+ }
+ }
+
+ public void recordHandlingException(
+ ReferenceBinding exceptionType,
+ UnconditionalFlowInfo flowInfo,
+ TypeBinding raisedException,
+ AstNode invocationSite,
+ boolean wasMasked) {
+
+ int size = thrownExceptions.length;
+ if (exceptionCount == size) {
+ System.arraycopy(
+ thrownExceptions,
+ 0,
+ (thrownExceptions = new TypeBinding[size * 2]),
+ 0,
+ size);
+ System.arraycopy(
+ exceptionThrowers,
+ 0,
+ (exceptionThrowers = new AstNode[size * 2]),
+ 0,
+ size);
+ }
+ thrownExceptions[exceptionCount] = raisedException;
+ exceptionThrowers[exceptionCount++] = invocationSite;
+ }
+
+ public void recordReturnFrom(UnconditionalFlowInfo flowInfo) {
+
+ // record initializations which were performed at the return point
+ initsOnReturn = initsOnReturn.mergedWith(flowInfo);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/InsideSubRoutineFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/InsideSubRoutineFlowContext.java
new file mode 100644
index 0000000000..961cf2564b
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/InsideSubRoutineFlowContext.java
@@ -0,0 +1,31 @@
+package org.eclipse.jdt.internal.compiler.flow;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+/**
+ * Reflects the context of code analysis, keeping track of enclosing
+ * try statements, exception handlers, etc...
+ */
+public class InsideSubRoutineFlowContext extends FlowContext {
+ public InsideSubRoutineFlowContext(
+ FlowContext parent,
+ AstNode associatedNode) {
+ super(parent, associatedNode);
+ }
+
+ public boolean isNonReturningContext() {
+ return associatedNode.cannotReturn();
+ }
+
+ public AstNode subRoutine() {
+ return associatedNode;
+ }
+
+}
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
new file mode 100644
index 0000000000..ca33ee2ee2
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LabelFlowContext.java
@@ -0,0 +1,55 @@
+package org.eclipse.jdt.internal.compiler.flow;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+/**
+ * Reflects the context of code analysis, keeping track of enclosing
+ * try statements, exception handlers, etc...
+ */
+public class LabelFlowContext extends SwitchFlowContext {
+ public char[] labelName;
+ public LabelFlowContext(
+ FlowContext parent,
+ AstNode associatedNode,
+ char[] labelName,
+ Label breakLabel,
+ BlockScope scope) {
+
+ super(parent, associatedNode, breakLabel);
+ this.labelName = labelName;
+ checkLabelValidity(scope);
+ }
+
+ void checkLabelValidity(BlockScope scope) {
+
+ // check if label was already defined above
+
+ FlowContext current = parent;
+ while (current != null) {
+ char[] currentLabelName;
+ if (((currentLabelName = current.labelName()) != null)
+ && CharOperation.equals(currentLabelName, labelName)) {
+ scope.problemReporter().alreadyDefinedLabel(labelName, associatedNode);
+ }
+ current = current.parent;
+ }
+ }
+
+ public String individualToString() {
+ return "Label flow context [label:" + String.valueOf(labelName) + "]";
+ }
+
+ public char[] labelName() {
+ return labelName;
+ }
+
+}
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
new file mode 100644
index 0000000000..9b20777bf9
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java
@@ -0,0 +1,142 @@
+package org.eclipse.jdt.internal.compiler.flow;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+/**
+ * Reflects the context of code analysis, keeping track of enclosing
+ * try statements, exception handlers, etc...
+ */
+public class LoopingFlowContext extends SwitchFlowContext {
+ public Label continueLabel;
+ public UnconditionalFlowInfo initsOnContinue = FlowInfo.DeadEnd;
+ Reference finalAssignments[];
+ VariableBinding finalVariables[];
+ int assignCount = 0;
+ Scope associatedScope;
+ public LoopingFlowContext(
+ FlowContext parent,
+ AstNode associatedNode,
+ Label breakLabel,
+ Label continueLabel,
+ Scope associatedScope) {
+ super(parent, associatedNode, breakLabel);
+ this.continueLabel = continueLabel;
+ this.associatedScope = associatedScope;
+ }
+
+ public void complainOnFinalAssignmentsInLoop(
+ BlockScope scope,
+ FlowInfo flowInfo) {
+ for (int i = 0; i < assignCount; i++) {
+ VariableBinding variable;
+ if ((variable = finalVariables[i]) != null) {
+ boolean complained; // remember if have complained on this final assignment
+ if (variable instanceof FieldBinding) {
+ if (complained = flowInfo.isPotentiallyAssigned((FieldBinding) variable)) {
+ scope.problemReporter().duplicateInitializationOfBlankFinalField(
+ (FieldBinding) variable,
+ (NameReference) finalAssignments[i]);
+ }
+ } else {
+ if (complained =
+ flowInfo.isPotentiallyAssigned((LocalVariableBinding) variable)) {
+ scope.problemReporter().duplicateInitializationOfFinalLocal(
+ (LocalVariableBinding) variable,
+ (NameReference) finalAssignments[i]);
+ }
+ }
+ // any reference reported at this level is removed from the parent context where it
+ // could also be reported again
+ if (complained) {
+ FlowContext context = parent;
+ while (context != null) {
+ context.removeFinalAssignmentIfAny(finalAssignments[i]);
+ context = context.parent;
+ }
+ }
+ }
+ }
+ }
+
+ public Label continueLabel() {
+ return continueLabel;
+ }
+
+ public String individualToString() {
+ return "Looping flow context";
+ }
+
+ public boolean isContinuable() {
+ return true;
+ }
+
+ public boolean isContinuedTo() {
+ return initsOnContinue != FlowInfo.DeadEnd;
+ }
+
+ public void recordContinueFrom(FlowInfo flowInfo) {
+
+ if (initsOnContinue == FlowInfo.DeadEnd) {
+ initsOnContinue = flowInfo.copy().unconditionalInits();
+ } else {
+ // ignore if not really reachable (1FKEKRP)
+ if (flowInfo.isFakeReachable())
+ return;
+ initsOnContinue.mergedWith(flowInfo.unconditionalInits());
+ };
+ }
+
+ boolean recordFinalAssignment(
+ VariableBinding binding,
+ Reference finalAssignment) {
+ // do not consider variables which are defined inside this loop
+ if (binding instanceof LocalVariableBinding) {
+ Scope scope = ((LocalVariableBinding) binding).declaringScope;
+ while ((scope = scope.parent) != null) {
+ if (scope == associatedScope)
+ return false;
+ }
+ }
+ if (assignCount == 0) {
+ finalAssignments = new Reference[5];
+ finalVariables = new VariableBinding[5];
+ } else {
+ if (assignCount == finalAssignments.length)
+ System.arraycopy(
+ finalAssignments,
+ 0,
+ (finalAssignments = new Reference[assignCount * 2]),
+ 0,
+ assignCount);
+ System.arraycopy(
+ finalVariables,
+ 0,
+ (finalVariables = new VariableBinding[assignCount * 2]),
+ 0,
+ assignCount);
+ };
+ finalAssignments[assignCount] = finalAssignment;
+ finalVariables[assignCount++] = binding;
+ return true;
+ }
+
+ void removeFinalAssignmentIfAny(Reference reference) {
+
+ for (int i = 0; i < assignCount; i++) {
+ if (finalAssignments[i] == reference) {
+ finalAssignments[i] = null;
+ finalVariables[i] = null;
+ return;
+ }
+ }
+ }
+
+}
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
new file mode 100644
index 0000000000..67a8b31c48
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/SwitchFlowContext.java
@@ -0,0 +1,55 @@
+package org.eclipse.jdt.internal.compiler.flow;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+/**
+ * Reflects the context of code analysis, keeping track of enclosing
+ * try statements, exception handlers, etc...
+ */
+public class SwitchFlowContext extends FlowContext {
+ public Label breakLabel;
+ public UnconditionalFlowInfo initsOnBreak = FlowInfo.DeadEnd;
+ /**
+ *
+ */
+ public SwitchFlowContext(
+ FlowContext parent,
+ AstNode associatedNode,
+ Label breakLabel) {
+ super(parent, associatedNode);
+ this.breakLabel = breakLabel;
+ }
+
+ public Label breakLabel() {
+ return breakLabel;
+ }
+
+ public String individualToString() {
+ return "Switch flow context";
+ }
+
+ public boolean isBreakable() {
+ return true;
+ }
+
+ public void recordBreakFrom(FlowInfo flowInfo) {
+
+ if (initsOnBreak == FlowInfo.DeadEnd) {
+ initsOnBreak = flowInfo.copy().unconditionalInits();
+ } else {
+ // ignore if not really reachable (1FKEKRP)
+ if (flowInfo.isFakeReachable())
+ return;
+ initsOnBreak.mergedWith(flowInfo.unconditionalInits());
+ };
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java
new file mode 100644
index 0000000000..13bdf1c806
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java
@@ -0,0 +1,534 @@
+package org.eclipse.jdt.internal.compiler.flow;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+/**
+ * Record initialization status during definite assignment analysis
+ *
+ * No caching of pre-allocated instances.
+ */
+public class UnconditionalFlowInfo extends FlowInfo {
+ public long definiteInits;
+ long potentialInits;
+ public long extraDefiniteInits[];
+ long extraPotentialInits[];
+ public boolean isFakeReachable;
+ public int maxFieldCount;
+
+ // Constants
+ public static final int BitCacheSize = 64; // 64 bits in a long.
+ UnconditionalFlowInfo() {
+ }
+
+ public UnconditionalFlowInfo addInitializationsFrom(UnconditionalFlowInfo otherInits) {
+
+ // unions of both sets of initialization - used for try/finally
+ if (this == DeadEnd)
+ return this;
+ if (otherInits == DeadEnd)
+ return this;
+
+ // union of definitely assigned variables,
+ definiteInits |= otherInits.definiteInits;
+ // union of potentially set ones
+ potentialInits |= otherInits.potentialInits;
+
+ // treating extra storage
+ if (extraDefiniteInits != null) {
+ if (otherInits.extraDefiniteInits != null) {
+ // both sides have extra storage
+ int i = 0, length, otherLength;
+ if ((length = extraDefiniteInits.length)
+ < (otherLength = otherInits.extraDefiniteInits.length)) {
+ // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?)
+ System.arraycopy(
+ extraDefiniteInits,
+ 0,
+ (extraDefiniteInits = new long[otherLength]),
+ 0,
+ length);
+ System.arraycopy(
+ extraPotentialInits,
+ 0,
+ (extraPotentialInits = new long[otherLength]),
+ 0,
+ length);
+ while (i < length) {
+ extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i];
+ extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
+ }
+ while (i < otherLength) {
+ extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
+ }
+ } else {
+ // current storage is longer
+ while (i < otherLength) {
+ extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i];
+ extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
+ }
+ while (i < length)
+ extraDefiniteInits[i++] = 0;
+ }
+ } else {
+ // no extra storage on otherInits
+ }
+ } else
+ if (otherInits.extraDefiniteInits != null) {
+ // no storage here, but other has extra storage.
+ int otherLength;
+ System.arraycopy(
+ otherInits.extraDefiniteInits,
+ 0,
+ (extraDefiniteInits =
+ new long[otherLength = otherInits.extraDefiniteInits.length]),
+ 0,
+ otherLength);
+ System.arraycopy(
+ otherInits.extraPotentialInits,
+ 0,
+ (extraPotentialInits = new long[otherLength]),
+ 0,
+ otherLength);
+ }
+ return this;
+ }
+
+ public UnconditionalFlowInfo addPotentialInitializationsFrom(UnconditionalFlowInfo otherInits) {
+
+ // unions of both sets of initialization - used for try/finally
+ if (this == DeadEnd) {
+ return this;
+ }
+ if (otherInits == DeadEnd) {
+ return this;
+ }
+ // union of potentially set ones
+ potentialInits |= otherInits.potentialInits;
+
+ // treating extra storage
+ if (extraDefiniteInits != null) {
+ if (otherInits.extraDefiniteInits != null) {
+ // both sides have extra storage
+ int i = 0, length, otherLength;
+ if ((length = extraDefiniteInits.length)
+ < (otherLength = otherInits.extraDefiniteInits.length)) {
+ // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?)
+ System.arraycopy(
+ extraDefiniteInits,
+ 0,
+ (extraDefiniteInits = new long[otherLength]),
+ 0,
+ length);
+ System.arraycopy(
+ extraPotentialInits,
+ 0,
+ (extraPotentialInits = new long[otherLength]),
+ 0,
+ length);
+ while (i < length) {
+ extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
+ }
+ while (i < otherLength) {
+ extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
+ }
+ } else {
+ // current storage is longer
+ while (i < otherLength) {
+ extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
+ }
+ }
+ }
+ } else
+ if (otherInits.extraDefiniteInits != null) {
+ // no storage here, but other has extra storage.
+ int otherLength;
+ extraDefiniteInits =
+ new long[otherLength = otherInits.extraDefiniteInits.length];
+ System.arraycopy(
+ otherInits.extraPotentialInits,
+ 0,
+ (extraPotentialInits = new long[otherLength]),
+ 0,
+ otherLength);
+ }
+ return this;
+ }
+
+ public boolean complainIfUnreachable(Statement statement, BlockScope scope) {
+ // Report an error if necessary
+
+ boolean isDeadEnd;
+ if ((isDeadEnd = (this == DeadEnd)) || isFakeReachable) {
+ statement.bits &= ~Statement.IsReachableMASK;
+ /* EXTRA REFERENCE RECORDING
+ statement.recordUnreachableReferences(scope.referenceType()); // scopes cannot have an enclosingMethod slot since there are class scopes
+ */
+ if (isDeadEnd)
+ scope.problemReporter().unreachableCode(statement);
+ return isDeadEnd;
+ }
+ return false;
+ }
+
+ /**
+ * Answers a copy of the current instance
+ */
+ public FlowInfo copy() {
+ // do not clone the DeadEnd
+ if (this == DeadEnd)
+ return this;
+
+ // look for an unused preallocated object
+ UnconditionalFlowInfo copy = new UnconditionalFlowInfo();
+
+ // copy slots
+ copy.definiteInits = definiteInits;
+ copy.potentialInits = potentialInits;
+ copy.isFakeReachable = isFakeReachable;
+ copy.maxFieldCount = maxFieldCount;
+
+ if (extraDefiniteInits != null) {
+ int length;
+ System.arraycopy(
+ extraDefiniteInits,
+ 0,
+ (copy.extraDefiniteInits = new long[(length = extraDefiniteInits.length)]),
+ 0,
+ length);
+ System.arraycopy(
+ extraPotentialInits,
+ 0,
+ (copy.extraPotentialInits = new long[length]),
+ 0,
+ length);
+ };
+ return copy;
+ }
+
+ public FlowInfo initsWhenFalse() {
+ return this;
+ }
+
+ public FlowInfo initsWhenTrue() {
+ return this;
+ }
+
+ /**
+ * Check status of definite assignment at a given position.
+ * It deals with the dual representation of the InitializationInfo2:
+ * bits for the first 64 entries, then an array of booleans.
+ */
+ final private boolean isDefinitelyAssigned(int position) {
+ // Dependant of CodeStream.isDefinitelyAssigned(..)
+ // id is zero-based
+ if (position < BitCacheSize) {
+ return (definiteInits & (1L << position)) != 0; // use bits
+ }
+ // use extra vector
+ if (extraDefiniteInits == null)
+ return false; // if vector not yet allocated, then not initialized
+ int vectorIndex;
+ if ((vectorIndex = (position / BitCacheSize) - 1) >= extraDefiniteInits.length)
+ return false; // if not enough room in vector, then not initialized
+ return ((extraDefiniteInits[vectorIndex]) & (1L << (position % BitCacheSize)))
+ != 0;
+ }
+
+ /**
+ * Check status of definite assignment for a field.
+ */
+ final public boolean isDefinitelyAssigned(FieldBinding field) {
+ // We do not want to complain in unreachable code
+ if (this == DeadEnd)
+ return true;
+ return isDefinitelyAssigned(field.id);
+ }
+
+ /**
+ * Check status of definite assignment for a local.
+ */
+ final public boolean isDefinitelyAssigned(LocalVariableBinding local) {
+ // Dependant of CodeStream.isDefinitelyAssigned(..)
+ // We do not want to complain in unreachable code
+ if ((this == DeadEnd) || (this.isFakeReachable))
+ return true;
+ if (local.isArgument) {
+ return true;
+ }
+ return isDefinitelyAssigned(local.id + maxFieldCount);
+ }
+
+ public boolean isFakeReachable() {
+ return isFakeReachable;
+ }
+
+ /**
+ * Check status of potential assignment at a given position.
+ * It deals with the dual representation of the InitializationInfo3:
+ * bits for the first 64 entries, then an array of booleans.
+ */
+ final private boolean isPotentiallyAssigned(int position) {
+ // id is zero-based
+ if (position < BitCacheSize) {
+ // use bits
+ return (potentialInits & (1L << position)) != 0;
+ }
+ // use extra vector
+ if (extraPotentialInits == null)
+ return false; // if vector not yet allocated, then not initialized
+ int vectorIndex;
+ if ((vectorIndex = (position / BitCacheSize) - 1)
+ >= extraPotentialInits.length)
+ return false; // if not enough room in vector, then not initialized
+ return ((extraPotentialInits[vectorIndex]) & (1L << (position % BitCacheSize)))
+ != 0;
+ }
+
+ /**
+ * Check status of definite assignment for a field.
+ */
+ final public boolean isPotentiallyAssigned(FieldBinding field) {
+ // We do not want to complain in unreachable code
+ if (this == DeadEnd)
+ return false;
+ return isPotentiallyAssigned(field.id);
+ }
+
+ /**
+ * Check status of potential assignment for a local.
+ */
+ final public boolean isPotentiallyAssigned(LocalVariableBinding local) {
+ // We do not want to complain in unreachable code
+ if ((this == DeadEnd) || (this.isFakeReachable))
+ return false;
+ if (local.isArgument) {
+ return true;
+ }
+ return isPotentiallyAssigned(local.id + maxFieldCount);
+ }
+
+ /**
+ * Record a definite assignment at a given position.
+ * It deals with the dual representation of the InitializationInfo2:
+ * bits for the first 64 entries, then an array of booleans.
+ */
+ final private void markAsDefinitelyAssigned(int position) {
+ if (this != DeadEnd) {
+
+ // position is zero-based
+ if (position < BitCacheSize) {
+ // use bits
+ long mask;
+ definiteInits |= (mask = 1L << position);
+ potentialInits |= mask;
+ } else {
+ // use extra vector
+ int vectorIndex = (position / BitCacheSize) - 1;
+ if (extraDefiniteInits == null) {
+ int length;
+ extraDefiniteInits = new long[length = vectorIndex + 1];
+ extraPotentialInits = new long[length];
+ } else {
+ int oldLength; // might need to grow the arrays
+ if (vectorIndex >= (oldLength = extraDefiniteInits.length)) {
+ System.arraycopy(
+ extraDefiniteInits,
+ 0,
+ (extraDefiniteInits = new long[vectorIndex + 1]),
+ 0,
+ oldLength);
+ System.arraycopy(
+ extraPotentialInits,
+ 0,
+ (extraPotentialInits = new long[vectorIndex + 1]),
+ 0,
+ oldLength);
+ }
+ }
+ long mask;
+ extraDefiniteInits[vectorIndex] |= (mask = 1L << (position % BitCacheSize));
+ extraPotentialInits[vectorIndex] |= mask;
+ }
+ }
+ }
+
+ /**
+ * Record a field got definitely assigned.
+ */
+ public void markAsDefinitelyAssigned(FieldBinding field) {
+ if (this != DeadEnd)
+ markAsDefinitelyAssigned(field.id);
+ }
+
+ /**
+ * Record a local got definitely assigned.
+ */
+ public void markAsDefinitelyAssigned(LocalVariableBinding local) {
+ if (this != DeadEnd)
+ markAsDefinitelyAssigned(local.id + maxFieldCount);
+ }
+
+ /**
+ * Clear initialization information at a given position.
+ * It deals with the dual representation of the InitializationInfo2:
+ * bits for the first 64 entries, then an array of booleans.
+ */
+ final private void markAsDefinitelyNotAssigned(int position) {
+ if (this != DeadEnd) {
+
+ // position is zero-based
+ if (position < BitCacheSize) {
+ // use bits
+ long mask;
+ definiteInits &= ~(mask = 1L << position);
+ potentialInits &= ~mask;
+ } else {
+ // use extra vector
+ int vectorIndex = (position / BitCacheSize) - 1;
+ if (extraDefiniteInits == null) {
+ return; // nothing to do, it was not yet set
+ } else {
+ int oldLength; // might need to grow the arrays
+ if (vectorIndex >= (oldLength = extraDefiniteInits.length)) {
+ return; // nothing to do, it was not yet set
+ }
+ }
+ long mask;
+ extraDefiniteInits[vectorIndex] &= ~(mask = 1L << (position % BitCacheSize));
+ extraPotentialInits[vectorIndex] &= ~mask;
+ }
+ }
+ }
+
+ /**
+ * Clear the initialization info for a field
+ */
+ public void markAsDefinitelyNotAssigned(FieldBinding field) {
+ if (this != DeadEnd)
+ markAsDefinitelyNotAssigned(field.id);
+ }
+
+ /**
+ * Clear the initialization info for a local variable
+ */
+
+ public void markAsDefinitelyNotAssigned(LocalVariableBinding local) {
+ if (this != DeadEnd)
+ markAsDefinitelyNotAssigned(local.id + maxFieldCount);
+ }
+
+ public FlowInfo markAsFakeReachable(boolean isFakeReachable) {
+ this.isFakeReachable = isFakeReachable;
+ return this;
+ }
+
+ public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) {
+ // updates the receiver with:
+ // - intersection of definitely assigned variables,
+ // - union of potentially set ones
+
+ if (this == DeadEnd)
+ return otherInits;
+ if (otherInits == DeadEnd)
+ return this;
+
+ // if one branch is not fake reachable, then the merged one is reachable
+ if (!otherInits.isFakeReachable())
+ markAsFakeReachable(false);
+
+ // intersection of definitely assigned variables,
+ definiteInits &= otherInits.definiteInits;
+ // union of potentially set ones
+ potentialInits |= otherInits.potentialInits;
+
+ // treating extra storage
+ if (extraDefiniteInits != null) {
+ if (otherInits.extraDefiniteInits != null) {
+ // both sides have extra storage
+ int i = 0, length, otherLength;
+ if ((length = extraDefiniteInits.length)
+ < (otherLength = otherInits.extraDefiniteInits.length)) {
+ // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?)
+ System.arraycopy(
+ extraDefiniteInits,
+ 0,
+ (extraDefiniteInits = new long[otherLength]),
+ 0,
+ length);
+ System.arraycopy(
+ extraPotentialInits,
+ 0,
+ (extraPotentialInits = new long[otherLength]),
+ 0,
+ length);
+ while (i < length) {
+ extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i];
+ extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
+ }
+ while (i < otherLength) {
+ extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
+ }
+ } else {
+ // current storage is longer
+ while (i < otherLength) {
+ extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i];
+ extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
+ }
+ while (i < length)
+ extraDefiniteInits[i++] = 0;
+ }
+ } else {
+ // no extra storage on otherInits
+ int i = 0, length = extraDefiniteInits.length;
+ while (i < length)
+ extraDefiniteInits[i++] = 0;
+ }
+ } else
+ if (otherInits.extraDefiniteInits != null) {
+ // no storage here, but other has extra storage.
+ int otherLength;
+ extraDefiniteInits =
+ new long[otherLength = otherInits.extraDefiniteInits.length];
+ System.arraycopy(
+ otherInits.extraPotentialInits,
+ 0,
+ (extraPotentialInits = new long[otherLength]),
+ 0,
+ otherLength);
+ }
+ return this;
+ }
+
+ /*
+ * Answer the total number of fields in enclosing types of a given type
+ */
+ static int numberOfEnclosingFields(ReferenceBinding type) {
+ int count = 0;
+ type = type.enclosingType();
+ while (type != null) {
+ count += type.fieldCount();
+ type = type.enclosingType();
+ }
+ return count;
+ }
+
+ public String toString() {
+ if (this == DeadEnd) {
+ return "FlowInfo.DeadEnd";
+ }
+ return "FlowInfo<def: " + definiteInits + ", pot: " + potentialInits + ">";
+ }
+
+ public UnconditionalFlowInfo unconditionalInits() {
+ // also see conditional inits, where it requests them to merge
+ return this;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/BooleanConstant.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/BooleanConstant.java
new file mode 100644
index 0000000000..f8d9bd0521
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/BooleanConstant.java
@@ -0,0 +1,41 @@
+package org.eclipse.jdt.internal.compiler.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+public class BooleanConstant extends Constant {
+ boolean value;
+
+ public BooleanConstant(boolean value) {
+ this.value = value;
+ }
+
+ public boolean booleanValue() {
+ return (boolean) value;
+ }
+
+ public String stringValue() {
+ //spec 15.17.11
+
+ String s = new Boolean(value).toString();
+ if (s == null)
+ return "null";
+ else
+ return s;
+ }
+
+ public String toString() {
+
+ return "(boolean)" + value;
+ }
+
+ public int typeID() {
+ return T_boolean;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ByteConstant.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ByteConstant.java
new file mode 100644
index 0000000000..17719ee455
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ByteConstant.java
@@ -0,0 +1,56 @@
+package org.eclipse.jdt.internal.compiler.impl;
+
+public class ByteConstant extends Constant {
+ byte value;
+ public ByteConstant(byte value) {
+ this.value = value;
+ }
+
+ public byte byteValue() {
+ return (byte) value;
+ }
+
+ public char charValue() {
+ return (char) value;
+ }
+
+ public double doubleValue() {
+ return (double) value;
+ }
+
+ public float floatValue() {
+ return (float) value;
+ }
+
+ public int intValue() {
+ return (int) value;
+ }
+
+ public long longValue() {
+ return (long) value;
+ }
+
+ public short shortValue() {
+ return (short) value;
+ }
+
+ public String stringValue() {
+ //spec 15.17.11
+
+ String s = new Integer(value).toString();
+ if (s == null)
+ return "null";
+ else
+ return s;
+ }
+
+ public String toString() {
+
+ return "(byte)" + value;
+ }
+
+ public int typeID() {
+ return T_byte;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CharConstant.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CharConstant.java
new file mode 100644
index 0000000000..313a0520a7
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CharConstant.java
@@ -0,0 +1,64 @@
+package org.eclipse.jdt.internal.compiler.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+public class CharConstant extends Constant {
+ char value;
+ public CharConstant(char value) {
+ this.value = value;
+ }
+
+ public byte byteValue() {
+ return (byte) value;
+ }
+
+ public char charValue() {
+ return (char) value;
+ }
+
+ public double doubleValue() {
+ return (double) value;
+ }
+
+ public float floatValue() {
+ return (float) value;
+ }
+
+ public int intValue() {
+ return (int) value;
+ }
+
+ public long longValue() {
+ return (long) value;
+ }
+
+ public short shortValue() {
+ return (short) value;
+ }
+
+ public String stringValue() {
+ //spec 15.17.11
+
+ String s = new Character(value).toString();
+ if (s == null)
+ return "null";
+ else
+ return s;
+ }
+
+ public String toString() {
+
+ return "(char)" + value;
+ }
+
+ public int typeID() {
+ return T_char;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
new file mode 100644
index 0000000000..8f45ea2079
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
@@ -0,0 +1,523 @@
+package org.eclipse.jdt.internal.compiler.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.Locale;
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class CompilerOptions
+ implements ConfigurableProblems, ProblemIrritants, ProblemReasons, ProblemSeverities {
+
+ // class file output
+ // these are the bits used to buld a mask to know which debug
+ // attributes should be included in the .class file
+ // By default only lines and source attributes are generated.
+ public static final int Source = 1; // SourceFileAttribute
+ public static final int Lines = 2; // LineNumberAttribute
+ public static final int Vars = 4; // LocalVariableTableAttribute
+
+ public int produceDebugAttributes = Lines | Source;
+
+ // default severity level for handlers
+ public int errorThreshold = UnreachableCode | ImportProblem;
+ public int warningThreshold =
+ ParsingOptionalError
+ | MethodWithConstructorName
+ | OverriddenPackageDefaultMethod
+ | UsingDeprecatedAPI
+ | MaskedCatchBlock
+ | UnusedLocalVariable
+ | UnusedArgument
+ | TemporaryWarning;
+
+ // target JDK 1.1 or 1.2
+ public static final int JDK1_1 = 0;
+ public static final int JDK1_2 = 1;
+ public int targetJDK = JDK1_1; // default generates for JVM1.1
+
+ // print what unit is being processed
+ public boolean verbose = false;
+ // indicates if reference info is desired
+ public boolean produceReferenceInfo = true;
+ // indicates if unused/optimizable local variables need to be preserved (debugging purpose)
+ public boolean preserveAllLocalVariables = false;
+ // indicates whether literal expressions are inlined at parse-time or not
+ public boolean parseLiteralExpressionsAsConstants = true;
+
+ // exception raised for unresolved compile errors
+ public String runtimeExceptionNameForCompileError = "java.lang.Error";
+
+ // toggle private access emulation for 1.2 (constr. accessor has extra arg on constructor) or 1.3 (make private constructor default access when access needed)
+ public boolean isPrivateConstructorAccessChangingVisibility = false;
+ // by default, follows 1.2
+ /**
+ * Initializing the compiler options with defaults
+ */
+ public CompilerOptions() {
+ }
+
+ /**
+ * Initializing the compiler options with external settings
+ */
+ public CompilerOptions(ConfigurableOption[] settings) {
+ if (settings == null)
+ return;
+ // filter options which are related to the compiler component
+ String componentName = Compiler.class.getName();
+ for (int i = 0, max = settings.length; i < max; i++) {
+ if (settings[i].getComponentName().equals(componentName)) {
+ this.setOption(settings[i]);
+ }
+ }
+ }
+
+ /**
+ * Returns all the options of the compiler to be shown by the UI
+ *
+ * @param locale java.util.Locale
+ * @return org.eclipse.jdt.internal.compiler.ConfigurableOption[]
+ */
+ public ConfigurableOption[] getConfigurableOptions(Locale locale) {
+ String componentName = Compiler.class.getName();
+ return new ConfigurableOption[] {
+ new ConfigurableOption(
+ componentName,
+ "debug.vars",
+ locale,
+ (produceDebugAttributes & Vars) != 0 ? 0 : 1),
+ new ConfigurableOption(
+ componentName,
+ "debug.lines",
+ locale,
+ (produceDebugAttributes & Lines) != 0 ? 0 : 1),
+ new ConfigurableOption(
+ componentName,
+ "debug.source",
+ locale,
+ (produceDebugAttributes & Source) != 0 ? 0 : 1),
+ new ConfigurableOption(
+ componentName,
+ "debug.preserveAllLocals",
+ locale,
+ preserveAllLocalVariables ? 0 : 1),
+ new ConfigurableOption(
+ componentName,
+ "optionalError.unReachableCode",
+ locale,
+ (errorThreshold & UnreachableCode) != 0 ? 0 : 1),
+ new ConfigurableOption(
+ componentName,
+ "optionalError.importProblem",
+ locale,
+ (errorThreshold & ImportProblem) != 0 ? 0 : 1),
+ new ConfigurableOption(
+ componentName,
+ "optionalWarning.methodWithConstructorName",
+ locale,
+ (warningThreshold & MethodWithConstructorName) != 0 ? 0 : 1),
+ new ConfigurableOption(
+ componentName,
+ "optionalWarning.overridingPackageDefaultMethod",
+ locale,
+ (warningThreshold & OverriddenPackageDefaultMethod) != 0 ? 0 : 1),
+ new ConfigurableOption(
+ componentName,
+ "optionalWarning.deprecated",
+ locale,
+ (warningThreshold & UsingDeprecatedAPI) != 0 ? 0 : 1),
+ new ConfigurableOption(
+ componentName,
+ "optionalWarning.maskedCatchBlock",
+ locale,
+ (warningThreshold & MaskedCatchBlock) != 0 ? 0 : 1),
+ new ConfigurableOption(
+ componentName,
+ "optionalWarning.unusedLocalVariable",
+ locale,
+ (warningThreshold & UnusedLocalVariable) != 0 ? 0 : 1),
+ new ConfigurableOption(
+ componentName,
+ "optionalWarning.unusedArgument",
+ locale,
+ (warningThreshold & UnusedArgument) != 0 ? 0 : 1),
+ new ConfigurableOption(
+ componentName,
+ "binaryCompatibility.targetJDK",
+ locale,
+ targetJDK),
+ new ConfigurableOption(
+ componentName,
+ "optionalWarning.accessEmulation",
+ locale,
+ (warningThreshold & AccessEmulation) != 0 ? 0 : 1)};
+ }
+
+ public int getDebugAttributesMask() {
+ return this.produceDebugAttributes;
+ }
+
+ public int getTargetJDK() {
+ return this.targetJDK;
+ }
+
+ public void handleAccessEmulationAsWarning(boolean flag) {
+ if (flag) {
+ warningThreshold |= AccessEmulation;
+ } else {
+ warningThreshold &= ~AccessEmulation;
+ }
+ }
+
+ public void handleDeprecationUseAsWarning(boolean flag) {
+ if (flag) {
+ warningThreshold |= UsingDeprecatedAPI;
+ } else {
+ warningThreshold &= ~UsingDeprecatedAPI;
+ }
+ }
+
+ public void handleImportProblemAsError(boolean flag) {
+ if (flag) {
+ errorThreshold |= ImportProblem;
+ warningThreshold &= ~ImportProblem;
+ } else {
+ errorThreshold &= ~ImportProblem;
+ warningThreshold |= ImportProblem;
+ }
+ }
+
+ public void handleMaskedCatchBlockAsWarning(boolean flag) {
+ if (flag) {
+ warningThreshold |= MaskedCatchBlock;
+ } else {
+ warningThreshold &= ~MaskedCatchBlock;
+ }
+ }
+
+ public void handleMethodWithConstructorNameAsWarning(boolean flag) {
+ if (flag) {
+ warningThreshold |= MethodWithConstructorName;
+ } else {
+ warningThreshold &= ~MethodWithConstructorName;
+ }
+ }
+
+ public void handleObsoleteLiteralAsError(boolean flag) {
+ if (flag) {
+ errorThreshold |= ParsingOptionalError;
+ warningThreshold &= ~ParsingOptionalError;
+ } else {
+ errorThreshold &= ~ParsingOptionalError;
+ warningThreshold |= ParsingOptionalError;
+ }
+ }
+
+ public void handleOverriddenPackageDefaultMethodAsWarning(boolean flag) {
+ if (flag) {
+ warningThreshold |= OverriddenPackageDefaultMethod;
+ } else {
+ warningThreshold &= ~OverriddenPackageDefaultMethod;
+ }
+ }
+
+ public void handleUnreachableCodeAsError(boolean flag) {
+ if (flag) {
+ errorThreshold |= UnreachableCode;
+ warningThreshold &= ~UnreachableCode;
+ } else {
+ errorThreshold &= ~UnreachableCode;
+ warningThreshold |= UnreachableCode;
+ }
+ }
+
+ public void handleUnusedArgumentAsWarning(boolean flag) {
+ if (flag) {
+ warningThreshold |= UnusedArgument;
+ } else {
+ warningThreshold &= ~UnusedArgument;
+ }
+ }
+
+ public void handleUnusedLocalVariableAsWarning(boolean flag) {
+ if (flag) {
+ warningThreshold |= UnusedLocalVariable;
+ } else {
+ warningThreshold &= ~UnusedLocalVariable;
+ }
+ }
+
+ public boolean isAccessEmulationHandledAsWarning() {
+ return (warningThreshold & AccessEmulation) != 0;
+ }
+
+ public boolean isDeprecationUseHandledAsWarning() {
+ return (warningThreshold & UsingDeprecatedAPI) != 0;
+ }
+
+ public boolean isImportProblemHandledAsError() {
+ return (errorThreshold & ImportProblem) != 0;
+ }
+
+ public boolean isMaskedCatchBlockHandledAsWarning() {
+ return (warningThreshold & MaskedCatchBlock) != 0;
+ }
+
+ public boolean isMethodWithConstructorNameHandledAsWarning() {
+ return (warningThreshold & MethodWithConstructorName) != 0;
+ }
+
+ public boolean isObsoleteLiteralAsHandledError() {
+ return (errorThreshold & ParsingOptionalError) != 0;
+ }
+
+ public boolean isOverriddenPackageDefaultMethodHandledAsWarning() {
+ return (warningThreshold & OverriddenPackageDefaultMethod) != 0;
+ }
+
+ public boolean isPreservingAllLocalVariables() {
+ return this.preserveAllLocalVariables;
+ }
+
+ public boolean isPrivateConstructorAccessChangingVisibility() {
+ return isPrivateConstructorAccessChangingVisibility;
+ }
+
+ public boolean isUnreachableCodeHandledAsError() {
+ return (errorThreshold & UnreachableCode) != 0;
+ }
+
+ public boolean isUnusedArgumentHandledAsWarning() {
+ return (warningThreshold & UnusedArgument) != 0;
+ }
+
+ public boolean isUnusedLocalVariableHandledAsWarning() {
+ return (warningThreshold & UnusedLocalVariable) != 0;
+ }
+
+ public void preserveAllLocalVariables(boolean flag) {
+ this.preserveAllLocalVariables = flag;
+ }
+
+ public void privateConstructorAccessChangesVisibility(boolean flag) {
+ isPrivateConstructorAccessChangingVisibility = flag;
+ }
+
+ public void produceDebugAttributes(int mask) {
+ this.produceDebugAttributes = mask;
+ }
+
+ public void produceReferenceInfo(boolean flag) {
+ this.produceReferenceInfo = flag;
+ }
+
+ public void setErrorThreshold(int errorMask) {
+ this.errorThreshold = errorMask;
+ }
+
+ /**
+ * Change the value of the option corresponding to the option number
+ *
+ * @param optionNumber <CODE>int</CODE>
+ * @param setting.getCurrentValueIndex() <CODE>int</CODE>
+ */
+ void setOption(ConfigurableOption setting) {
+
+ switch (setting.getID()) {
+ case 1 : // Local variable table attribute
+ if (setting.getCurrentValueIndex() == 0) {
+ // set the debug flag with Vars.
+ produceDebugAttributes |= Vars;
+ } else {
+ produceDebugAttributes &= ~Vars;
+ }
+ break;
+ case 2 : // Line number attribute
+ if (setting.getCurrentValueIndex() == 0) {
+ // set the debug flag with Lines
+ produceDebugAttributes |= Lines;
+ } else {
+ produceDebugAttributes &= ~Lines;
+ }
+ break;
+ case 3 : // source file attribute
+ if (setting.getCurrentValueIndex() == 0) {
+ // set the debug flag with Source.
+ produceDebugAttributes |= Source;
+ } else {
+ produceDebugAttributes &= ~Source;
+ }
+ break;
+ case 4 : // preserveAllLocals flag
+ preserveAllLocalVariables(setting.getCurrentValueIndex() == 0);
+ break;
+ case 5 : // unreachable code reported as error
+ handleUnreachableCodeAsError(setting.getCurrentValueIndex() == 0);
+ break;
+ case 6 : // invalid import
+ handleImportProblemAsError(setting.getCurrentValueIndex() == 0);
+ break;
+ case 7 : // methods with constructor name
+ handleMethodWithConstructorNameAsWarning(setting.getCurrentValueIndex() == 0);
+ break;
+ case 8 : // overridden package default method
+ handleOverriddenPackageDefaultMethodAsWarning(
+ setting.getCurrentValueIndex() == 0);
+ break;
+ case 9 : // use of deprecated API
+ handleDeprecationUseAsWarning(setting.getCurrentValueIndex() == 0);
+ break;
+ case 10 : // catch block hidden by another one
+ handleMaskedCatchBlockAsWarning(setting.getCurrentValueIndex() == 0);
+ break;
+ case 11 : // local variable not used
+ handleUnusedLocalVariableAsWarning(setting.getCurrentValueIndex() == 0);
+ break;
+ case 12 : // argument not used
+ handleUnusedArgumentAsWarning(setting.getCurrentValueIndex() == 0);
+ break;
+ case 13 : // temporary warning
+ if (setting.getCurrentValueIndex() == 0) {
+ warningThreshold |= TemporaryWarning;
+ }
+ break;
+ case 14 : // target JDK
+ setTargetJDK(setting.getCurrentValueIndex() == 0 ? JDK1_1 : JDK1_2);
+ break;
+ case 15 : // synthetic access emulation
+ handleAccessEmulationAsWarning(setting.getCurrentValueIndex() == 0);
+ break;
+ }
+ }
+
+ public void setTargetJDK(int vmID) {
+ this.targetJDK = vmID;
+ }
+
+ public void setVerboseMode(boolean flag) {
+ this.verbose = flag;
+ }
+
+ public void setWarningThreshold(int warningMask) {
+ this.warningThreshold = warningMask;
+ }
+
+ public String toString() {
+
+ StringBuffer buf = new StringBuffer("CompilerOptions:");
+ if ((produceDebugAttributes & Vars) != 0) {
+ buf.append("\n-local variables debug attributes: ON");
+ } else {
+ buf.append("\n-local variables debug attributes: OFF");
+ }
+ if ((produceDebugAttributes & Lines) != 0) {
+ buf.append("\n-line number debug attributes: ON");
+ } else {
+ buf.append("\n-line number debug attributes: OFF");
+ }
+ if ((produceDebugAttributes & Source) != 0) {
+ buf.append("\n-source debug attributes: ON");
+ } else {
+ buf.append("\n-source debug attributes: OFF");
+ }
+ if (preserveAllLocalVariables) {
+ buf.append("\n-preserve all local variables: ON");
+ } else {
+ buf.append("\n-preserve all local variables: OFF");
+ }
+ if ((errorThreshold & UnreachableCode) != 0) {
+ buf.append("\n-unreachable code: ERROR");
+ } else {
+ if ((warningThreshold & UnreachableCode) != 0) {
+ buf.append("\n-unreachable code: WARNING");
+ } else {
+ buf.append("\n-unreachable code: IGNORE");
+ }
+ }
+ if ((errorThreshold & ImportProblem) != 0) {
+ buf.append("\n-import problem: ERROR");
+ } else {
+ if ((warningThreshold & ImportProblem) != 0) {
+ buf.append("\n-import problem: WARNING");
+ } else {
+ buf.append("\n-import problem: IGNORE");
+ }
+ }
+ if ((errorThreshold & MethodWithConstructorName) != 0) {
+ buf.append("\n-method with constructor name: ERROR");
+ } else {
+ if ((warningThreshold & MethodWithConstructorName) != 0) {
+ buf.append("\n-method with constructor name: WARNING");
+ } else {
+ buf.append("\n-method with constructor name: IGNORE");
+ }
+ }
+ if ((errorThreshold & OverriddenPackageDefaultMethod) != 0) {
+ buf.append("\n-overridden package default method: ERROR");
+ } else {
+ if ((warningThreshold & OverriddenPackageDefaultMethod) != 0) {
+ buf.append("\n-overridden package default method: WARNING");
+ } else {
+ buf.append("\n-overridden package default method: IGNORE");
+ }
+ }
+ if ((errorThreshold & UsingDeprecatedAPI) != 0) {
+ buf.append("\n-deprecation: ERROR");
+ } else {
+ if ((warningThreshold & UsingDeprecatedAPI) != 0) {
+ buf.append("\n-deprecation: WARNING");
+ } else {
+ buf.append("\n-deprecation: IGNORE");
+ }
+ }
+ if ((errorThreshold & MaskedCatchBlock) != 0) {
+ buf.append("\n-masked catch block: ERROR");
+ } else {
+ if ((warningThreshold & MaskedCatchBlock) != 0) {
+ buf.append("\n-masked catch block: WARNING");
+ } else {
+ buf.append("\n-masked catch block: IGNORE");
+ }
+ }
+ if ((errorThreshold & UnusedLocalVariable) != 0) {
+ buf.append("\n-unused local variable: ERROR");
+ } else {
+ if ((warningThreshold & UnusedLocalVariable) != 0) {
+ buf.append("\n-unused local variable: WARNING");
+ } else {
+ buf.append("\n-unused local variable: IGNORE");
+ }
+ }
+ if ((errorThreshold & UnusedArgument) != 0) {
+ buf.append("\n-unused parameter: ERROR");
+ } else {
+ if ((warningThreshold & UnusedArgument) != 0) {
+ buf.append("\n-unused parameter: WARNING");
+ } else {
+ buf.append("\n-unused parameter: IGNORE");
+ }
+ }
+ switch (targetJDK) {
+ case JDK1_1 :
+ buf.append("\n-target JDK: 1.1");
+ break;
+ case JDK1_2 :
+ buf.append("\n-target JDK: 1.2");
+ }
+ buf.append("\n-verbose : " + (verbose ? "ON" : "OFF"));
+ buf.append(
+ "\n-produce reference info : " + (produceReferenceInfo ? "ON" : "OFF"));
+ buf.append(
+ "\n-parse literal expressions as constants : "
+ + (parseLiteralExpressionsAsConstants ? "ON" : "OFF"));
+ buf.append(
+ "\n-runtime exception name for compile error : "
+ + runtimeExceptionNameForCompileError);
+ return buf.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ConfigurableProblems.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ConfigurableProblems.java
new file mode 100644
index 0000000000..85e85f9cda
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ConfigurableProblems.java
@@ -0,0 +1,15 @@
+package org.eclipse.jdt.internal.compiler.impl;
+
+public interface ConfigurableProblems {
+ final int UnreachableCode = 0x100;
+ final int ParsingOptionalError = 0x200;
+ final int ImportProblem = 0x400;
+ final int MethodWithConstructorName = 0x1000;
+ final int OverriddenPackageDefaultMethod = 0x2000;
+ final int UsingDeprecatedAPI = 0x4000;
+ final int MaskedCatchBlock = 0x8000;
+ final int UnusedLocalVariable = 0x10000;
+ final int UnusedArgument = 0x20000;
+ final int TemporaryWarning = 0x40000;
+ final int AccessEmulation = 0x80000;
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/Constant.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/Constant.java
new file mode 100644
index 0000000000..14c39d2be8
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/Constant.java
@@ -0,0 +1,2553 @@
+package org.eclipse.jdt.internal.compiler.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public abstract class Constant implements TypeIds, OperatorIds {
+ public static final Constant NotAConstant = new DoubleConstant(Double.NaN);
+
+ public static final IntConstant Zero = new IntConstant(0);
+ public static final IntConstant Two = new IntConstant(2);
+ public static final IntConstant One = new IntConstant(1);
+ public boolean booleanValue() {
+ throw new ShouldNotImplement(
+ typeName() + " constant cannot be casted into boolean");
+ }
+
+ public byte byteValue() {
+ throw new ShouldNotImplement(
+ typeName() + " constant cannot be casted into byte");
+ }
+
+ public final Constant castTo(int conversionToTargetType) {
+ //the cast is an int of the form
+ // (castId<<4)+typeId (in order to follow the
+ //user written style (cast)expression ....
+ //This method assumes that the TC is done (correctly :-)
+
+ if (this == NotAConstant)
+ return NotAConstant;
+ switch (conversionToTargetType) {
+ case T_undefined :
+ return this;
+ // case (T_undefined<<4)+T_undefined : return NotAConstant ;
+ // case (T_undefined<<4)+T_byte : return NotAConstant ;
+ // case (T_undefined<<4)+T_long : return NotAConstant ;
+ // case (T_undefined<<4)+T_short : return NotAConstant ;
+ // case (T_undefined<<4)+T_void : return NotAConstant ;
+ // case (T_undefined<<4)+T_String : return NotAConstant ;
+ // case (T_undefined<<4)+T_Object : return NotAConstant ;
+ // case (T_undefined<<4)+T_double : return NotAConstant ;
+ // case (T_undefined<<4)+T_float : return NotAConstant ;
+ // case (T_undefined<<4)+T_boolean : return NotAConstant ;
+ // case (T_undefined<<4)+T_char : return NotAConstant ;
+ // case (T_undefined<<4)+T_int : return NotAConstant ;
+ // case (T_undefined<<4)+T_null : return NotAConstant ;
+
+ // case (T_byte<<4)+T_undefined : return NotAConstant ;
+ case (T_byte << 4) + T_byte :
+ return this;
+ case (T_byte << 4) + T_long :
+ return Constant.fromValue((byte) this.longValue());
+ case (T_byte << 4) + T_short :
+ return Constant.fromValue((byte) this.shortValue());
+ // case (T_byte<<4)+T_void : return NotAConstant ;
+ // case (T_byte<<4)+T_String : return NotAConstant ;
+ // case (T_byte<<4)+T_Object : return NotAConstant ;
+ case (T_byte << 4) + T_double :
+ return Constant.fromValue((byte) this.doubleValue());
+ case (T_byte << 4) + T_float :
+ return Constant.fromValue((byte) this.floatValue());
+ // case (T_byte<<4)+T_boolean : return NotAConstant ;
+ case (T_byte << 4) + T_char :
+ return Constant.fromValue((byte) this.charValue());
+ case (T_byte << 4) + T_int :
+ return Constant.fromValue((byte) this.intValue());
+ // case (T_byte<<4)+T_null : return NotAConstant ;
+
+ // case (T_long<<4)+T_undefined : return NotAConstant ;
+ case (T_long << 4) + T_byte :
+ return Constant.fromValue((long) this.byteValue());
+ case (T_long << 4) + T_long :
+ return this;
+ case (T_long << 4) + T_short :
+ return Constant.fromValue((long) this.shortValue());
+ ;
+ // case (T_long<<4)+T_void : return NotAConstant ;
+ // case (T_long<<4)+T_String : return NotAConstant ;
+ // case (T_long<<4)+T_Object : return NotAConstant ;
+ case (T_long << 4) + T_double :
+ return Constant.fromValue((long) this.doubleValue());
+ ;
+ case (T_long << 4) + T_float :
+ return Constant.fromValue((long) this.floatValue());
+ ;
+ // case (T_long<<4)+T_boolean : return NotAConstant ;
+ case (T_long << 4) + T_char :
+ return Constant.fromValue((long) this.charValue());
+ ;
+ case (T_long << 4) + T_int :
+ return Constant.fromValue((long) this.intValue());
+ ;
+ // case (T_long<<4)+T_null : return NotAConstant ;
+
+ // case (T_short<<4)+T_undefined : return NotAConstant ;
+ case (T_short << 4) + T_byte :
+ return Constant.fromValue((short) this.byteValue());
+ ;
+ case (T_short << 4) + T_long :
+ return Constant.fromValue((short) this.longValue());
+ ;
+ case (T_short << 4) + T_short :
+ return this;
+ // case (T_short<<4)+T_void : return NotAConstant ;
+ // case (T_short<<4)+T_String : return NotAConstant ;
+ // case (T_short<<4)+T_Object : return NotAConstant ;
+ case (T_short << 4) + T_double :
+ return Constant.fromValue((short) this.doubleValue());
+ case (T_short << 4) + T_float :
+ return Constant.fromValue((short) this.floatValue());
+ // case (T_short<<4)+T_boolean : return NotAConstant ;
+ case (T_short << 4) + T_char :
+ return Constant.fromValue((short) this.charValue());
+ case (T_short << 4) + T_int :
+ return Constant.fromValue((short) this.intValue());
+ // case (T_short<<4)+T_null : return NotAConstant ;
+
+ // case (T_void<<4)+T_undefined : return NotAConstant ;
+ // case (T_void<<4)+T_byte : return NotAConstant ;
+ // case (T_void<<4)+T_long : return NotAConstant ;
+ // case (T_void<<4)+T_short : return NotAConstant ;
+ // case (T_void<<4)+T_void : return NotAConstant ;
+ // case (T_void<<4)+T_String : return NotAConstant ;
+ // case (T_void<<4)+T_Object : return NotAConstant ;
+ // case (T_void<<4)+T_double : return NotAConstant ;
+ // case (T_void<<4)+T_float : return NotAConstant ;
+ // case (T_void<<4)+T_boolean : return NotAConstant ;
+ // case (T_void<<4)+T_char : return NotAConstant ;
+ // case (T_void<<4)+T_int : return NotAConstant ;
+ // case (T_void<<4)+T_null : return NotAConstant ;
+
+ // case (T_String<<4)+T_undefined : return NotAConstant ;
+ // case (T_String<<4)+T_byte : return NotAConstant ;
+ // case (T_String<<4)+T_long : return NotAConstant ;
+ // case (T_String<<4)+T_short : return NotAConstant ;
+ // case (T_String<<4)+T_void : return NotAConstant ;
+ case (T_String << 4) + T_String :
+ return this;
+ // case (T_String<<4)+T_Object : return NotAConstant ;
+ // case (T_String<<4)+T_double : return NotAConstant ;
+ // case (T_String<<4)+T_float : return NotAConstant ;
+ // case (T_String<<4)+T_boolean : return NotAConstant ;
+ // case (T_String<<4)+T_char : return NotAConstant ;
+ // case (T_String<<4)+T_int : return NotAConstant ;
+ // case (T_String<<4)+T_null : return NotAConstant ;
+
+ // case (T_Object<<4)+T_undefined : return NotAConstant ;
+ // case (T_Object<<4)+T_byte : return NotAConstant ;
+ // case (T_Object<<4)+T_long : return NotAConstant ;
+ // case (T_Object<<4)+T_short : return NotAConstant ;
+ // case (T_Object<<4)+T_void : return NotAConstant ;
+ // case (T_Object<<4)+T_String : return NotAConstant ;
+ // case (T_Object<<4)+T_Object : return NotAConstant ;
+ // case (T_Object<<4)+T_double : return NotAConstant ;
+ // case (T_Object<<4)+T_float : return NotAConstant ;
+ // case (T_Object<<4)+T_boolean : return NotAConstant ;
+ // case (T_Object<<4)+T_char : return NotAConstant ;
+ // case (T_Object<<4)+T_int : return NotAConstant ;
+ case (T_Object << 4) + T_null :
+ return this;
+
+ // case (T_double<<4)+T_undefined : return NotAConstant ;
+ case (T_double << 4) + T_byte :
+ return Constant.fromValue((double) this.byteValue());
+ case (T_double << 4) + T_long :
+ return Constant.fromValue((double) this.longValue());
+ case (T_double << 4) + T_short :
+ return Constant.fromValue((double) this.shortValue());
+ // case (T_double<<4)+T_void : return NotAConstant ;
+ // case (T_double<<4)+T_String : return NotAConstant ;
+ // case (T_double<<4)+T_Object : return NotAConstant ;
+ case (T_double << 4) + T_double :
+ return this;
+ case (T_double << 4) + T_float :
+ return Constant.fromValue((double) this.floatValue());
+ // case (T_double<<4)+T_boolean : return NotAConstant ;
+ case (T_double << 4) + T_char :
+ return Constant.fromValue((double) this.charValue());
+ case (T_double << 4) + T_int :
+ return Constant.fromValue((double) this.intValue());
+ // case (T_double<<4)+T_null : return NotAConstant ;
+
+ // case (T_float<<4)+T_undefined : return NotAConstant ;
+ case (T_float << 4) + T_byte :
+ return Constant.fromValue((float) this.byteValue());
+ case (T_float << 4) + T_long :
+ return Constant.fromValue((float) this.longValue());
+ case (T_float << 4) + T_short :
+ return Constant.fromValue((float) this.shortValue());
+ // case (T_float<<4)+T_void : return NotAConstant ;
+ // case (T_float<<4)+T_String : return NotAConstant ;
+ // case (T_float<<4)+T_Object : return NotAConstant ;
+ case (T_float << 4) + T_double :
+ return Constant.fromValue((float) this.doubleValue());
+ case (T_float << 4) + T_float :
+ return this;
+ // case (T_float<<4)+T_boolean : return NotAConstant ;
+ case (T_float << 4) + T_char :
+ return Constant.fromValue((float) this.charValue());
+ case (T_float << 4) + T_int :
+ return Constant.fromValue((float) this.intValue());
+ // case (T_float<<4)+T_null : return NotAConstant ;
+
+ // case (T_boolean<<4)+T_undefined : return NotAConstant ;
+ // case (T_boolean<<4)+T_byte : return NotAConstant ;
+ // case (T_boolean<<4)+T_long : return NotAConstant ;
+ // case (T_boolean<<4)+T_short : return NotAConstant ;
+ // case (T_boolean<<4)+T_void : return NotAConstant ;
+ // case (T_boolean<<4)+T_String : return NotAConstant ;
+ // case (T_boolean<<4)+T_Object : return NotAConstant ;
+ // case (T_boolean<<4)+T_double : return NotAConstant ;
+ // case (T_boolean<<4)+T_float : return NotAConstant ;
+ case (T_boolean << 4) + T_boolean :
+ return this;
+ // case (T_boolean<<4)+T_char : return NotAConstant ;
+ // case (T_boolean<<4)+T_int : return NotAConstant ;
+ // case (T_boolean<<4)+T_null : return NotAConstant ;
+
+ // case (T_char<<4)+T_undefined : return NotAConstant ;
+ case (T_char << 4) + T_byte :
+ return Constant.fromValue((char) this.byteValue());
+ case (T_char << 4) + T_long :
+ return Constant.fromValue((char) this.longValue());
+ case (T_char << 4) + T_short :
+ return Constant.fromValue((char) this.shortValue());
+ // case (T_char<<4)+T_void : return NotAConstant ;
+ // case (T_char<<4)+T_String : return NotAConstant ;
+ // case (T_char<<4)+T_Object : return NotAConstant ;
+ case (T_char << 4) + T_double :
+ return Constant.fromValue((char) this.doubleValue());
+ case (T_char << 4) + T_float :
+ return Constant.fromValue((char) this.floatValue());
+ // case (T_char<<4)+T_boolean : return NotAConstant ;
+ case (T_char << 4) + T_char :
+ return this;
+ case (T_char << 4) + T_int :
+ return Constant.fromValue((char) this.intValue());
+ // case (T_char<<4)+T_null : return NotAConstant ;
+
+ // case (T_int<<4)+T_undefined : return NotAConstant ;
+ case (T_int << 4) + T_byte :
+ return Constant.fromValue((int) this.byteValue());
+ case (T_int << 4) + T_long :
+ return Constant.fromValue((int) this.longValue());
+ case (T_int << 4) + T_short :
+ return Constant.fromValue((int) this.shortValue());
+ // case (T_int<<4)+T_void : return NotAConstant ;
+ // case (T_int<<4)+T_String : return NotAConstant ;
+ // case (T_int<<4)+T_Object : return NotAConstant ;
+ case (T_int << 4) + T_double :
+ return Constant.fromValue((int) this.doubleValue());
+ case (T_int << 4) + T_float :
+ return Constant.fromValue((int) this.floatValue());
+ // case (T_int<<4)+T_boolean : return NotAConstant ;
+ case (T_int << 4) + T_char :
+ return Constant.fromValue((int) this.charValue());
+ case (T_int << 4) + T_int :
+ return this;
+ // case (T_int<<4)+T_null : return NotAConstant ;
+
+ // case (T_null<<4)+T_undefined : return NotAConstant ;
+ // case (T_null<<4)+T_byte : return NotAConstant ;
+ // case (T_null<<4)+T_long : return NotAConstant ;
+ // case (T_null<<4)+T_short : return NotAConstant ;
+ // case (T_null<<4)+T_void : return NotAConstant ;
+ // case (T_null<<4)+T_String : return NotAConstant ;
+ // case (T_null<<4)+T_Object : return NotAConstant ;
+ // case (T_null<<4)+T_double : return NotAConstant ;
+ // case (T_null<<4)+T_float : return NotAConstant ;
+ // case (T_null<<4)+T_boolean : return NotAConstant ;
+ // case (T_null<<4)+T_char : return NotAConstant ;
+ // case (T_null<<4)+T_int : return NotAConstant ;
+ case (T_null << 4) + T_null :
+ return this;
+ }
+
+ return NotAConstant;
+ }
+
+ public char charValue() {
+ throw new ShouldNotImplement(
+ typeName() + " constant cannot be casted into char");
+ }
+
+ public static final Constant computeConstantOperation(
+ Constant cst,
+ int id,
+ int operator) {
+ //this method assumes that the TC has been done .
+ //the result should be availbale with not runtime error
+
+ switch (operator) {
+ case NOT :
+ if (cst.booleanValue() == true)
+ return Constant.fromValue(false);
+ return Constant.fromValue(true);
+ case PLUS :
+ return cst; //apriori we do not need to clone it
+ case MINUS : //the two special -9223372036854775808L and -2147483648 are inlined at parseTime
+ switch (id) {
+ case T_float :
+ float f;
+ if ((f = cst.floatValue()) == 0.0f) { //positive and negative 0....
+ if (Float.floatToIntBits(f) == 0)
+ return Constant.fromValue(-0.0f);
+ else
+ return Constant.fromValue(0.0f);
+ }
+ break; //default case
+ case T_double :
+ double d;
+ if ((d = cst.doubleValue()) == 0.0d) { //positive and negative 0....
+ if (Double.doubleToLongBits(d) == 0)
+ return Constant.fromValue(-0.0d);
+ else
+ return Constant.fromValue(0.0d);
+ }
+ break; //default case
+ }
+ return computeConstantOperationMINUS(Zero, T_int, operator, cst, id);
+ case TWIDDLE :
+ switch (id) {
+ case T_char :
+ return Constant.fromValue(~cst.charValue());
+ case T_byte :
+ return Constant.fromValue(~cst.byteValue());
+ case T_short :
+ return Constant.fromValue(~cst.shortValue());
+ case T_int :
+ return Constant.fromValue(~cst.intValue());
+ case T_long :
+ return Constant.fromValue(~cst.longValue());
+ default :
+ return NotAConstant;
+ } //should not occur.....(conservative code)
+ default :
+ return NotAConstant;
+ }
+ } //should not occur....(conservative code)
+
+ public static final Constant computeConstantOperation(
+ Constant left,
+ int leftId,
+ int operator,
+ Constant right,
+ int rightId) {
+ //this method assumes that the TC has been done . So (except for divide by zero)
+ //the result should be availbale with not runtime error
+
+ switch (operator) {
+ case AND :
+ return computeConstantOperationAND(left, leftId, operator, right, rightId);
+ case AND_AND :
+ return computeConstantOperationAND_AND(left, leftId, operator, right, rightId);
+ case DIVIDE :
+ return computeConstantOperationDIVIDE(left, leftId, operator, right, rightId);
+ case GREATER :
+ return computeConstantOperationGREATER(left, leftId, operator, right, rightId);
+ case GREATER_EQUAL :
+ return computeConstantOperationGREATER_EQUAL(
+ left,
+ leftId,
+ operator,
+ right,
+ rightId);
+ case LEFT_SHIFT :
+ return computeConstantOperationLEFT_SHIFT(
+ left,
+ leftId,
+ operator,
+ right,
+ rightId);
+ case LESS :
+ return computeConstantOperationLESS(left, leftId, operator, right, rightId);
+ case LESS_EQUAL :
+ return computeConstantOperationLESS_EQUAL(
+ left,
+ leftId,
+ operator,
+ right,
+ rightId);
+ case MINUS :
+ return computeConstantOperationMINUS(left, leftId, operator, right, rightId);
+ case MULTIPLY :
+ return computeConstantOperationMULTIPLY(left, leftId, operator, right, rightId);
+ case OR :
+ return computeConstantOperationOR(left, leftId, operator, right, rightId);
+ case OR_OR :
+ return computeConstantOperationOR_OR(left, leftId, operator, right, rightId);
+ case PLUS :
+ return computeConstantOperationPLUS(left, leftId, operator, right, rightId);
+ case REMAINDER :
+ return computeConstantOperationREMAINDER(
+ left,
+ leftId,
+ operator,
+ right,
+ rightId);
+ case RIGHT_SHIFT :
+ return computeConstantOperationRIGHT_SHIFT(
+ left,
+ leftId,
+ operator,
+ right,
+ rightId);
+ case UNSIGNED_RIGHT_SHIFT :
+ return computeConstantOperationUNSIGNED_RIGHT_SHIFT(
+ left,
+ leftId,
+ operator,
+ right,
+ rightId);
+ case XOR :
+ return computeConstantOperationXOR(left, leftId, operator, right, rightId);
+
+ default :
+ return NotAConstant;
+ }
+ } //should not occurs....(conservative code)
+
+ public static final Constant computeConstantOperationAND(
+ Constant left,
+ int leftId,
+ int operator,
+ Constant right,
+ int rightId) {
+ //this method assumes that the TC has been done .
+
+ switch (leftId) {
+ case T_boolean :
+ return Constant.fromValue(left.booleanValue() & right.booleanValue());
+ case T_char :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.charValue() & right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.charValue() & right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.charValue() & right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.charValue() & right.intValue());
+ case T_long :
+ return Constant.fromValue(left.charValue() & right.longValue());
+ }
+ break;
+ case T_byte :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.byteValue() & right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.byteValue() & right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.byteValue() & right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.byteValue() & right.intValue());
+ case T_long :
+ return Constant.fromValue(left.byteValue() & right.longValue());
+ }
+ break;
+ case T_short :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.shortValue() & right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.shortValue() & right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.shortValue() & right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.shortValue() & right.intValue());
+ case T_long :
+ return Constant.fromValue(left.shortValue() & right.longValue());
+ }
+ break;
+ case T_int :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.intValue() & right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.intValue() & right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.intValue() & right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.intValue() & right.intValue());
+ case T_long :
+ return Constant.fromValue(left.intValue() & right.longValue());
+ }
+ break;
+ case T_long :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.longValue() & right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.longValue() & right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.longValue() & right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.longValue() & right.intValue());
+ case T_long :
+ return Constant.fromValue(left.longValue() & right.longValue());
+ }
+
+ }
+
+ return NotAConstant;
+ } // should not get here
+
+ public static final Constant computeConstantOperationAND_AND(
+ Constant left,
+ int leftId,
+ int operator,
+ Constant right,
+ int rightId) {
+ //this method assumes that the TC has been done .
+
+ return Constant.fromValue(left.booleanValue() && right.booleanValue());
+ }
+
+ public static final Constant computeConstantOperationDIVIDE(
+ Constant left,
+ int leftId,
+ int operator,
+ Constant right,
+ int rightId) {
+ //this method assumes that the TC has been done .
+ // the /0 must be handled outside this method (error reporting)
+
+ switch (leftId) {
+ case T_char :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.charValue() / right.charValue());
+ case T_float :
+ return Constant.fromValue(left.charValue() / right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.charValue() / right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.charValue() / right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.charValue() / right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.charValue() / right.intValue());
+ case T_long :
+ return Constant.fromValue(left.charValue() / right.longValue());
+ }
+ break;
+ case T_float :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.floatValue() / right.charValue());
+ case T_float :
+ return Constant.fromValue(left.floatValue() / right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.floatValue() / right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.floatValue() / right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.floatValue() / right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.floatValue() / right.intValue());
+ case T_long :
+ return Constant.fromValue(left.floatValue() / right.longValue());
+ }
+ break;
+ case T_double :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.doubleValue() / right.charValue());
+ case T_float :
+ return Constant.fromValue(left.doubleValue() / right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.doubleValue() / right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.doubleValue() / right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.doubleValue() / right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.doubleValue() / right.intValue());
+ case T_long :
+ return Constant.fromValue(left.doubleValue() / right.longValue());
+ }
+ break;
+ case T_byte :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.byteValue() / right.charValue());
+ case T_float :
+ return Constant.fromValue(left.byteValue() / right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.byteValue() / right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.byteValue() / right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.byteValue() / right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.byteValue() / right.intValue());
+ case T_long :
+ return Constant.fromValue(left.byteValue() / right.longValue());
+ }
+ break;
+ case T_short :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.shortValue() / right.charValue());
+ case T_float :
+ return Constant.fromValue(left.shortValue() / right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.shortValue() / right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.shortValue() / right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.shortValue() / right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.shortValue() / right.intValue());
+ case T_long :
+ return Constant.fromValue(left.shortValue() / right.longValue());
+ }
+ break;
+ case T_int :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.intValue() / right.charValue());
+ case T_float :
+ return Constant.fromValue(left.intValue() / right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.intValue() / right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.intValue() / right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.intValue() / right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.intValue() / right.intValue());
+ case T_long :
+ return Constant.fromValue(left.intValue() / right.longValue());
+ }
+ break;
+ case T_long :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.longValue() / right.charValue());
+ case T_float :
+ return Constant.fromValue(left.longValue() / right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.longValue() / right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.longValue() / right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.longValue() / right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.longValue() / right.intValue());
+ case T_long :
+ return Constant.fromValue(left.longValue() / right.longValue());
+ }
+
+ }
+
+ return NotAConstant;
+ } //should not get here
+
+ public static final Constant computeConstantOperationEQUAL_EQUAL(
+ Constant left,
+ int leftId,
+ int operator,
+ Constant right,
+ int rightId) {
+ //this method assumes that the TC has been done .
+
+ switch (leftId) {
+ case T_boolean :
+ if (rightId == T_boolean) {
+ return Constant.fromValue(left.booleanValue() == right.booleanValue());
+ }
+ break;
+ case T_char :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.charValue() == right.charValue());
+ case T_float :
+ return Constant.fromValue(left.charValue() == right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.charValue() == right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.charValue() == right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.charValue() == right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.charValue() == right.intValue());
+ case T_long :
+ return Constant.fromValue(left.charValue() == right.longValue());
+ }
+ break;
+ case T_float :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.floatValue() == right.charValue());
+ case T_float :
+ return Constant.fromValue(left.floatValue() == right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.floatValue() == right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.floatValue() == right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.floatValue() == right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.floatValue() == right.intValue());
+ case T_long :
+ return Constant.fromValue(left.floatValue() == right.longValue());
+ }
+ break;
+ case T_double :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.doubleValue() == right.charValue());
+ case T_float :
+ return Constant.fromValue(left.doubleValue() == right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.doubleValue() == right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.doubleValue() == right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.doubleValue() == right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.doubleValue() == right.intValue());
+ case T_long :
+ return Constant.fromValue(left.doubleValue() == right.longValue());
+ }
+ break;
+ case T_byte :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.byteValue() == right.charValue());
+ case T_float :
+ return Constant.fromValue(left.byteValue() == right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.byteValue() == right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.byteValue() == right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.byteValue() == right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.byteValue() == right.intValue());
+ case T_long :
+ return Constant.fromValue(left.byteValue() == right.longValue());
+ }
+ break;
+ case T_short :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.shortValue() == right.charValue());
+ case T_float :
+ return Constant.fromValue(left.shortValue() == right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.shortValue() == right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.shortValue() == right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.shortValue() == right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.shortValue() == right.intValue());
+ case T_long :
+ return Constant.fromValue(left.shortValue() == right.longValue());
+ }
+ break;
+ case T_int :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.intValue() == right.charValue());
+ case T_float :
+ return Constant.fromValue(left.intValue() == right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.intValue() == right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.intValue() == right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.intValue() == right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.intValue() == right.intValue());
+ case T_long :
+ return Constant.fromValue(left.intValue() == right.longValue());
+ }
+ break;
+ case T_long :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.longValue() == right.charValue());
+ case T_float :
+ return Constant.fromValue(left.longValue() == right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.longValue() == right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.longValue() == right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.longValue() == right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.longValue() == right.intValue());
+ case T_long :
+ return Constant.fromValue(left.longValue() == right.longValue());
+ }
+ break;
+ case T_String :
+ if (rightId == T_String) {
+ //String are intermed in th compiler==>thus if two string constant
+ //get to be compared, it is an equal on the vale which is done
+ return Constant.fromValue(
+ ((StringConstant) left).compileTimeEqual((StringConstant) right));
+ }
+ break;
+ case T_null :
+ if (rightId == T_String) {
+ return Constant.fromValue(false);
+ } else {
+ if (rightId == T_null) {
+ return Constant.fromValue(true);
+ }
+ }
+ }
+
+ return Constant.fromValue(false);
+ }
+
+ public static final Constant computeConstantOperationGREATER(
+ Constant left,
+ int leftId,
+ int operator,
+ Constant right,
+ int rightId) {
+ //this method assumes that the TC has been done .
+
+ switch (leftId) {
+ case T_char :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.charValue() > right.charValue());
+ case T_float :
+ return Constant.fromValue(left.charValue() > right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.charValue() > right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.charValue() > right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.charValue() > right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.charValue() > right.intValue());
+ case T_long :
+ return Constant.fromValue(left.charValue() > right.longValue());
+ }
+ break;
+ case T_float :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.floatValue() > right.charValue());
+ case T_float :
+ return Constant.fromValue(left.floatValue() > right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.floatValue() > right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.floatValue() > right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.floatValue() > right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.floatValue() > right.intValue());
+ case T_long :
+ return Constant.fromValue(left.floatValue() > right.longValue());
+ }
+ break;
+ case T_double :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.doubleValue() > right.charValue());
+ case T_float :
+ return Constant.fromValue(left.doubleValue() > right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.doubleValue() > right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.doubleValue() > right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.doubleValue() > right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.doubleValue() > right.intValue());
+ case T_long :
+ return Constant.fromValue(left.doubleValue() > right.longValue());
+ }
+ break;
+ case T_byte :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.byteValue() > right.charValue());
+ case T_float :
+ return Constant.fromValue(left.byteValue() > right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.byteValue() > right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.byteValue() > right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.byteValue() > right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.byteValue() > right.intValue());
+ case T_long :
+ return Constant.fromValue(left.byteValue() > right.longValue());
+ }
+ break;
+ case T_short :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.shortValue() > right.charValue());
+ case T_float :
+ return Constant.fromValue(left.shortValue() > right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.shortValue() > right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.shortValue() > right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.shortValue() > right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.shortValue() > right.intValue());
+ case T_long :
+ return Constant.fromValue(left.shortValue() > right.longValue());
+ }
+ break;
+ case T_int :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.intValue() > right.charValue());
+ case T_float :
+ return Constant.fromValue(left.intValue() > right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.intValue() > right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.intValue() > right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.intValue() > right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.intValue() > right.intValue());
+ case T_long :
+ return Constant.fromValue(left.intValue() > right.longValue());
+ }
+ break;
+ case T_long :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.longValue() > right.charValue());
+ case T_float :
+ return Constant.fromValue(left.longValue() > right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.longValue() > right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.longValue() > right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.longValue() > right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.longValue() > right.intValue());
+ case T_long :
+ return Constant.fromValue(left.longValue() > right.longValue());
+ }
+
+ }
+
+ return NotAConstant;
+ } //should not get here
+
+ public static final Constant computeConstantOperationGREATER_EQUAL(
+ Constant left,
+ int leftId,
+ int operator,
+ Constant right,
+ int rightId) {
+ //this method assumes that the TC has been done .
+
+ switch (leftId) {
+ case T_char :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.charValue() >= right.charValue());
+ case T_float :
+ return Constant.fromValue(left.charValue() >= right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.charValue() >= right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.charValue() >= right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.charValue() >= right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.charValue() >= right.intValue());
+ case T_long :
+ return Constant.fromValue(left.charValue() >= right.longValue());
+ }
+ break;
+ case T_float :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.floatValue() >= right.charValue());
+ case T_float :
+ return Constant.fromValue(left.floatValue() >= right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.floatValue() >= right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.floatValue() >= right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.floatValue() >= right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.floatValue() >= right.intValue());
+ case T_long :
+ return Constant.fromValue(left.floatValue() >= right.longValue());
+ }
+ break;
+ case T_double :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.doubleValue() >= right.charValue());
+ case T_float :
+ return Constant.fromValue(left.doubleValue() >= right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.doubleValue() >= right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.doubleValue() >= right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.doubleValue() >= right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.doubleValue() >= right.intValue());
+ case T_long :
+ return Constant.fromValue(left.doubleValue() >= right.longValue());
+ }
+ break;
+ case T_byte :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.byteValue() >= right.charValue());
+ case T_float :
+ return Constant.fromValue(left.byteValue() >= right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.byteValue() >= right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.byteValue() >= right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.byteValue() >= right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.byteValue() >= right.intValue());
+ case T_long :
+ return Constant.fromValue(left.byteValue() >= right.longValue());
+ }
+ break;
+ case T_short :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.shortValue() >= right.charValue());
+ case T_float :
+ return Constant.fromValue(left.shortValue() >= right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.shortValue() >= right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.shortValue() >= right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.shortValue() >= right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.shortValue() >= right.intValue());
+ case T_long :
+ return Constant.fromValue(left.shortValue() >= right.longValue());
+ }
+ break;
+ case T_int :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.intValue() >= right.charValue());
+ case T_float :
+ return Constant.fromValue(left.intValue() >= right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.intValue() >= right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.intValue() >= right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.intValue() >= right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.intValue() >= right.intValue());
+ case T_long :
+ return Constant.fromValue(left.intValue() >= right.longValue());
+ }
+ break;
+ case T_long :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.longValue() >= right.charValue());
+ case T_float :
+ return Constant.fromValue(left.longValue() >= right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.longValue() >= right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.longValue() >= right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.longValue() >= right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.longValue() >= right.intValue());
+ case T_long :
+ return Constant.fromValue(left.longValue() >= right.longValue());
+ }
+
+ }
+
+ return NotAConstant;
+ } //should not get here
+
+ public static final Constant computeConstantOperationLEFT_SHIFT(
+ Constant left,
+ int leftId,
+ int operator,
+ Constant right,
+ int rightId) {
+ //this method assumes that the TC has been done .
+
+ switch (leftId) {
+ case T_char :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.charValue() << right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.charValue() << right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.charValue() << right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.charValue() << right.intValue());
+ case T_long :
+ return Constant.fromValue(left.charValue() << right.longValue());
+ }
+ break;
+ case T_byte :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.byteValue() << right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.byteValue() << right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.byteValue() << right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.byteValue() << right.intValue());
+ case T_long :
+ return Constant.fromValue(left.byteValue() << right.longValue());
+ }
+ break;
+ case T_short :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.shortValue() << right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.shortValue() << right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.shortValue() << right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.shortValue() << right.intValue());
+ case T_long :
+ return Constant.fromValue(left.shortValue() << right.longValue());
+ }
+ break;
+ case T_int :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.intValue() << right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.intValue() << right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.intValue() << right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.intValue() << right.intValue());
+ case T_long :
+ return Constant.fromValue(left.intValue() << right.longValue());
+ }
+ break;
+ case T_long :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.longValue() << right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.longValue() << right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.longValue() << right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.longValue() << right.intValue());
+ case T_long :
+ return Constant.fromValue(left.longValue() << right.longValue());
+ }
+
+ }
+
+ return NotAConstant;
+ } // should not get here
+
+ public static final Constant computeConstantOperationLESS(
+ Constant left,
+ int leftId,
+ int operator,
+ Constant right,
+ int rightId) {
+ //this method assumes that the TC has been done .
+
+ switch (leftId) {
+ case T_char :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.charValue() < right.charValue());
+ case T_float :
+ return Constant.fromValue(left.charValue() < right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.charValue() < right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.charValue() < right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.charValue() < right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.charValue() < right.intValue());
+ case T_long :
+ return Constant.fromValue(left.charValue() < right.longValue());
+ }
+ break;
+ case T_float :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.floatValue() < right.charValue());
+ case T_float :
+ return Constant.fromValue(left.floatValue() < right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.floatValue() < right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.floatValue() < right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.floatValue() < right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.floatValue() < right.intValue());
+ case T_long :
+ return Constant.fromValue(left.floatValue() < right.longValue());
+ }
+ break;
+ case T_double :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.doubleValue() < right.charValue());
+ case T_float :
+ return Constant.fromValue(left.doubleValue() < right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.doubleValue() < right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.doubleValue() < right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.doubleValue() < right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.doubleValue() < right.intValue());
+ case T_long :
+ return Constant.fromValue(left.doubleValue() < right.longValue());
+ }
+ break;
+ case T_byte :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.byteValue() < right.charValue());
+ case T_float :
+ return Constant.fromValue(left.byteValue() < right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.byteValue() < right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.byteValue() < right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.byteValue() < right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.byteValue() < right.intValue());
+ case T_long :
+ return Constant.fromValue(left.byteValue() < right.longValue());
+ }
+ break;
+ case T_short :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.shortValue() < right.charValue());
+ case T_float :
+ return Constant.fromValue(left.shortValue() < right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.shortValue() < right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.shortValue() < right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.shortValue() < right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.shortValue() < right.intValue());
+ case T_long :
+ return Constant.fromValue(left.shortValue() < right.longValue());
+ }
+ break;
+ case T_int :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.intValue() < right.charValue());
+ case T_float :
+ return Constant.fromValue(left.intValue() < right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.intValue() < right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.intValue() < right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.intValue() < right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.intValue() < right.intValue());
+ case T_long :
+ return Constant.fromValue(left.intValue() < right.longValue());
+ }
+ break;
+ case T_long :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.longValue() < right.charValue());
+ case T_float :
+ return Constant.fromValue(left.longValue() < right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.longValue() < right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.longValue() < right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.longValue() < right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.longValue() < right.intValue());
+ case T_long :
+ return Constant.fromValue(left.longValue() < right.longValue());
+ }
+
+ }
+
+ return NotAConstant;
+ } //should not get here
+
+ public static final Constant computeConstantOperationLESS_EQUAL(
+ Constant left,
+ int leftId,
+ int operator,
+ Constant right,
+ int rightId) {
+ //this method assumes that the TC has been done .
+
+ switch (leftId) {
+ case T_char :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.charValue() <= right.charValue());
+ case T_float :
+ return Constant.fromValue(left.charValue() <= right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.charValue() <= right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.charValue() <= right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.charValue() <= right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.charValue() <= right.intValue());
+ case T_long :
+ return Constant.fromValue(left.charValue() <= right.longValue());
+ }
+ break;
+ case T_float :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.floatValue() <= right.charValue());
+ case T_float :
+ return Constant.fromValue(left.floatValue() <= right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.floatValue() <= right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.floatValue() <= right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.floatValue() <= right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.floatValue() <= right.intValue());
+ case T_long :
+ return Constant.fromValue(left.floatValue() <= right.longValue());
+ }
+ break;
+ case T_double :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.doubleValue() <= right.charValue());
+ case T_float :
+ return Constant.fromValue(left.doubleValue() <= right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.doubleValue() <= right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.doubleValue() <= right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.doubleValue() <= right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.doubleValue() <= right.intValue());
+ case T_long :
+ return Constant.fromValue(left.doubleValue() <= right.longValue());
+ }
+ break;
+ case T_byte :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.byteValue() <= right.charValue());
+ case T_float :
+ return Constant.fromValue(left.byteValue() <= right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.byteValue() <= right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.byteValue() <= right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.byteValue() <= right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.byteValue() <= right.intValue());
+ case T_long :
+ return Constant.fromValue(left.byteValue() <= right.longValue());
+ }
+ break;
+ case T_short :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.shortValue() <= right.charValue());
+ case T_float :
+ return Constant.fromValue(left.shortValue() <= right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.shortValue() <= right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.shortValue() <= right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.shortValue() <= right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.shortValue() <= right.intValue());
+ case T_long :
+ return Constant.fromValue(left.shortValue() <= right.longValue());
+ }
+ break;
+ case T_int :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.intValue() <= right.charValue());
+ case T_float :
+ return Constant.fromValue(left.intValue() <= right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.intValue() <= right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.intValue() <= right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.intValue() <= right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.intValue() <= right.intValue());
+ case T_long :
+ return Constant.fromValue(left.intValue() <= right.longValue());
+ }
+ break;
+ case T_long :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.longValue() <= right.charValue());
+ case T_float :
+ return Constant.fromValue(left.longValue() <= right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.longValue() <= right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.longValue() <= right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.longValue() <= right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.longValue() <= right.intValue());
+ case T_long :
+ return Constant.fromValue(left.longValue() <= right.longValue());
+ }
+
+ }
+
+ return NotAConstant;
+ } //should not get here
+
+ public static final Constant computeConstantOperationMINUS(
+ Constant left,
+ int leftId,
+ int operator,
+ Constant right,
+ int rightId) {
+ //this method assumes that the TC has been done .
+
+ switch (leftId) {
+ case T_char :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.charValue() - right.charValue());
+ case T_float :
+ return Constant.fromValue(left.charValue() - right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.charValue() - right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.charValue() - right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.charValue() - right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.charValue() - right.intValue());
+ case T_long :
+ return Constant.fromValue(left.charValue() - right.longValue());
+ }
+ break;
+ case T_float :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.floatValue() - right.charValue());
+ case T_float :
+ return Constant.fromValue(left.floatValue() - right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.floatValue() - right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.floatValue() - right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.floatValue() - right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.floatValue() - right.intValue());
+ case T_long :
+ return Constant.fromValue(left.floatValue() - right.longValue());
+ }
+ break;
+ case T_double :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.doubleValue() - right.charValue());
+ case T_float :
+ return Constant.fromValue(left.doubleValue() - right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.doubleValue() - right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.doubleValue() - right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.doubleValue() - right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.doubleValue() - right.intValue());
+ case T_long :
+ return Constant.fromValue(left.doubleValue() - right.longValue());
+ }
+ break;
+ case T_byte :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.byteValue() - right.charValue());
+ case T_float :
+ return Constant.fromValue(left.byteValue() - right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.byteValue() - right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.byteValue() - right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.byteValue() - right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.byteValue() - right.intValue());
+ case T_long :
+ return Constant.fromValue(left.byteValue() - right.longValue());
+ }
+ break;
+ case T_short :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.shortValue() - right.charValue());
+ case T_float :
+ return Constant.fromValue(left.shortValue() - right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.shortValue() - right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.shortValue() - right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.shortValue() - right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.shortValue() - right.intValue());
+ case T_long :
+ return Constant.fromValue(left.shortValue() - right.longValue());
+ }
+ break;
+ case T_int :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.intValue() - right.charValue());
+ case T_float :
+ return Constant.fromValue(left.intValue() - right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.intValue() - right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.intValue() - right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.intValue() - right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.intValue() - right.intValue());
+ case T_long :
+ return Constant.fromValue(left.intValue() - right.longValue());
+ }
+ break;
+ case T_long :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.longValue() - right.charValue());
+ case T_float :
+ return Constant.fromValue(left.longValue() - right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.longValue() - right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.longValue() - right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.longValue() - right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.longValue() - right.intValue());
+ case T_long :
+ return Constant.fromValue(left.longValue() - right.longValue());
+ }
+
+ }
+
+ return NotAConstant;
+ } //should not get here
+
+ public static final Constant computeConstantOperationMULTIPLY(
+ Constant left,
+ int leftId,
+ int operator,
+ Constant right,
+ int rightId) {
+ //this method assumes that the TC has been done .
+
+ switch (leftId) {
+ case T_char :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.charValue() * right.charValue());
+ case T_float :
+ return Constant.fromValue(left.charValue() * right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.charValue() * right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.charValue() * right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.charValue() * right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.charValue() * right.intValue());
+ case T_long :
+ return Constant.fromValue(left.charValue() * right.longValue());
+ }
+ break;
+ case T_float :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.floatValue() * right.charValue());
+ case T_float :
+ return Constant.fromValue(left.floatValue() * right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.floatValue() * right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.floatValue() * right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.floatValue() * right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.floatValue() * right.intValue());
+ case T_long :
+ return Constant.fromValue(left.floatValue() * right.longValue());
+ }
+ break;
+ case T_double :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.doubleValue() * right.charValue());
+ case T_float :
+ return Constant.fromValue(left.doubleValue() * right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.doubleValue() * right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.doubleValue() * right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.doubleValue() * right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.doubleValue() * right.intValue());
+ case T_long :
+ return Constant.fromValue(left.doubleValue() * right.longValue());
+ }
+ break;
+ case T_byte :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.byteValue() * right.charValue());
+ case T_float :
+ return Constant.fromValue(left.byteValue() * right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.byteValue() * right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.byteValue() * right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.byteValue() * right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.byteValue() * right.intValue());
+ case T_long :
+ return Constant.fromValue(left.byteValue() * right.longValue());
+ }
+ break;
+ case T_short :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.shortValue() * right.charValue());
+ case T_float :
+ return Constant.fromValue(left.shortValue() * right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.shortValue() * right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.shortValue() * right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.shortValue() * right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.shortValue() * right.intValue());
+ case T_long :
+ return Constant.fromValue(left.shortValue() * right.longValue());
+ }
+ break;
+ case T_int :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.intValue() * right.charValue());
+ case T_float :
+ return Constant.fromValue(left.intValue() * right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.intValue() * right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.intValue() * right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.intValue() * right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.intValue() * right.intValue());
+ case T_long :
+ return Constant.fromValue(left.intValue() * right.longValue());
+ }
+ break;
+ case T_long :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.longValue() * right.charValue());
+ case T_float :
+ return Constant.fromValue(left.longValue() * right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.longValue() * right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.longValue() * right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.longValue() * right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.longValue() * right.intValue());
+ case T_long :
+ return Constant.fromValue(left.longValue() * right.longValue());
+ }
+
+ }
+
+ return NotAConstant;
+ } //should not get here
+
+ public static final Constant computeConstantOperationOR(
+ Constant left,
+ int leftId,
+ int operator,
+ Constant right,
+ int rightId) {
+ //this method assumes that the TC has been done .
+
+ switch (leftId) {
+ case T_boolean :
+ return Constant.fromValue(left.booleanValue() | right.booleanValue());
+ case T_char :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.charValue() | right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.charValue() | right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.charValue() | right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.charValue() | right.intValue());
+ case T_long :
+ return Constant.fromValue(left.charValue() | right.longValue());
+ }
+ break;
+ case T_byte :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.byteValue() | right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.byteValue() | right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.byteValue() | right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.byteValue() | right.intValue());
+ case T_long :
+ return Constant.fromValue(left.byteValue() | right.longValue());
+ }
+ break;
+ case T_short :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.shortValue() | right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.shortValue() | right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.shortValue() | right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.shortValue() | right.intValue());
+ case T_long :
+ return Constant.fromValue(left.shortValue() | right.longValue());
+ }
+ break;
+ case T_int :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.intValue() | right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.intValue() | right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.intValue() | right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.intValue() | right.intValue());
+ case T_long :
+ return Constant.fromValue(left.intValue() | right.longValue());
+ }
+ break;
+ case T_long :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.longValue() | right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.longValue() | right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.longValue() | right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.longValue() | right.intValue());
+ case T_long :
+ return Constant.fromValue(left.longValue() | right.longValue());
+ }
+
+ }
+
+ return NotAConstant;
+ } // should not get here
+
+ public static final Constant computeConstantOperationOR_OR(
+ Constant left,
+ int leftId,
+ int operator,
+ Constant right,
+ int rightId) {
+ //this method assumes that the TC has been done .
+
+ return Constant.fromValue(left.booleanValue() || right.booleanValue());
+ }
+
+ public static final Constant computeConstantOperationPLUS(
+ Constant left,
+ int leftId,
+ int operator,
+ Constant right,
+ int rightId) {
+ //this method assumes that the TC has been done .
+
+ switch (leftId) {
+ case T_Object :
+ if (rightId == T_String) {
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ }
+ case T_boolean :
+ if (rightId == T_String) {
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ }
+ break;
+ case T_char :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.charValue() + right.charValue());
+ case T_float :
+ return Constant.fromValue(left.charValue() + right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.charValue() + right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.charValue() + right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.charValue() + right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.charValue() + right.intValue());
+ case T_long :
+ return Constant.fromValue(left.charValue() + right.longValue());
+ case T_String :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ }
+ break;
+ case T_float :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.floatValue() + right.charValue());
+ case T_float :
+ return Constant.fromValue(left.floatValue() + right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.floatValue() + right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.floatValue() + right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.floatValue() + right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.floatValue() + right.intValue());
+ case T_long :
+ return Constant.fromValue(left.floatValue() + right.longValue());
+ case T_String :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ }
+ break;
+ case T_double :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.doubleValue() + right.charValue());
+ case T_float :
+ return Constant.fromValue(left.doubleValue() + right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.doubleValue() + right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.doubleValue() + right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.doubleValue() + right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.doubleValue() + right.intValue());
+ case T_long :
+ return Constant.fromValue(left.doubleValue() + right.longValue());
+ case T_String :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ }
+ break;
+ case T_byte :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.byteValue() + right.charValue());
+ case T_float :
+ return Constant.fromValue(left.byteValue() + right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.byteValue() + right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.byteValue() + right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.byteValue() + right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.byteValue() + right.intValue());
+ case T_long :
+ return Constant.fromValue(left.byteValue() + right.longValue());
+ case T_String :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ }
+
+ break;
+ case T_short :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.shortValue() + right.charValue());
+ case T_float :
+ return Constant.fromValue(left.shortValue() + right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.shortValue() + right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.shortValue() + right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.shortValue() + right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.shortValue() + right.intValue());
+ case T_long :
+ return Constant.fromValue(left.shortValue() + right.longValue());
+ case T_String :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ }
+ break;
+ case T_int :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.intValue() + right.charValue());
+ case T_float :
+ return Constant.fromValue(left.intValue() + right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.intValue() + right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.intValue() + right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.intValue() + right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.intValue() + right.intValue());
+ case T_long :
+ return Constant.fromValue(left.intValue() + right.longValue());
+ case T_String :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ }
+ break;
+ case T_long :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.longValue() + right.charValue());
+ case T_float :
+ return Constant.fromValue(left.longValue() + right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.longValue() + right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.longValue() + right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.longValue() + right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.longValue() + right.intValue());
+ case T_long :
+ return Constant.fromValue(left.longValue() + right.longValue());
+ case T_String :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ }
+ break;
+ case T_String :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ case T_float :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ case T_double :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ case T_byte :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ case T_short :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ case T_int :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ case T_long :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ case T_String :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ case T_null :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ case T_boolean :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ }
+ break;
+ case T_null :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ case T_float :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ case T_double :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ case T_byte :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ case T_short :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ case T_int :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ case T_long :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ case T_String :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ case T_null :
+ return Constant.fromValue(left.stringValue() + right.stringValue());
+ }
+
+ }
+
+ return NotAConstant;
+ } //should not get here
+
+ public static final Constant computeConstantOperationREMAINDER(
+ Constant left,
+ int leftId,
+ int operator,
+ Constant right,
+ int rightId) {
+ //this method assumes that the TC has been done .
+
+ switch (leftId) {
+ case T_char :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.charValue() % right.charValue());
+ case T_float :
+ return Constant.fromValue(left.charValue() % right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.charValue() % right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.charValue() % right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.charValue() % right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.charValue() % right.intValue());
+ case T_long :
+ return Constant.fromValue(left.charValue() % right.longValue());
+ }
+ break;
+ case T_float :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.floatValue() % right.charValue());
+ case T_float :
+ return Constant.fromValue(left.floatValue() % right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.floatValue() % right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.floatValue() % right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.floatValue() % right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.floatValue() % right.intValue());
+ case T_long :
+ return Constant.fromValue(left.floatValue() % right.longValue());
+ }
+ break;
+ case T_double :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.doubleValue() % right.charValue());
+ case T_float :
+ return Constant.fromValue(left.doubleValue() % right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.doubleValue() % right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.doubleValue() % right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.doubleValue() % right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.doubleValue() % right.intValue());
+ case T_long :
+ return Constant.fromValue(left.doubleValue() % right.longValue());
+ }
+ break;
+ case T_byte :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.byteValue() % right.charValue());
+ case T_float :
+ return Constant.fromValue(left.byteValue() % right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.byteValue() % right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.byteValue() % right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.byteValue() % right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.byteValue() % right.intValue());
+ case T_long :
+ return Constant.fromValue(left.byteValue() % right.longValue());
+ }
+ break;
+ case T_short :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.shortValue() % right.charValue());
+ case T_float :
+ return Constant.fromValue(left.shortValue() % right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.shortValue() % right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.shortValue() % right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.shortValue() % right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.shortValue() % right.intValue());
+ case T_long :
+ return Constant.fromValue(left.shortValue() % right.longValue());
+ }
+ break;
+ case T_int :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.intValue() % right.charValue());
+ case T_float :
+ return Constant.fromValue(left.intValue() % right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.intValue() % right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.intValue() % right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.intValue() % right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.intValue() % right.intValue());
+ case T_long :
+ return Constant.fromValue(left.intValue() % right.longValue());
+ }
+ break;
+ case T_long :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.longValue() % right.charValue());
+ case T_float :
+ return Constant.fromValue(left.longValue() % right.floatValue());
+ case T_double :
+ return Constant.fromValue(left.longValue() % right.doubleValue());
+ case T_byte :
+ return Constant.fromValue(left.longValue() % right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.longValue() % right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.longValue() % right.intValue());
+ case T_long :
+ return Constant.fromValue(left.longValue() % right.longValue());
+ }
+
+ }
+
+ return NotAConstant;
+ } //should not get here
+
+ public static final Constant computeConstantOperationRIGHT_SHIFT(
+ Constant left,
+ int leftId,
+ int operator,
+ Constant right,
+ int rightId) {
+ //this method assumes that the TC has been done .
+
+ switch (leftId) {
+ case T_char :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.charValue() >> right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.charValue() >> right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.charValue() >> right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.charValue() >> right.intValue());
+ case T_long :
+ return Constant.fromValue(left.charValue() >> right.longValue());
+ }
+ break;
+ case T_byte :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.byteValue() >> right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.byteValue() >> right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.byteValue() >> right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.byteValue() >> right.intValue());
+ case T_long :
+ return Constant.fromValue(left.byteValue() >> right.longValue());
+ }
+ break;
+ case T_short :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.shortValue() >> right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.shortValue() >> right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.shortValue() >> right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.shortValue() >> right.intValue());
+ case T_long :
+ return Constant.fromValue(left.shortValue() >> right.longValue());
+ }
+ break;
+ case T_int :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.intValue() >> right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.intValue() >> right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.intValue() >> right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.intValue() >> right.intValue());
+ case T_long :
+ return Constant.fromValue(left.intValue() >> right.longValue());
+ }
+ break;
+ case T_long :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.longValue() >> right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.longValue() >> right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.longValue() >> right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.longValue() >> right.intValue());
+ case T_long :
+ return Constant.fromValue(left.longValue() >> right.longValue());
+ }
+
+ }
+
+ return NotAConstant;
+ } // should not get here
+
+ public static final Constant computeConstantOperationUNSIGNED_RIGHT_SHIFT(
+ Constant left,
+ int leftId,
+ int operator,
+ Constant right,
+ int rightId) {
+ //this method assumes that the TC has been done .
+
+ switch (leftId) {
+ case T_char :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.charValue() >>> right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.charValue() >>> right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.charValue() >>> right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.charValue() >>> right.intValue());
+ case T_long :
+ return Constant.fromValue(left.charValue() >>> right.longValue());
+ }
+ break;
+ case T_byte :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.byteValue() >>> right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.byteValue() >>> right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.byteValue() >>> right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.byteValue() >>> right.intValue());
+ case T_long :
+ return Constant.fromValue(left.byteValue() >>> right.longValue());
+ }
+ break;
+ case T_short :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.shortValue() >>> right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.shortValue() >>> right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.shortValue() >>> right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.shortValue() >>> right.intValue());
+ case T_long :
+ return Constant.fromValue(left.shortValue() >>> right.longValue());
+ }
+ break;
+ case T_int :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.intValue() >>> right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.intValue() >>> right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.intValue() >>> right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.intValue() >>> right.intValue());
+ case T_long :
+ return Constant.fromValue(left.intValue() >>> right.longValue());
+ }
+ break;
+ case T_long :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.longValue() >>> right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.longValue() >>> right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.longValue() >>> right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.longValue() >>> right.intValue());
+ case T_long :
+ return Constant.fromValue(left.longValue() >>> right.longValue());
+ }
+
+ }
+
+ return NotAConstant;
+ } // should not get here
+
+ public static final Constant computeConstantOperationXOR(
+ Constant left,
+ int leftId,
+ int operator,
+ Constant right,
+ int rightId) {
+ //this method assumes that the TC has been done .
+
+ switch (leftId) {
+ case T_boolean :
+ return Constant.fromValue(left.booleanValue() ^ right.booleanValue());
+ case T_char :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.charValue() ^ right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.charValue() ^ right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.charValue() ^ right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.charValue() ^ right.intValue());
+ case T_long :
+ return Constant.fromValue(left.charValue() ^ right.longValue());
+ }
+ break;
+ case T_byte :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.byteValue() ^ right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.byteValue() ^ right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.byteValue() ^ right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.byteValue() ^ right.intValue());
+ case T_long :
+ return Constant.fromValue(left.byteValue() ^ right.longValue());
+ }
+ break;
+ case T_short :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.shortValue() ^ right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.shortValue() ^ right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.shortValue() ^ right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.shortValue() ^ right.intValue());
+ case T_long :
+ return Constant.fromValue(left.shortValue() ^ right.longValue());
+ }
+ break;
+ case T_int :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.intValue() ^ right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.intValue() ^ right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.intValue() ^ right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.intValue() ^ right.intValue());
+ case T_long :
+ return Constant.fromValue(left.intValue() ^ right.longValue());
+ }
+ break;
+ case T_long :
+ switch (rightId) {
+ case T_char :
+ return Constant.fromValue(left.longValue() ^ right.charValue());
+ case T_byte :
+ return Constant.fromValue(left.longValue() ^ right.byteValue());
+ case T_short :
+ return Constant.fromValue(left.longValue() ^ right.shortValue());
+ case T_int :
+ return Constant.fromValue(left.longValue() ^ right.intValue());
+ case T_long :
+ return Constant.fromValue(left.longValue() ^ right.longValue());
+ }
+
+ }
+
+ return NotAConstant;
+ } // should not get here
+
+ public double doubleValue() {
+ throw new ShouldNotImplement(
+ typeName() + " constant cannot be casted into double");
+ }
+
+ public float floatValue() {
+ throw new ShouldNotImplement(
+ typeName() + " constant cannot be casted into float");
+ }
+
+ public static Constant fromValue(byte value) {
+ return new ByteConstant(value);
+ }
+
+ public static Constant fromValue(char value) {
+ return new CharConstant(value);
+ }
+
+ public static Constant fromValue(double value) {
+ return new DoubleConstant(value);
+ }
+
+ public static Constant fromValue(float value) {
+ return new FloatConstant(value);
+ }
+
+ public static Constant fromValue(int value) {
+ return new IntConstant(value);
+ }
+
+ public static Constant fromValue(long value) {
+ return new LongConstant(value);
+ }
+
+ public static Constant fromValue(String value) {
+ if (value == null)
+ return NullConstant.Default;
+ return new StringConstant(value);
+ }
+
+ public static Constant fromValue(short value) {
+ return new ShortConstant(value);
+ }
+
+ public static Constant fromValue(boolean value) {
+ return new BooleanConstant(value);
+ }
+
+ public int intValue() {
+ throw new ShouldNotImplement(
+ typeName() + " constant cannot be casted into int");
+ }
+
+ public long longValue() {
+ throw new ShouldNotImplement(
+ typeName() + " constant cannot be casted into long");
+ }
+
+ public short shortValue() {
+ throw new ShouldNotImplement(
+ typeName() + " constant cannot be converted to short");
+ }
+
+ /** Deprecated
+ */
+ public String stringValue() {
+ throw new ShouldNotImplement(
+ typeName() + " constant cannot be converted to String");
+ }
+
+ public String toString() {
+
+ if (this == NotAConstant)
+ return "(Constant) NotAConstant";
+ return super.toString();
+ }
+
+ public abstract int typeID();
+ public String typeName() {
+ switch (typeID()) {
+ case T_int :
+ return "int";
+ case T_byte :
+ return "byte";
+ case T_short :
+ return "short";
+ case T_char :
+ return "char";
+ case T_float :
+ return "float";
+ case T_double :
+ return "double";
+ case T_boolean :
+ return "boolean";
+ case T_String :
+ return "java.lang.String";
+ case T_null :
+ return "null";
+ default :
+ return "unknown";
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/DoubleConstant.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/DoubleConstant.java
new file mode 100644
index 0000000000..c81c68d9dd
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/DoubleConstant.java
@@ -0,0 +1,58 @@
+package org.eclipse.jdt.internal.compiler.impl;
+
+public class DoubleConstant extends Constant {
+ double value;
+ public DoubleConstant(double value) {
+ this.value = value;
+ }
+
+ public byte byteValue() {
+ return (byte) value;
+ }
+
+ public char charValue() {
+ return (char) value;
+ }
+
+ public double doubleValue() {
+ return (double) value;
+ }
+
+ public float floatValue() {
+ return (float) value;
+ }
+
+ public int intValue() {
+ return (int) value;
+ }
+
+ public long longValue() {
+ return (long) value;
+ }
+
+ public short shortValue() {
+ return (short) value;
+ }
+
+ public String stringValue() {
+ //spec 15.17.11
+
+ String s = new Double(value).toString();
+ if (s == null)
+ return "null";
+ else
+ return s;
+ }
+
+ public String toString() {
+
+ if (this == NotAConstant)
+ return "(Constant) NotAConstant";
+ return "(double)" + value;
+ }
+
+ public int typeID() {
+ return T_double;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/FloatConstant.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/FloatConstant.java
new file mode 100644
index 0000000000..df143bc8f6
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/FloatConstant.java
@@ -0,0 +1,56 @@
+package org.eclipse.jdt.internal.compiler.impl;
+
+public class FloatConstant extends Constant {
+ float value;
+ public FloatConstant(float value) {
+ this.value = value;
+ }
+
+ public byte byteValue() {
+ return (byte) value;
+ }
+
+ public char charValue() {
+ return (char) value;
+ }
+
+ public double doubleValue() {
+ return (double) value;
+ }
+
+ public float floatValue() {
+ return (float) value;
+ }
+
+ public int intValue() {
+ return (int) value;
+ }
+
+ public long longValue() {
+ return (long) value;
+ }
+
+ public short shortValue() {
+ return (short) value;
+ }
+
+ public String stringValue() {
+ //spec 15.17.11
+
+ String s = new Float(value).toString();
+ if (s == null)
+ return "null";
+ else
+ return s;
+ }
+
+ public String toString() {
+
+ return "(float)" + value;
+ }
+
+ public int typeID() {
+ return T_float;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ITypeRequestor.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ITypeRequestor.java
new file mode 100644
index 0000000000..e8fc9d9231
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ITypeRequestor.java
@@ -0,0 +1,27 @@
+package org.eclipse.jdt.internal.compiler.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
+
+import org.eclipse.jdt.internal.compiler.env.*;
+
+public interface ITypeRequestor {
+ /**
+ * Accept the resolved binary form for the requested type.
+ */
+
+ void accept(IBinaryType binaryType, PackageBinding packageBinding);
+ /**
+ * Accept the requested type's compilation unit.
+ */
+
+ void accept(ICompilationUnit unit);
+ /**
+ * Accept the unresolved source form for the requested type.
+ */
+
+ void accept(ISourceType sourceType, PackageBinding packageBinding);
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IntConstant.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IntConstant.java
new file mode 100644
index 0000000000..8fca6c6214
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IntConstant.java
@@ -0,0 +1,56 @@
+package org.eclipse.jdt.internal.compiler.impl;
+
+public class IntConstant extends Constant {
+ int value;
+ public IntConstant(int value) {
+ this.value = value;
+ }
+
+ public byte byteValue() {
+ return (byte) value;
+ }
+
+ public char charValue() {
+ return (char) value;
+ }
+
+ public double doubleValue() {
+ return (double) value;
+ }
+
+ public float floatValue() {
+ return (float) value;
+ }
+
+ public int intValue() {
+ return (int) value;
+ }
+
+ public long longValue() {
+ return (long) value;
+ }
+
+ public short shortValue() {
+ return (short) value;
+ }
+
+ public String stringValue() {
+ //spec 15.17.11
+
+ String s = new Integer(value).toString();
+ if (s == null)
+ return "null";
+ else
+ return s;
+ }
+
+ public String toString() {
+
+ return "(int)" + value;
+ }
+
+ public int typeID() {
+ return T_int;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/LongConstant.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/LongConstant.java
new file mode 100644
index 0000000000..61026dff33
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/LongConstant.java
@@ -0,0 +1,56 @@
+package org.eclipse.jdt.internal.compiler.impl;
+
+public class LongConstant extends Constant {
+ long value;
+ public LongConstant(long value) {
+ this.value = value;
+ }
+
+ public byte byteValue() {
+ return (byte) value;
+ }
+
+ public char charValue() {
+ return (char) value;
+ }
+
+ public double doubleValue() {
+ return (double) value;
+ }
+
+ public float floatValue() {
+ return (float) value;
+ }
+
+ public int intValue() {
+ return (int) value;
+ }
+
+ public long longValue() {
+ return (long) value;
+ }
+
+ public short shortValue() {
+ return (short) value;
+ }
+
+ public String stringValue() {
+ //spec 15.17.11
+
+ String s = new Long(value).toString();
+ if (s == null)
+ return "null";
+ else
+ return s;
+ }
+
+ public String toString() {
+
+ return "(long)" + value;
+ }
+
+ public int typeID() {
+ return T_long;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/NullConstant.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/NullConstant.java
new file mode 100644
index 0000000000..85c2124b70
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/NullConstant.java
@@ -0,0 +1,25 @@
+package org.eclipse.jdt.internal.compiler.impl;
+
+public class NullConstant extends Constant {
+ public static final NullConstant Default = new NullConstant();
+
+ final static String NullString =
+ new StringBuffer(4).append((String) null).toString();
+ private NullConstant() {
+ }
+
+ public String stringValue() {
+
+ return NullString;
+ }
+
+ public String toString() {
+
+ return "(null)" + null;
+ }
+
+ public int typeID() {
+ return T_null;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ReferenceContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ReferenceContext.java
new file mode 100644
index 0000000000..ccf4cb4f68
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ReferenceContext.java
@@ -0,0 +1,19 @@
+package org.eclipse.jdt.internal.compiler.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/*
+ * Implementors are valid compilation contexts from which we can
+ * escape in case of error:
+ * i.e. method | type | compilation unit
+ */
+
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+
+public interface ReferenceContext {
+ public void abort(int abortLevel);
+ public CompilationResult compilationResult();
+ void tagAsHavingErrors();
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ShortConstant.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ShortConstant.java
new file mode 100644
index 0000000000..41e3aabc2f
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ShortConstant.java
@@ -0,0 +1,56 @@
+package org.eclipse.jdt.internal.compiler.impl;
+
+public class ShortConstant extends Constant {
+ short value;
+ public ShortConstant(short value) {
+ this.value = value;
+ }
+
+ public byte byteValue() {
+ return (byte) value;
+ }
+
+ public char charValue() {
+ return (char) value;
+ }
+
+ public double doubleValue() {
+ return (double) value;
+ }
+
+ public float floatValue() {
+ return (float) value;
+ }
+
+ public int intValue() {
+ return (int) value;
+ }
+
+ public long longValue() {
+ return (long) value;
+ }
+
+ public short shortValue() {
+ return (short) value;
+ }
+
+ public String stringValue() {
+ //spec 15.17.11
+
+ String s = new Integer(value).toString();
+ if (s == null)
+ return "null";
+ else
+ return s;
+ }
+
+ public String toString() {
+
+ return "(short)" + value;
+ }
+
+ public int typeID() {
+ return T_short;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/StringConstant.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/StringConstant.java
new file mode 100644
index 0000000000..6bad1d70e5
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/StringConstant.java
@@ -0,0 +1,42 @@
+package org.eclipse.jdt.internal.compiler.impl;
+
+public class StringConstant extends Constant {
+ public String value;
+
+ public StringConstant(String value) {
+ this.value = value;
+ }
+
+ public boolean compileTimeEqual(StringConstant right) {
+ //String are intermed in th compiler==>thus if two string constant
+ //get to be compared, it is an equal on the vale which is done
+
+ return true;
+ }
+
+ public String stringValue() {
+ //spec 15.17.11
+
+ //the next line do not go into the toString() send....!
+ return value;
+
+ /*
+ String s = value.toString() ;
+ if (s == null)
+ return "null";
+ else
+ return s;
+ */
+
+ }
+
+ public String toString() {
+
+ return "(String)\"" + value + "\"";
+ }
+
+ public int typeID() {
+ return T_String;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java
new file mode 100644
index 0000000000..2c5ffe2df7
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java
@@ -0,0 +1,152 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public final class ArrayBinding extends TypeBinding {
+ // creation and initialization of the length field
+ // the declaringClass of this field is intentionally set to null so it can be distinguished.
+ public static final FieldBinding LengthField =
+ new FieldBinding(
+ LENGTH,
+ IntBinding,
+ AccPublic | AccFinal,
+ null,
+ Constant.NotAConstant);
+
+ public TypeBinding leafComponentType;
+ public int dimensions;
+
+ char[] constantPoolName;
+ public ArrayBinding(TypeBinding type, int dimensions) {
+ this.tagBits |= IsArrayType;
+ this.leafComponentType = type;
+ this.dimensions = dimensions;
+ }
+
+ /* Answer the receiver's constant pool name.
+ *
+ * NOTE: This method should only be used during/after code gen.
+ */
+
+ public char[] constantPoolName() /* [Ljava/lang/Object; */ {
+ if (constantPoolName != null)
+ return constantPoolName;
+
+ char[] brackets = new char[dimensions];
+ for (int i = dimensions - 1; i >= 0; i--)
+ brackets[i] = '[';
+ return constantPoolName =
+ CharOperation.concat(brackets, leafComponentType.signature());
+ }
+
+ String debugName() {
+ StringBuffer brackets = new StringBuffer(dimensions * 2);
+ for (int i = dimensions; --i >= 0;)
+ brackets.append("[]");
+ return leafComponentType.debugName() + brackets.toString();
+ }
+
+ /* Answer an array whose dimension size is one less than the receiver.
+ *
+ * When the receiver's dimension size is one then answer the leaf component type.
+ */
+
+ public TypeBinding elementsType(Scope scope) {
+ if (dimensions == 1)
+ return leafComponentType;
+ else
+ return scope.createArray(leafComponentType, dimensions - 1);
+ }
+
+ public PackageBinding getPackage() {
+ return leafComponentType.getPackage();
+ }
+
+ /* Answer true if the receiver type can be assigned to the argument type (right)
+ */
+
+ boolean isCompatibleWith(TypeBinding right) {
+ if (this == right)
+ return true;
+
+ char[][] rightName;
+ if (right.isArrayType()) {
+ ArrayBinding rightArray = (ArrayBinding) right;
+ if (rightArray.leafComponentType.isBaseType())
+ return false; // relying on the fact that all equal arrays are identical
+ if (dimensions == rightArray.dimensions)
+ return leafComponentType.isCompatibleWith(rightArray.leafComponentType);
+ if (dimensions < rightArray.dimensions)
+ return false;
+ // cannot assign 'String[]' into 'Object[][]' but can assign 'byte[][]' into 'Object[]'
+ rightName = ((ReferenceBinding) rightArray.leafComponentType).compoundName;
+ } else {
+ if (right.isBaseType())
+ return false;
+ rightName = ((ReferenceBinding) right).compoundName;
+ }
+ //Check dimensions - Java does not support explicitly sized dimensions for types.
+ //However, if it did, the type checking support would go here.
+
+ if (CharOperation.equals(rightName, JAVA_LANG_OBJECT))
+ return true;
+ if (CharOperation.equals(rightName, JAVA_LANG_CLONEABLE))
+ return true;
+ if (CharOperation.equals(rightName, JAVA_IO_SERIALIZABLE))
+ return true;
+ return false;
+ }
+
+ /* API
+ * Answer the problem id associated with the receiver.
+ * NoError if the receiver is a valid binding.
+ */
+
+ public int problemId() {
+ return leafComponentType.problemId();
+ }
+
+ /**
+ * Answer the source name for the type.
+ * In the case of member types, as the qualified name from its top level type.
+ * For example, for a member type N defined inside M & A: "A.M.N".
+ */
+
+ public char[] qualifiedSourceName() {
+ char[] brackets = new char[dimensions * 2];
+ for (int i = dimensions * 2 - 1; i >= 0; i -= 2) {
+ brackets[i] = ']';
+ brackets[i - 1] = '[';
+ }
+ return CharOperation.concat(leafComponentType.qualifiedSourceName(), brackets);
+ }
+
+ public char[] readableName() /* java.lang.Object[] */ {
+ char[] brackets = new char[dimensions * 2];
+ for (int i = dimensions * 2 - 1; i >= 0; i -= 2) {
+ brackets[i] = ']';
+ brackets[i - 1] = '[';
+ }
+ return CharOperation.concat(leafComponentType.readableName(), brackets);
+ }
+
+ public char[] sourceName() {
+ char[] brackets = new char[dimensions * 2];
+ for (int i = dimensions * 2 - 1; i >= 0; i -= 2) {
+ brackets[i] = ']';
+ brackets[i - 1] = '[';
+ }
+ return CharOperation.concat(leafComponentType.sourceName(), brackets);
+ }
+
+ public String toString() {
+ return leafComponentType != null ? debugName() : "NULL TYPE ARRAY";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypeBinding.java
new file mode 100644
index 0000000000..5117709a51
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypeBinding.java
@@ -0,0 +1,175 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+
+public final class BaseTypeBinding extends TypeBinding {
+ public char[] simpleName;
+ private char[] constantPoolName;
+ BaseTypeBinding(int id, char[] name, char[] constantPoolName) {
+ this.tagBits |= IsBaseType;
+ this.id = id;
+ this.simpleName = name;
+ this.constantPoolName = constantPoolName;
+ }
+
+ /* Answer the receiver's constant pool name.
+ */
+
+ public char[] constantPoolName() {
+ return constantPoolName;
+ }
+
+ public PackageBinding getPackage() {
+ return null;
+ }
+
+ /* Answer true if the receiver type can be assigned to the argument type (right)
+ */
+
+ final boolean isCompatibleWith(TypeBinding right) {
+ if (this == right)
+ return true;
+ if (!right.isBaseType())
+ return this == NullBinding;
+
+ switch (right.id) {
+ case T_boolean :
+ case T_byte :
+ case T_char :
+ return false;
+ case T_double :
+ switch (id) {
+ case T_byte :
+ case T_char :
+ case T_short :
+ case T_int :
+ case T_long :
+ case T_float :
+ return true;
+ default :
+ return false;
+ }
+ case T_float :
+ switch (id) {
+ case T_byte :
+ case T_char :
+ case T_short :
+ case T_int :
+ case T_long :
+ return true;
+ default :
+ return false;
+ }
+ case T_long :
+ switch (id) {
+ case T_byte :
+ case T_char :
+ case T_short :
+ case T_int :
+ return true;
+ default :
+ return false;
+ }
+ case T_int :
+ switch (id) {
+ case T_byte :
+ case T_char :
+ case T_short :
+ return true;
+ default :
+ return false;
+ }
+ case T_short :
+ return (id == T_byte);
+ }
+ return false;
+ }
+
+ public static final boolean isNarrowing(int left, int right) {
+ //can "left" store a "right" using some narrowing conversion
+ //(is left smaller than right)
+
+ switch (left) {
+ case T_boolean :
+ return right == T_boolean;
+ case T_char :
+ case T_byte :
+ if (right == T_byte)
+ return true;
+ case T_short :
+ if (right == T_short)
+ return true;
+ if (right == T_char)
+ return true;
+ case T_int :
+ if (right == T_int)
+ return true;
+ case T_long :
+ if (right == T_long)
+ return true;
+ case T_float :
+ if (right == T_float)
+ return true;
+ case T_double :
+ if (right == T_double)
+ return true;
+ default :
+ return false;
+ }
+ }
+
+ public static final boolean isWidening(int left, int right) {
+ //can "left" store a "right" using some widening conversion
+ //(is left "bigger" than right)
+
+ switch (left) {
+ case T_boolean :
+ return right == T_boolean;
+ case T_char :
+ return right == T_char;
+ case T_double :
+ if (right == T_double)
+ return true;
+ case T_float :
+ if (right == T_float)
+ return true;
+ case T_long :
+ if (right == T_long)
+ return true;
+ case T_int :
+ if (right == T_int)
+ return true;
+ if (right == T_char)
+ return true;
+ case T_short :
+ if (right == T_short)
+ return true;
+ case T_byte :
+ if (right == T_byte)
+ return true;
+ default :
+ return false;
+ }
+ }
+
+ public char[] qualifiedSourceName() {
+ return simpleName;
+ }
+
+ public char[] readableName() {
+ return simpleName;
+ }
+
+ public char[] sourceName() {
+ return simpleName;
+ }
+
+ public String toString() {
+ return new String(constantPoolName) + " (id=" + id + ")";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypes.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypes.java
new file mode 100644
index 0000000000..8f5d754f78
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypes.java
@@ -0,0 +1,31 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+public interface BaseTypes {
+ final BaseTypeBinding IntBinding =
+ new BaseTypeBinding(TypeIds.T_int, "int".toCharArray(), new char[] { 'I' });
+ final BaseTypeBinding ByteBinding =
+ new BaseTypeBinding(TypeIds.T_byte, "byte".toCharArray(), new char[] { 'B' });
+ final BaseTypeBinding ShortBinding =
+ new BaseTypeBinding(TypeIds.T_short, "short".toCharArray(), new char[] { 'S' });
+ final BaseTypeBinding CharBinding =
+ new BaseTypeBinding(TypeIds.T_char, "char".toCharArray(), new char[] { 'C' });
+ final BaseTypeBinding LongBinding =
+ new BaseTypeBinding(TypeIds.T_long, "long".toCharArray(), new char[] { 'J' });
+ final BaseTypeBinding FloatBinding =
+ new BaseTypeBinding(TypeIds.T_float, "float".toCharArray(), new char[] { 'F' });
+ final BaseTypeBinding DoubleBinding =
+ new BaseTypeBinding(
+ TypeIds.T_double,
+ "double".toCharArray(),
+ new char[] { 'D' });
+ final BaseTypeBinding BooleanBinding =
+ new BaseTypeBinding(
+ TypeIds.T_boolean,
+ "boolean".toCharArray(),
+ new char[] { 'Z' });
+ final BaseTypeBinding NullBinding =
+ new BaseTypeBinding(TypeIds.T_null, "null".toCharArray(), new char[] { 'N' });
+ //N stands for null even if it is never internally used
+ final BaseTypeBinding VoidBinding =
+ new BaseTypeBinding(TypeIds.T_void, "void".toCharArray(), new char[] { 'V' });
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
new file mode 100644
index 0000000000..531c59e87b
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
@@ -0,0 +1,512 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+/*
+Not all fields defined by this type are initialized when it is created.
+Some are initialized only when needed.
+
+Accessors have been provided for some public fields so all TypeBindings have the same API...
+but access public fields directly whenever possible.
+Non-public fields have accessors which should be used everywhere you expect the field to be initialized.
+
+null is NOT a valid value for a non-public field... it just means the field is not initialized.
+*/
+
+public final class BinaryTypeBinding extends ReferenceBinding {
+ // all of these fields are ONLY guaranteed to be initialized if accessed using their public accessor method
+ private ReferenceBinding superclass;
+ private ReferenceBinding enclosingType;
+ private ReferenceBinding[] superInterfaces;
+ private FieldBinding[] fields;
+ private MethodBinding[] methods;
+ private ReferenceBinding[] memberTypes;
+
+ // For the link with the principle structure
+ private LookupEnvironment environment;
+ public BinaryTypeBinding(
+ PackageBinding packageBinding,
+ IBinaryType binaryType,
+ LookupEnvironment environment) {
+ this.compoundName = CharOperation.splitOn('/', binaryType.getName());
+ computeId();
+
+ this.tagBits |= IsBinaryBinding;
+ this.environment = environment;
+ this.fPackage = packageBinding;
+ this.fileName = binaryType.getFileName();
+
+ // source name must be one name without "$".
+ char[] possibleSourceName = this.compoundName[this.compoundName.length - 1];
+ int start = CharOperation.lastIndexOf('$', possibleSourceName) + 1;
+ if (start == 0) {
+ this.sourceName = possibleSourceName;
+ } else {
+ this.sourceName = new char[possibleSourceName.length - start];
+ System.arraycopy(
+ possibleSourceName,
+ start,
+ this.sourceName,
+ 0,
+ this.sourceName.length);
+ }
+
+ this.modifiers = binaryType.getModifiers();
+ if (binaryType.isInterface())
+ this.modifiers |= AccInterface;
+ }
+
+ void cachePartsFrom(IBinaryType binaryType, boolean needFieldsAndMethods) {
+ char[] superclassName = binaryType.getSuperclassName();
+ if (superclassName != null)
+ // attempt to find the superclass if it exists in the cache (otherwise - resolve it when requested)
+ this.superclass =
+ environment.getTypeFromConstantPoolName(superclassName, 0, -1);
+
+ char[] enclosingTypeName = binaryType.getEnclosingTypeName();
+ if (enclosingTypeName != null) {
+ // attempt to find the enclosing type if it exists in the cache (otherwise - resolve it when requested)
+ this.enclosingType =
+ environment.getTypeFromConstantPoolName(enclosingTypeName, 0, -1);
+ this.tagBits |= MemberTypeMask;
+ // must be a member type not a top-level or local type
+ if (this.enclosingType().isStrictfp())
+ this.modifiers |= AccStrictfp;
+ if (this.enclosingType().isDeprecated())
+ this.modifiers |= AccDeprecatedImplicitly;
+ }
+
+ this.memberTypes = NoMemberTypes;
+ IBinaryNestedType[] memberTypeStructures = binaryType.getMemberTypes();
+ if (memberTypeStructures != null) {
+ int size = memberTypeStructures.length;
+ if (size > 0) {
+ this.memberTypes = new ReferenceBinding[size];
+ for (int i = 0; i < size; i++)
+ // attempt to find each member type if it exists in the cache (otherwise - resolve it when requested)
+ this.memberTypes[i] =
+ environment.getTypeFromConstantPoolName(
+ memberTypeStructures[i].getName(),
+ 0,
+ -1);
+ }
+ }
+
+ this.superInterfaces = NoSuperInterfaces;
+ char[][] interfaceNames = binaryType.getInterfaceNames();
+ if (interfaceNames != null) {
+ int size = interfaceNames.length;
+ if (size > 0) {
+ this.superInterfaces = new ReferenceBinding[size];
+ for (int i = 0; i < size; i++)
+ // attempt to find each superinterface if it exists in the cache (otherwise - resolve it when requested)
+ this.superInterfaces[i] =
+ environment.getTypeFromConstantPoolName(interfaceNames[i], 0, -1);
+ }
+ }
+ if (needFieldsAndMethods) {
+ createFields(binaryType.getFields());
+ createMethods(binaryType.getMethods());
+ }
+ }
+
+ private void createFields(IBinaryField[] iFields) {
+ this.fields = NoFields;
+ if (iFields != null) {
+ int size = iFields.length;
+ if (size > 0) {
+ this.fields = new FieldBinding[size];
+ for (int i = 0; i < size; i++) {
+ IBinaryField field = iFields[i];
+ this.fields[i] =
+ new FieldBinding(
+ field.getName(),
+ environment.getTypeFromSignature(field.getTypeName(), 0, -1),
+ field.getModifiers(),
+ this,
+ field.getConstant());
+ }
+ }
+ }
+ }
+
+ private MethodBinding createMethod(IBinaryMethod method) {
+ int modifiers = method.getModifiers() | AccUnresolved;
+
+ ReferenceBinding[] exceptions = NoExceptions;
+ char[][] exceptionTypes = method.getExceptionTypeNames();
+ if (exceptionTypes != null) {
+ int size = exceptionTypes.length;
+ if (size > 0) {
+ exceptions = new ReferenceBinding[size];
+ for (int i = 0; i < size; i++)
+ exceptions[i] =
+ environment.getTypeFromConstantPoolName(exceptionTypes[i], 0, -1);
+ }
+ }
+
+ TypeBinding[] parameters = NoParameters;
+ char[] signature = method.getMethodDescriptor();
+ // of the form (I[Ljava/jang/String;)V
+ int numOfParams = 0;
+ char nextChar;
+ int index = 0; // first character is always '(' so skip it
+ while ((nextChar = signature[++index]) != ')') {
+ if (nextChar != '[') {
+ numOfParams++;
+ if (nextChar == 'L')
+ while ((nextChar = signature[++index]) != ';');
+ }
+ }
+
+ // Ignore synthetic argument for member types.
+ int startIndex =
+ (method.isConstructor() && isMemberType() && !isStatic()) ? 1 : 0;
+ int size = numOfParams - startIndex;
+ if (size > 0) {
+ parameters = new TypeBinding[size];
+ index = 1;
+ int end = 0; // first character is always '(' so skip it
+ for (int i = 0; i < numOfParams; i++) {
+ while ((nextChar = signature[++end]) == '[');
+ if (nextChar == 'L')
+ while ((nextChar = signature[++end]) != ';');
+
+ if (i >= startIndex) // skip the synthetic arg if necessary
+ parameters[i - startIndex] =
+ environment.getTypeFromSignature(signature, index, end);
+ index = end + 1;
+ }
+ }
+
+ MethodBinding binding = null;
+ if (method.isConstructor())
+ binding = new MethodBinding(modifiers, parameters, exceptions, this);
+ else
+ binding =
+ new MethodBinding(
+ modifiers,
+ method.getSelector(),
+ environment.getTypeFromSignature(signature, index + 1, -1),
+ // index is currently pointing at the ')'
+ parameters, exceptions, this);
+ return binding;
+ }
+
+ private void createMethods(IBinaryMethod[] iMethods) {
+ int total = 0;
+ int clinitIndex = -1;
+ if (iMethods != null) {
+ total = iMethods.length;
+ for (int i = total; --i >= 0;) {
+ char[] methodName = iMethods[i].getSelector();
+ if (methodName[0] == '<'
+ && methodName.length == 8) { // Can only match <clinit>
+ total--;
+ clinitIndex = i;
+ break;
+ }
+ }
+ }
+ if (total == 0) {
+ this.methods = NoMethods;
+ return;
+ }
+
+ this.methods = new MethodBinding[total];
+ int next = 0;
+ for (int i = 0, length = iMethods.length; i < length; i++)
+ if (i != clinitIndex)
+ this.methods[next++] = createMethod(iMethods[i]);
+ modifiers |= AccUnresolved; // until methods() is sent
+ }
+
+ /* Answer the receiver's enclosing type... null if the receiver is a top level type.
+ *
+ * NOTE: enclosingType of a binary type is resolved when needed
+ */
+
+ public ReferenceBinding enclosingType() {
+ if (enclosingType == null)
+ return null;
+ if (enclosingType instanceof UnresolvedReferenceBinding)
+ enclosingType =
+ ((UnresolvedReferenceBinding) enclosingType).resolve(environment);
+ return enclosingType;
+ }
+
+ // NOTE: the type of each field of a binary type is resolved when needed
+
+ public FieldBinding[] fields() {
+ for (int i = fields.length; --i >= 0;)
+ resolveTypeFor(fields[i]);
+ return fields;
+ }
+
+ // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
+
+ public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) {
+ int argCount = argumentTypes.length;
+ nextMethod : for (int m = methods.length; --m >= 0;) {
+ MethodBinding method = methods[m];
+ if (method.selector == ConstructorDeclaration.ConstantPoolName
+ && method.parameters.length == argCount) {
+ resolveTypesFor(method);
+ TypeBinding[] toMatch = method.parameters;
+ for (int p = 0; p < argCount; p++)
+ if (toMatch[p] != argumentTypes[p])
+ continue nextMethod;
+ return method;
+ }
+ }
+ return null;
+ }
+
+ // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
+ // searches up the hierarchy as long as no potential (but not exact) match was found.
+
+ public MethodBinding getExactMethod(
+ char[] selector,
+ TypeBinding[] argumentTypes) {
+ int argCount = argumentTypes.length;
+ int selectorLength = selector.length;
+ boolean foundNothing = true;
+ nextMethod : for (int m = methods.length; --m >= 0;) {
+ MethodBinding method = methods[m];
+ if (method.selector.length == selectorLength
+ && CharOperation.prefixEquals(method.selector, selector)) {
+ foundNothing = false;
+ // inner type lookups must know that a method with this name exists
+ if (method.parameters.length == argCount) {
+ resolveTypesFor(method);
+ TypeBinding[] toMatch = method.parameters;
+ for (int p = 0; p < argCount; p++)
+ if (toMatch[p] != argumentTypes[p])
+ continue nextMethod;
+ return method;
+ }
+ }
+ }
+
+ if (foundNothing) {
+ if (isInterface()) {
+ if (superInterfaces.length == 1)
+ return superInterfaces[0].getExactMethod(selector, argumentTypes);
+ } else
+ if (superclass != null) {
+ return superclass.getExactMethod(selector, argumentTypes);
+ }
+ }
+ return null;
+ }
+
+ // NOTE: the type of a field of a binary type is resolved when needed
+
+ public FieldBinding getField(char[] fieldName) {
+ int fieldLength = fieldName.length;
+ for (int f = fields.length; --f >= 0;) {
+ char[] name = fields[f].name;
+ if (name.length == fieldLength && CharOperation.prefixEquals(name, fieldName))
+ return resolveTypeFor(fields[f]);
+ }
+ return null;
+ }
+
+ // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
+
+ public MethodBinding[] getMethods(char[] selector) {
+ int count = 0;
+ int lastIndex = -1;
+ int selectorLength = selector.length;
+ for (int m = 0, length = methods.length; m < length; m++) {
+ MethodBinding method = methods[m];
+ if (method.selector.length == selectorLength
+ && CharOperation.prefixEquals(method.selector, selector)) {
+ resolveTypesFor(method);
+ count++;
+ lastIndex = m;
+ }
+ }
+ if (count == 1)
+ return new MethodBinding[] { methods[lastIndex] };
+ if (count > 0) {
+ MethodBinding[] result = new MethodBinding[count];
+ count = 0;
+ for (int m = 0; m <= lastIndex; m++) {
+ MethodBinding method = methods[m];
+ if (method.selector.length == selectorLength
+ && CharOperation.prefixEquals(method.selector, selector))
+ result[count++] = method;
+ }
+ return result;
+ }
+ return NoMethods;
+ }
+
+ // NOTE: member types of binary types are resolved when needed
+
+ public ReferenceBinding[] memberTypes() {
+ for (int i = memberTypes.length; --i >= 0;)
+ if (memberTypes[i] instanceof UnresolvedReferenceBinding)
+ memberTypes[i] =
+ ((UnresolvedReferenceBinding) memberTypes[i]).resolve(environment);
+ return memberTypes;
+ }
+
+ // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
+
+ public MethodBinding[] methods() {
+ if ((modifiers & AccUnresolved) == 0)
+ return methods;
+
+ for (int i = methods.length; --i >= 0;)
+ resolveTypesFor(methods[i]);
+ modifiers ^= AccUnresolved;
+ return methods;
+ }
+
+ private TypeBinding resolveType(TypeBinding type) {
+ if (type instanceof UnresolvedReferenceBinding)
+ return ((UnresolvedReferenceBinding) type).resolve(environment);
+ if (type instanceof ArrayBinding) {
+ ArrayBinding array = (ArrayBinding) type;
+ if (array.leafComponentType instanceof UnresolvedReferenceBinding)
+ array.leafComponentType =
+ ((UnresolvedReferenceBinding) array.leafComponentType).resolve(environment);
+ }
+ return type;
+ }
+
+ private FieldBinding resolveTypeFor(FieldBinding field) {
+ field.type = resolveType(field.type);
+ return field;
+ }
+
+ private MethodBinding resolveTypesFor(MethodBinding method) {
+ if ((method.modifiers & AccUnresolved) == 0)
+ return method;
+
+ if (!method.isConstructor())
+ method.returnType = resolveType(method.returnType);
+ for (int i = method.parameters.length; --i >= 0;)
+ method.parameters[i] = resolveType(method.parameters[i]);
+ for (int i = method.thrownExceptions.length; --i >= 0;)
+ if (method.thrownExceptions[i] instanceof UnresolvedReferenceBinding)
+ method.thrownExceptions[i] =
+ ((UnresolvedReferenceBinding) method.thrownExceptions[i]).resolve(environment);
+ method.modifiers ^= AccUnresolved;
+ return method;
+ }
+
+ /* Answer the receiver's superclass... null if the receiver is Object or an interface.
+ *
+ * NOTE: superclass of a binary type is resolved when needed
+ */
+
+ public ReferenceBinding superclass() {
+ if (superclass == null)
+ return null;
+ if (superclass instanceof UnresolvedReferenceBinding)
+ superclass = ((UnresolvedReferenceBinding) superclass).resolve(environment);
+ return superclass;
+ }
+
+ // NOTE: superInterfaces of binary types are resolved when needed
+
+ public ReferenceBinding[] superInterfaces() {
+ for (int i = superInterfaces.length; --i >= 0;)
+ if (superInterfaces[i] instanceof UnresolvedReferenceBinding)
+ superInterfaces[i] =
+ ((UnresolvedReferenceBinding) superInterfaces[i]).resolve(environment);
+ return superInterfaces;
+ }
+
+ public String toString() {
+ String s = "";
+
+ if (isDeprecated())
+ s += "deprecated ";
+ if (isPublic())
+ s += "public ";
+ if (isProtected())
+ s += "protected ";
+ if (isPrivate())
+ s += "private ";
+ if (isAbstract() && isClass())
+ s += "abstract ";
+ if (isStatic() && isNestedType())
+ s += "static ";
+ if (isFinal())
+ s += "final ";
+
+ s += isInterface() ? "interface " : "class ";
+ s += (compoundName != null)
+ ? CharOperation.toString(compoundName)
+ : "UNNAMED TYPE";
+
+ s += "\n\textends ";
+ s += (superclass != null) ? superclass.debugName() : "NULL TYPE";
+
+ if (superInterfaces != null) {
+ if (superInterfaces != NoSuperInterfaces) {
+ s += "\n\timplements : ";
+ for (int i = 0, length = superInterfaces.length; i < length; i++) {
+ if (i > 0)
+ s += ", ";
+ s += (superInterfaces[i] != null)
+ ? superInterfaces[i].debugName()
+ : "NULL TYPE";
+ }
+ }
+ } else {
+ s += "NULL SUPERINTERFACES";
+ }
+
+ if (enclosingType != null) {
+ s += "\n\tenclosing type : ";
+ s += enclosingType.debugName();
+ }
+
+ if (fields != null) {
+ if (fields != NoFields) {
+ s += "\n/* fields */";
+ for (int i = 0, length = fields.length; i < length; i++)
+ s += (fields[i] != null) ? "\n" + fields[i].toString() : "\nNULL FIELD";
+ }
+ } else {
+ s += "NULL FIELDS";
+ }
+
+ if (methods != null) {
+ if (methods != NoMethods) {
+ s += "\n/* methods */";
+ for (int i = 0, length = methods.length; i < length; i++)
+ s += (methods[i] != null) ? "\n" + methods[i].toString() : "\nNULL METHOD";
+ }
+ } else {
+ s += "NULL METHODS";
+ }
+
+ if (memberTypes != null) {
+ if (memberTypes != NoMemberTypes) {
+ s += "\n/* members */";
+ for (int i = 0, length = memberTypes.length; i < length; i++)
+ s += (memberTypes[i] != null)
+ ? "\n" + memberTypes[i].toString()
+ : "\nNULL TYPE";
+ }
+ } else {
+ s += "NULL MEMBER TYPES";
+ }
+
+ s += "\n\n\n";
+ return s;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java
new file mode 100644
index 0000000000..b4f66cbb65
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java
@@ -0,0 +1,34 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+public abstract class Binding
+ implements BindingIds, CompilerModifiers, ProblemReasons {
+ /* API
+ * Answer the receiver's binding type from Binding.BindingID.
+ *
+ * Note: Do NOT expect this to be used very often... only in switch statements with
+ * more than 2 possible choices.
+ */
+
+ public abstract int bindingType();
+ /* API
+ * Answer true if the receiver is not a problem binding
+ */
+
+ public final boolean isValidBinding() {
+ return problemId() == NoError;
+ }
+
+ /* API
+ * Answer the problem id associated with the receiver.
+ * NoError if the receiver is a valid binding.
+ */
+
+ public int problemId() {
+ return NoError;
+ }
+
+ /* Answer a printable representation of the receiver.
+ */
+
+ public abstract char[] readableName();
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BindingIds.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BindingIds.java
new file mode 100644
index 0000000000..ba67d08bd9
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BindingIds.java
@@ -0,0 +1,11 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+public interface BindingIds {
+ final int FIELD = 1;
+ final int LOCAL = 2;
+ final int VARIABLE = FIELD | LOCAL;
+ final int TYPE = 4;
+ final int METHOD = 8;
+ final int PACKAGE = 16;
+ final int IMPORT = 32;
+}
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
new file mode 100644
index 0000000000..c5516f1057
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java
@@ -0,0 +1,1451 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class BlockScope extends Scope {
+ // Local variable management
+ public LocalVariableBinding[] locals;
+ public int localIndex; // position for next variable
+ public int analysisIndex; // for setting flow-analysis id
+ public int startIndex;
+ // start position in this scope - for ordering scopes vs. variables
+
+ public final static VariableBinding[] EmulationPathToImplicitThis = {
+ };
+
+ public Scope[] subscopes = new Scope[1]; // need access from code assist
+ public int scopeIndex = 0; // need access from code assist
+ protected BlockScope(int kind, Scope parent) {
+ super(kind, parent);
+ }
+
+ public BlockScope(BlockScope parent) {
+ this(BLOCK_SCOPE, parent);
+ locals = new LocalVariableBinding[5];
+ parent.addSubscope(this);
+ this.startIndex = parent.localIndex;
+ }
+
+ public BlockScope(BlockScope parent, int variableCount) {
+ this(BLOCK_SCOPE, parent);
+ locals = new LocalVariableBinding[variableCount];
+ parent.addSubscope(this);
+ this.startIndex = parent.localIndex;
+ }
+
+ /* Create the class scope & binding for the anonymous type.
+ */
+
+ public final void addAnonymousType(
+ TypeDeclaration anonymousType,
+ ReferenceBinding superBinding) {
+ ClassScope anonymousClassScope = new ClassScope(this, anonymousType);
+ anonymousClassScope.buildAnonymousTypeBinding(
+ enclosingSourceType(),
+ superBinding);
+
+ /* provide some "default" name?
+ char[][] enclosingName = enclosing.compoundName;
+ System.arraycopy(
+ enclosingName, 0,
+ binding.compoundName = new char[enclosingName.length+1][], 0,
+ enclosingName.length);
+ binding.compoundName[enclosingName.length] = ANONYMOUS_EMPTY_NAME;
+ */
+ }
+
+ /* Create the class scope & binding for the local type.
+ */
+
+ public final void addLocalType(TypeDeclaration localType) {
+ // check that the localType does not conflict with an enclosing type
+ ReferenceBinding type = enclosingSourceType();
+ do {
+ if (CharOperation.equals(type.sourceName, localType.name)) {
+ problemReporter().hidingEnclosingType(localType);
+ return;
+ }
+ type = type.enclosingType();
+ } while (type != null);
+
+ // check that the localType does not conflict with another sibling local type
+ Scope scope = this;
+ do {
+ if (((BlockScope) scope).findLocalType(localType.name) != null) {
+ problemReporter().duplicateNestedType(localType);
+ return;
+ }
+ } while ((scope = scope.parent) instanceof BlockScope);
+
+ ClassScope localTypeScope = new ClassScope(this, localType);
+ localTypeScope.buildLocalTypeBinding(enclosingSourceType());
+ addSubscope(localTypeScope);
+ }
+
+ /* Insert a local variable into a given scope, updating its position
+ * and checking there are not too many locals or arguments allocated.
+ */
+
+ public final void addLocalVariable(LocalVariableBinding binding) {
+ checkAndSetModifiersForVariable(binding);
+
+ // insert local in scope
+ if (localIndex == locals.length)
+ System.arraycopy(
+ locals,
+ 0,
+ (locals = new LocalVariableBinding[localIndex * 2]),
+ 0,
+ localIndex);
+ locals[localIndex++] = binding;
+
+ // update local variable binding
+ binding.declaringScope = this;
+ binding.id = this.outerMostMethodScope().analysisIndex++;
+ // share the outermost method scope analysisIndex
+
+ /*
+ // update localIndex
+ TypeBinding resolvedType;
+ if (((resolvedType = binding.type) == LongBinding) || (resolvedType == DoubleBinding)) {
+ localIndex += 2;
+ } else {
+ localIndex++;
+ };
+ */
+ /*
+ if (binding.isArgument) {
+ // check argument count < 255 words
+ if (localIndex > 255) {
+ problemReporter().noMoreAvailableSpaceForArgument(binding);
+ }
+ } else {
+ // ensure local index < 65535 words
+ if (localIndex > 65535) {
+ problemReporter().noMoreAvailableSpaceForLocalVariable(binding);
+ }
+ }
+ */
+ }
+
+ private void addSubscope(Scope childScope) {
+ if (scopeIndex == subscopes.length)
+ System.arraycopy(
+ subscopes,
+ 0,
+ (subscopes = new Scope[scopeIndex * 2]),
+ 0,
+ scopeIndex);
+ subscopes[scopeIndex++] = childScope;
+ }
+
+ /* Answer true if the receiver is suitable for assigning final blank fields.
+ *
+ * i.e. is inside an initializer, a constructor or a clinit
+ */
+
+ public final boolean allowBlankFinalFieldAssignment(FieldBinding binding) {
+ if (enclosingSourceType() != binding.declaringClass)
+ return false;
+
+ MethodScope methodScope = methodScope();
+ if (methodScope.isStatic != binding.isStatic())
+ return false;
+ return methodScope.isInsideInitializer() // inside initializer
+ || ((AbstractMethodDeclaration) methodScope.referenceContext)
+ .isInitializationMethod();
+ // inside constructor or clinit
+ }
+
+ String basicToString(int tab) {
+ String newLine = "\n";
+ for (int i = tab; --i >= 0;)
+ newLine += "\t";
+
+ String s = newLine + "--- Block Scope ---";
+ newLine += "\t";
+ s += newLine + "locals:";
+ for (int i = 0; i < localIndex; i++)
+ s += newLine + "\t" + locals[i].toString();
+ s += newLine + "startIndex = " + startIndex;
+ return s;
+ }
+
+ private void checkAndSetModifiersForVariable(LocalVariableBinding varBinding) {
+ int modifiers = varBinding.modifiers;
+ if ((modifiers & AccAlternateModifierProblem) != 0)
+ problemReporter().duplicateModifierForVariable(varBinding.declaration);
+
+ int realModifiers = modifiers & AccJustFlag;
+ int unexpectedModifiers = ~AccFinal;
+ if ((realModifiers & unexpectedModifiers) != 0)
+ problemReporter().illegalModifierForVariable(varBinding.declaration);
+
+ varBinding.modifiers = modifiers;
+ }
+
+ /* Compute variable positions in scopes given an initial position offset
+ * ignoring unused local variables.
+ */
+
+ public final void computeLocalVariablePositions(
+ int offset,
+ CodeStream codeStream) {
+ // local variable init
+ int ilocal = 0, maxLocals = 0, localsLength = locals.length;
+ while ((maxLocals < localsLength) && (locals[maxLocals] != null))
+ maxLocals++;
+ boolean hasMoreVariables = maxLocals > 0;
+
+ // scope init
+ int iscope = 0, maxScopes = 0, subscopesLength = subscopes.length;
+ while ((maxScopes < subscopesLength) && (subscopes[maxScopes] != null))
+ maxScopes++;
+ boolean hasMoreScopes = maxScopes > 0;
+
+ // iterate scopes and variables in parallel
+ while (hasMoreVariables || hasMoreScopes) {
+ if (hasMoreScopes
+ && (!hasMoreVariables || (subscopes[iscope].startIndex() <= ilocal))) {
+ // consider subscope first
+ if (subscopes[iscope] instanceof BlockScope)
+ ((BlockScope) subscopes[iscope]).computeLocalVariablePositions(
+ offset,
+ codeStream);
+ hasMoreScopes = ++iscope < maxScopes;
+ } else {
+ // consider variable first
+ LocalVariableBinding local = locals[ilocal];
+
+ // check if variable is actually used, and may force it to be preserved
+ boolean generatesLocal =
+ (local.used && (local.constant == Constant.NotAConstant)) || local.isArgument;
+ if (!local.used
+ && (local.declaration != null)) { // unused (and non secret) local
+ if (local.isArgument) // method argument
+ this.problemReporter().unusedArgument(local.declaration);
+ else
+ if (!(local.declaration instanceof Argument)) // catch variable
+ this.problemReporter().unusedLocalVariable(local.declaration);
+ }
+ if (!generatesLocal) {
+ if (local.declaration != null
+ && referenceCompilationUnit().problemReporter.options.preserveAllLocalVariables) {
+ generatesLocal = true; // force it to be preserved in the generated code
+ local.used = true;
+ }
+ }
+ if (generatesLocal) {
+ if (local.declaration != null)
+ codeStream.record(local);
+ // record user local variables for attribute generation
+ local.resolvedPosition = offset;
+ // check for too many arguments/local variables
+ if (local.isArgument) {
+ if (offset > 0xFF) { // no more than 255 words of arguments
+ this.problemReporter().noMoreAvailableSpaceForArgument(local.declaration);
+ }
+ } else {
+ if (offset > 0xFFFF) { // no more than 65535 words of locals
+ this.problemReporter().noMoreAvailableSpaceForLocal(local.declaration);
+ }
+ }
+ if ((local.type == LongBinding) || (local.type == DoubleBinding))
+ offset += 2;
+ else
+ offset++;
+ } else {
+ local.resolvedPosition = -1; // not generated
+ }
+ hasMoreVariables = ++ilocal < maxLocals;
+ }
+ }
+ }
+
+ /* Answer true if the variable name already exists within the receiver's scope.
+ */
+
+ public final LocalVariableBinding duplicateName(char[] name) {
+ for (int i = 0; i < localIndex; i++)
+ if (CharOperation.equals(name, locals[i].name))
+ return locals[i];
+
+ if (this instanceof MethodScope)
+ return null;
+ else
+ return ((BlockScope) parent).duplicateName(name);
+ }
+
+ /**
+ * Record the suitable binding denoting a synthetic field or constructor argument,
+ * mapping to the actual outer local variable in the scope context.
+ * Note that this may not need any effect, in case the outer local variable does not
+ * need to be emulated and can directly be used as is (using its back pointer to its
+ * declaring scope).
+ */
+ public void emulateOuterAccess(LocalVariableBinding outerLocalVariable) {
+ MethodScope currentMethodScope;
+ if ((currentMethodScope = this.methodScope())
+ != outerLocalVariable.declaringScope.methodScope()) {
+ NestedTypeBinding currentType = (NestedTypeBinding) this.enclosingSourceType();
+
+ //do nothing for member types, pre emulation was performed already
+ if (!currentType.isLocalType()) {
+ return;
+ }
+ // must also add a synthetic field if we're not inside a constructor
+ if (!currentMethodScope.isInsideInitializerOrConstructor()) {
+ currentType.addSyntheticArgumentAndField(outerLocalVariable);
+ } else {
+ currentType.addSyntheticArgument(outerLocalVariable);
+ }
+ }
+ }
+
+ /**
+ * Record the suitable binding denoting a synthetic field or constructor argument,
+ * mapping to a given actual enclosing instance type in the scope context.
+ * Skip it if the enclosingType is actually the current scope's enclosing type.
+ */
+
+ public void emulateOuterAccess(
+ ReferenceBinding targetEnclosingType,
+ boolean useDirectReference) {
+ ReferenceBinding currentType = enclosingSourceType();
+ if (currentType.isNestedType() && currentType != targetEnclosingType) {
+ NestedTypeBinding currentNestedType = (NestedTypeBinding) currentType;
+ if (useDirectReference) {
+ // the target enclosing type is not in scope, we directly refer it
+ // must also add a synthetic field if we're not inside a constructor
+ if (methodScope().isInsideInitializerOrConstructor())
+ currentNestedType.addSyntheticArgument(targetEnclosingType);
+ else
+ currentNestedType.addSyntheticArgumentAndField(targetEnclosingType);
+ } else
+ if (currentNestedType.isLocalType()) {
+ // direct enclosing instance link
+ // must also add a synthetic field if we're not inside a constructor
+ currentType = currentNestedType.enclosingType;
+ if (methodScope().isInsideInitializerOrConstructor())
+ currentNestedType.addSyntheticArgument(currentType);
+ else
+ currentNestedType.addSyntheticArgumentAndField(currentType);
+ // further indirect cases
+ while (currentType != targetEnclosingType
+ && !targetEnclosingType.isSuperclassOf(currentType)) {
+ currentNestedType = (NestedTypeBinding) currentType;
+ currentType = currentNestedType.enclosingType;
+ currentNestedType.addSyntheticArgumentAndField(currentType);
+ }
+ }
+ }
+ }
+
+ /* Note that it must never produce a direct access to the targetEnclosingType,
+ but instead a field sequence (this$2.this$1.this$0) so as to handle such a test case:
+
+ class XX {
+ void foo() {
+ class A {
+ class B {
+ class C {
+ boolean foo() {
+ return (Object) A.this == (Object) B.this;
+ }
+ }
+ }
+ }
+ new A().new B().new C();
+ }
+ }
+
+ where we only want to deal with ONE enclosing instance for C (could not figure out an A for C)
+ */
+ public final ReferenceBinding findLocalType(char[] name) {
+ for (int i = 0, length = scopeIndex; i < length; i++) {
+ if (subscopes[i] instanceof ClassScope) {
+ SourceTypeBinding sourceType =
+ ((ClassScope) subscopes[i]).referenceContext.binding;
+ if (CharOperation.equals(sourceType.sourceName(), name))
+ return sourceType;
+ }
+ }
+ return null;
+ }
+
+ public LocalVariableBinding findVariable(char[] variable) {
+ int variableLength = variable.length;
+ for (int i = 0, length = locals.length; i < length; i++) {
+ LocalVariableBinding local = locals[i];
+ if (local == null)
+ return null;
+ if (local.name.length == variableLength
+ && CharOperation.prefixEquals(local.name, variable))
+ return local;
+ }
+ return null;
+ }
+
+ /* API
+ flag is a mask of the following values VARIABLE (= FIELD or LOCAL), TYPE.
+ Only bindings corresponding to the mask will be answered.
+
+ if the VARIABLE mask is set then
+ If the first name provided is a field (or local) then the field (or local) is answered
+ Otherwise, package names and type names are consumed until a field is found.
+ In this case, the field is answered.
+
+ if the TYPE mask is set,
+ package names and type names are consumed until the end of the input.
+ Only if all of the input is consumed is the type answered
+
+ All other conditions are errors, and a problem binding is returned.
+
+ NOTE: If a problem binding is returned, senders should extract the compound name
+ from the binding & not assume the problem applies to the entire compoundName.
+
+ The VARIABLE mask has precedence over the TYPE mask.
+
+ InvocationSite implements
+ isSuperAccess(); this is used to determine if the discovered field is visible.
+ setFieldIndex(int); this is used to record the number of names that were consumed.
+
+ For example, getBinding({"foo","y","q", VARIABLE, site) will answer
+ the binding for the field or local named "foo" (or an error binding if none exists).
+ In addition, setFieldIndex(1) will be sent to the invocation site.
+ If a type named "foo" exists, it will not be detected (and an error binding will be answered)
+
+ IMPORTANT NOTE: This method is written under the assumption that compoundName is longer than length 1.
+ */
+
+ public Binding getBinding(
+ char[][] compoundName,
+ int mask,
+ InvocationSite invocationSite) {
+ Binding binding =
+ getBinding(compoundName[0], mask | TYPE | PACKAGE, invocationSite);
+ invocationSite.setFieldIndex(1);
+ if (!binding.isValidBinding() || binding instanceof VariableBinding)
+ return binding;
+
+ int length = compoundName.length;
+ int currentIndex = 1;
+ foundType : if (binding instanceof PackageBinding) {
+ PackageBinding packageBinding = (PackageBinding) binding;
+ compilationUnitScope().addNamespaceReference(packageBinding);
+
+ while (currentIndex < length) {
+ binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++]);
+ invocationSite.setFieldIndex(currentIndex);
+ if (binding == null) {
+ if (currentIndex == length)
+ // must be a type if its the last name, otherwise we have no idea if its a package or type
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ NotFound);
+ else
+ return new ProblemBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ NotFound);
+ }
+ if (binding instanceof ReferenceBinding) {
+ if (!binding.isValidBinding())
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ binding.problemId());
+ compilationUnitScope().addTypeReference((ReferenceBinding) binding);
+ if (!((ReferenceBinding) binding).canBeSeenBy(this))
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ NotVisible);
+ break foundType;
+ }
+ packageBinding = (PackageBinding) binding;
+ compilationUnitScope().addNamespaceReference(packageBinding);
+ }
+
+ // It is illegal to request a PACKAGE from this method.
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ NotFound);
+ }
+
+ // know binding is now a ReferenceBinding
+ while (currentIndex < length) {
+ ReferenceBinding typeBinding = (ReferenceBinding) binding;
+ char[] nextName = compoundName[currentIndex++];
+ invocationSite.setFieldIndex(currentIndex);
+ if ((binding = findField(typeBinding, nextName, invocationSite)) != null) {
+ if (!binding.isValidBinding())
+ return new ProblemFieldBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ binding.problemId());
+ break; // binding is now a field
+ }
+ if ((binding = findMemberType(nextName, typeBinding)) == null)
+ return new ProblemBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ typeBinding,
+ NotFound);
+ if (!binding.isValidBinding())
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ binding.problemId());
+ }
+
+ if ((mask & FIELD) != 0
+ && (binding instanceof FieldBinding)) {
+ // was looking for a field and found a field
+ FieldBinding field = (FieldBinding) binding;
+ if (!field.isStatic())
+ return new ProblemFieldBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ NonStaticReferenceInStaticContext);
+ return binding;
+ }
+ if ((mask & TYPE) != 0
+ && (binding instanceof ReferenceBinding)) {
+ // was looking for a type and found a type
+ return binding;
+ }
+
+ // handle the case when a field or type was asked for but we resolved the compoundName to a type or field
+ return new ProblemBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ NotFound);
+ }
+
+ // Added for code assist... NOT Public API
+
+ public final Binding getBinding(
+ char[][] compoundName,
+ InvocationSite invocationSite) {
+ int currentIndex = 0;
+ int length = compoundName.length;
+ Binding binding =
+ getBinding(
+ compoundName[currentIndex++],
+ VARIABLE | TYPE | PACKAGE,
+ invocationSite);
+ if (!binding.isValidBinding())
+ return binding;
+
+ foundType : if (binding instanceof PackageBinding) {
+ while (currentIndex < length) {
+ PackageBinding packageBinding = (PackageBinding) binding;
+ binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++]);
+ if (binding == null) {
+ if (currentIndex == length)
+ // must be a type if its the last name, otherwise we have no idea if its a package or type
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ NotFound);
+ else
+ return new ProblemBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ NotFound);
+ }
+ if (binding instanceof ReferenceBinding) {
+ if (!binding.isValidBinding())
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ binding.problemId());
+ if (!((ReferenceBinding) binding).canBeSeenBy(this))
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ NotVisible);
+ break foundType;
+ }
+ }
+ return binding;
+ }
+
+ foundField : if (binding instanceof ReferenceBinding) {
+ while (currentIndex < length) {
+ ReferenceBinding typeBinding = (ReferenceBinding) binding;
+ char[] nextName = compoundName[currentIndex++];
+ if ((binding = findField(typeBinding, nextName, invocationSite)) != null) {
+ if (!binding.isValidBinding())
+ return new ProblemFieldBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ binding.problemId());
+ if (!((FieldBinding) binding).isStatic())
+ return new ProblemFieldBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ NonStaticReferenceInStaticContext);
+ break foundField; // binding is now a field
+ }
+ if ((binding = findMemberType(nextName, typeBinding)) == null)
+ return new ProblemBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ typeBinding,
+ NotFound);
+ if (!binding.isValidBinding())
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ binding.problemId());
+ }
+ return binding;
+ }
+
+ VariableBinding variableBinding = (VariableBinding) binding;
+ while (currentIndex < length) {
+ TypeBinding typeBinding = variableBinding.type;
+ if (typeBinding == null)
+ return new ProblemFieldBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex + 1),
+ NotFound);
+ variableBinding =
+ findField(typeBinding, compoundName[currentIndex++], invocationSite);
+ if (variableBinding == null)
+ return new ProblemFieldBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ NotFound);
+ if (!variableBinding.isValidBinding())
+ return variableBinding;
+ }
+ return variableBinding;
+ }
+
+ /* API
+
+ Answer the binding that corresponds to the argument name.
+ flag is a mask of the following values VARIABLE (= FIELD or LOCAL), TYPE, PACKAGE.
+ Only bindings corresponding to the mask can be answered.
+
+ For example, getBinding("foo", VARIABLE, site) will answer
+ the binding for the field or local named "foo" (or an error binding if none exists).
+ If a type named "foo" exists, it will not be detected (and an error binding will be answered)
+
+ The VARIABLE mask has precedence over the TYPE mask.
+
+ If the VARIABLE mask is not set, neither fields nor locals will be looked for.
+
+ InvocationSite implements:
+ isSuperAccess(); this is used to determine if the discovered field is visible.
+
+ Limitations: cannot request FIELD independently of LOCAL, or vice versa
+ */
+
+ public Binding getBinding(
+ char[] name,
+ int mask,
+ InvocationSite invocationSite) {
+ Binding binding = null;
+ FieldBinding problemField = null;
+ if ((mask & VARIABLE) != 0) {
+ if (this.kind == BLOCK_SCOPE || this.kind == METHOD_SCOPE) {
+ LocalVariableBinding variableBinding = findVariable(name);
+ // looks in this scope only
+ if (variableBinding != null)
+ return variableBinding;
+ }
+
+ boolean insideStaticContext = false;
+ boolean insideConstructorCall = false;
+ if (this.kind == METHOD_SCOPE) {
+ MethodScope methodScope = (MethodScope) this;
+ insideStaticContext |= methodScope.isStatic;
+ insideConstructorCall |= methodScope.isConstructorCall;
+ }
+
+ FieldBinding foundField = null;
+ // can be a problem field which is answered if a valid field is not found
+ ProblemFieldBinding foundInsideProblem = null;
+ // inside Constructor call or inside static context
+ Scope scope = parent;
+ int depth = 0;
+ done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found
+ switch (scope.kind) {
+ case METHOD_SCOPE :
+ MethodScope methodScope = (MethodScope) scope;
+ insideStaticContext |= methodScope.isStatic;
+ insideConstructorCall |= methodScope.isConstructorCall;
+ // Fall through... could duplicate the code below to save a cast - questionable optimization
+ case BLOCK_SCOPE :
+ LocalVariableBinding variableBinding = ((BlockScope) scope).findVariable(name);
+ // looks in this scope only
+ if (variableBinding != null) {
+ if (foundField != null && foundField.isValidBinding())
+ return new ProblemFieldBinding(name, InheritedNameHidesEnclosingName);
+ if (depth > 0)
+ invocationSite.setDepth(depth);
+ return variableBinding;
+ }
+ break;
+ case CLASS_SCOPE :
+ ClassScope classScope = (ClassScope) scope;
+ SourceTypeBinding enclosingType = classScope.referenceContext.binding;
+ FieldBinding fieldBinding =
+ classScope.findField(enclosingType, name, invocationSite);
+ // Use next line instead if willing to enable protected access accross inner types
+ // FieldBinding fieldBinding = findField(enclosingType, name, invocationSite);
+ if (fieldBinding != null) { // skip it if we did not find anything
+ if (fieldBinding.problemId() == Ambiguous) {
+ if (foundField == null || foundField.problemId() == NotVisible)
+ // supercedes any potential InheritedNameHidesEnclosingName problem
+ return fieldBinding;
+ else
+ // make the user qualify the field, likely wants the first inherited field (javac generates an ambiguous error instead)
+ return new ProblemFieldBinding(name, InheritedNameHidesEnclosingName);
+ }
+
+ ProblemFieldBinding insideProblem = null;
+ if (fieldBinding.isValidBinding()) {
+ if (!fieldBinding.isStatic()) {
+ if (insideConstructorCall) {
+ insideProblem =
+ new ProblemFieldBinding(name, NonStaticReferenceInConstructorInvocation);
+ } else
+ if (insideStaticContext) {
+ insideProblem =
+ new ProblemFieldBinding(name, NonStaticReferenceInStaticContext);
+ }
+ }
+ if (enclosingType == fieldBinding.declaringClass) {
+ // found a valid field in the 'immediate' scope (ie. not inherited)
+ if (foundField == null) {
+ if (depth > 0)
+ invocationSite.setDepth(depth);
+ // return the fieldBinding if it is not declared in a superclass of the scope's binding (i.e. "inherited")
+ return insideProblem == null ? fieldBinding : insideProblem;
+ }
+ if (foundField.isValidBinding())
+ // if a valid field was found, complain when another is found in an 'immediate' enclosing type (ie. not inherited)
+ if (foundField.declaringClass != fieldBinding.declaringClass)
+ // ie. have we found the same field - do not trust field identity yet
+ return new ProblemFieldBinding(name, InheritedNameHidesEnclosingName);
+ }
+ }
+
+ if (foundField == null
+ || (foundField.problemId() == NotVisible
+ && fieldBinding.problemId() != NotVisible)) {
+ // only remember the fieldBinding if its the first one found or the previous one was not visible & fieldBinding is...
+ if (depth > 0)
+ invocationSite.setDepth(depth);
+ foundInsideProblem = insideProblem;
+ foundField = fieldBinding;
+ }
+ }
+ depth++;
+ insideStaticContext |= enclosingType.isStatic();
+ // 1EX5I8Z - accessing outer fields within a constructor call is permitted
+ // in order to do so, we change the flag as we exit from the type, not the method
+ // itself, because the class scope is used to retrieve the fields.
+ MethodScope enclosingMethodScope = scope.methodScope();
+ insideConstructorCall =
+ enclosingMethodScope == null ? false : enclosingMethodScope.isConstructorCall;
+ break;
+ case COMPILATION_UNIT_SCOPE :
+ break done;
+ }
+ scope = scope.parent;
+ }
+
+ if (foundInsideProblem != null)
+ return foundInsideProblem;
+ if (foundField != null) {
+ if (foundField.isValidBinding())
+ return foundField;
+ problemField = foundField;
+ }
+ }
+
+ // We did not find a local or instance variable.
+ if ((mask & TYPE) != 0) {
+ if ((binding = getBaseType(name)) != null)
+ return binding;
+ binding = getTypeOrPackage(name, (mask & PACKAGE) == 0 ? TYPE : TYPE | PACKAGE);
+ if (binding.isValidBinding() || mask == TYPE)
+ return binding;
+ // answer the problem type binding if we are only looking for a type
+ } else
+ if ((mask & PACKAGE) != 0) {
+ if ((binding = environment().getTopLevelPackage(name)) != null)
+ return binding;
+ }
+ if (problemField != null)
+ return problemField;
+ else
+ return new ProblemBinding(name, enclosingSourceType(), NotFound);
+ }
+
+ /**
+ * This retrieves the argument that maps to an enclosing instance of the suitable type,
+ * if not found then answers nil -- do not create one
+
+ * #implicitThis : the implicit this will be ok
+ * #((arg) this$n) : available as a constructor arg
+ * #((arg) this$n access$m... access$p) : available as as a constructor arg + a sequence of synthetic accessors to synthetic fields
+ * #((fieldDescr) this$n access#m... access$p) : available as a first synthetic field + a sequence of synthetic accessors to synthetic fields
+ * nil : not found
+ *
+ */
+ public Object[] getCompatibleEmulationPath(ReferenceBinding targetEnclosingType) {
+ MethodScope currentMethodScope = this.methodScope();
+ SourceTypeBinding sourceType = currentMethodScope.enclosingSourceType();
+
+ // identity check
+ if ((!currentMethodScope.isStatic)
+ && (sourceType == targetEnclosingType
+ || targetEnclosingType.isSuperclassOf(sourceType))) {
+ return EmulationPathToImplicitThis; // implicit this is good enough
+ }
+ if (!sourceType.isNestedType()
+ || sourceType.isStatic()) { // no emulation from within non-inner types
+ return null;
+ }
+ boolean insideConstructor =
+ currentMethodScope.isInsideInitializerOrConstructor();
+ // use synthetic constructor arguments if possible
+ if (insideConstructor) {
+ SyntheticArgumentBinding syntheticArg;
+ if ((syntheticArg =
+ ((NestedTypeBinding) sourceType).getSyntheticArgument(
+ targetEnclosingType,
+ this))
+ != null) {
+ return new Object[] { syntheticArg };
+ }
+ }
+ // use a direct synthetic field then
+ if (!currentMethodScope.isStatic) {
+ FieldBinding syntheticField;
+ if ((syntheticField = sourceType.getSyntheticField(targetEnclosingType, this))
+ != null) {
+ return new Object[] { syntheticField };
+ }
+ // could be reached through a sequence of enclosing instance link (nested members)
+ Object[] path = new Object[2]; // probably at least 2 of them
+ ReferenceBinding currentType = sourceType.enclosingType();
+ if (insideConstructor) {
+ path[0] =
+ ((NestedTypeBinding) sourceType).getSyntheticArgument(
+ (SourceTypeBinding) currentType,
+ this);
+ } else {
+ path[0] = sourceType.getSyntheticField((SourceTypeBinding) currentType, this);
+ }
+ if (path[0] != null) { // keep accumulating
+ int count = 1;
+ ReferenceBinding currentEnclosingType;
+ while ((currentEnclosingType = currentType.enclosingType()) != null) {
+ //done?
+ if (currentType == targetEnclosingType
+ || targetEnclosingType.isSuperclassOf(currentType))
+ break;
+ syntheticField =
+ ((NestedTypeBinding) currentType).getSyntheticField(
+ (SourceTypeBinding) currentEnclosingType,
+ this);
+ if (syntheticField == null)
+ break;
+ // append inside the path
+ if (count == path.length) {
+ System.arraycopy(path, 0, (path = new Object[count + 1]), 0, count);
+ }
+ // private access emulation is necessary since synthetic field is private
+ path[count++] = syntheticField.getSyntheticReadAccess();
+ currentType = currentEnclosingType;
+ }
+ if (currentType == targetEnclosingType
+ || targetEnclosingType.isSuperclassOf(currentType)) {
+ return path;
+ }
+ }
+ }
+ return null;
+ }
+
+ /* API
+
+ Answer the constructor binding that corresponds to receiverType, argumentTypes.
+
+ InvocationSite implements
+ isSuperAccess(); this is used to determine if the discovered constructor is visible.
+
+ If no visible constructor is discovered, an error binding is answered.
+ */
+
+ public MethodBinding getConstructor(
+ ReferenceBinding receiverType,
+ TypeBinding[] argumentTypes,
+ InvocationSite invocationSite) {
+ compilationUnitScope().addTypeReferences(argumentTypes);
+ MethodBinding methodBinding = receiverType.getExactConstructor(argumentTypes);
+ if (methodBinding != null)
+ if (methodBinding.canBeSeenBy(invocationSite, this))
+ return methodBinding;
+
+ MethodBinding[] methods =
+ receiverType.getMethods(ConstructorDeclaration.ConstantPoolName);
+ if (methods == NoMethods)
+ return new ProblemMethodBinding(
+ ConstructorDeclaration.ConstantPoolName,
+ argumentTypes,
+ NotFound);
+
+ MethodBinding[] compatible = new MethodBinding[methods.length];
+ int compatibleIndex = 0;
+ for (int i = 0, length = methods.length; i < length; i++)
+ if (areParametersAssignable(methods[i].parameters, argumentTypes))
+ compatible[compatibleIndex++] = methods[i];
+ if (compatibleIndex == 0)
+ return new ProblemMethodBinding(
+ ConstructorDeclaration.ConstantPoolName,
+ argumentTypes,
+ NotFound);
+ // need a more descriptive error... cannot convert from X to Y
+
+ MethodBinding[] visible = new MethodBinding[compatibleIndex];
+ int visibleIndex = 0;
+ for (int i = 0; i < compatibleIndex; i++) {
+ MethodBinding method = compatible[i];
+ if (method.canBeSeenBy(invocationSite, this))
+ visible[visibleIndex++] = method;
+ }
+ if (visibleIndex == 1)
+ return visible[0];
+ if (visibleIndex == 0)
+ return new ProblemMethodBinding(
+ ConstructorDeclaration.ConstantPoolName,
+ argumentTypes,
+ NotVisible);
+ return mostSpecificClassMethodBinding(visible, visibleIndex);
+ }
+
+ /**
+ * This retrieves the argument that maps to an enclosing instance of the suitable type,
+ * if not found then answers nil -- do not create one
+
+ * #implicitThis : the implicit this will be ok
+ * #((arg) this$n) : available as a constructor arg
+ * #((arg) this$n ... this$p) : available as as a constructor arg + a sequence of fields
+ * #((fieldDescr) this$n ... this$p) : available as a sequence of fields
+ * nil : not found
+
+ * Note that this algorithm should answer the shortest possible sequence when
+ * shortcuts are available:
+ * this$0 . this$0 . this$0
+ * instead of
+ * this$2 . this$1 . this$0 . this$1 . this$0
+ * thus the code generation will be more compact and runtime faster
+ */
+ public VariableBinding[] getEmulationPath(LocalVariableBinding outerLocalVariable) {
+
+ MethodScope currentMethodScope = this.methodScope();
+ SourceTypeBinding sourceType = currentMethodScope.enclosingSourceType();
+
+ // identity check
+ if (currentMethodScope == outerLocalVariable.declaringScope.methodScope()) {
+ return new VariableBinding[] { outerLocalVariable };
+ // implicit this is good enough
+ }
+ // use synthetic constructor arguments if possible
+ if (currentMethodScope.isInsideInitializerOrConstructor()
+ && (sourceType.isNestedType())) {
+ SyntheticArgumentBinding syntheticArg;
+ if ((syntheticArg =
+ ((NestedTypeBinding) sourceType).getSyntheticArgument(outerLocalVariable))
+ != null) {
+ return new VariableBinding[] { syntheticArg };
+ }
+ }
+ // use a synthetic field then
+ if (!currentMethodScope.isStatic) {
+ FieldBinding syntheticField;
+ if ((syntheticField = sourceType.getSyntheticField(outerLocalVariable))
+ != null) {
+ return new VariableBinding[] { syntheticField };
+ }
+ }
+ return null;
+ }
+
+ /*
+ | mapping mappingSequence targetFieldKey traversedType investigateArguments staticInvocationSite
+ targetDepth nameEnvironment |
+
+ targetDepth := expectedEnclosingClass enclosingDepth.
+ targetFieldKey := 'this$' , targetDepth printString. "$NON-NLS$"
+ mappingSequence := OrderedCollection new.
+ investigateArguments := enclosingMethod isConstructor.
+ staticInvocationSite := enclosingMethod isJavaStatic.
+ nameEnvironment := enclosingMethod nameEnvironment.
+
+ "If possible looks through the available constructor arguments (if we are in context only)"
+ investigateArguments
+ ifTrue: [
+ (mapping :=
+ self generatedConstructorArguments "get back an argument local"
+ at: targetFieldKey
+ ifAbsent: [])
+ notNil
+ ifTrue: [
+ (mapping resolvedType
+ isCompatibleWith: expectedEnclosingClass
+ in: nameEnvironment)
+ ifTrue: [
+ ^mappingSequence
+ add: mapping;
+ yourself]]].
+
+ "Cannot look into synthetic field on static invocation site"
+ staticInvocationSite ifTrue: [^nil].
+
+ "We now have to compute the <[argument|field]field*> sequence to retrieve the correct enclosing instance,
+ using the traversedType collection from one of them we will be able to reach the correct
+ target type, but difficult to foresee the correct one since the fields this$0... this$n may
+ be sparsely allocated."
+ traversedType := self.
+
+ [traversedType isNil] whileFalse: [| info |
+ info :=
+ (investigateArguments and: [traversedType == self])
+ ifTrue: [ "use argument" traversedType generatedConstructorArguments]
+ ifFalse: [ "use field" traversedType generatedAccessFields].
+ mapping :=
+ info "try a direct shortcut"
+ at: targetFieldKey
+ ifAbsent: [
+ info "one level-up"
+ at: 'this$' , (traversedType enclosingDepth - 1) printString "$NON-NLS$"
+ ifAbsent: [ "cannot proceed" ^nil]].
+ mappingSequence add: mapping.
+
+ "If the mapping matches the expected type, then we are done."
+ ((mapping isJavaFieldDescriptor ifTrue: [mapping type] ifFalse: [mapping resolvedType])
+ isCompatibleWith: expectedEnclosingClass
+ in: nameEnvironment)
+ ifTrue: [^mappingSequence].
+
+ "Go to the next enclosing type"
+ traversedType := traversedType enclosingType].
+
+
+ "Not suitable enclosing instance available -- should never reach this point since detected above"
+ enclosingMethod errorInterface
+ abortDueToInternalError: (NlsCatJDEV indexedMsg: 439). "$NLS$ Failed to emulate access to enclosing instance"
+ ^nil
+
+ */
+ /**
+ * This retrieves the argument that maps to an enclosing instance of the suitable type,
+ * if not found then answers nil -- do not create one
+
+ * #implicitThis : the implicit this will be ok
+ * #((arg) this$n) : available as a constructor arg
+ * #((arg) this$n access$m... access$p) : available as as a constructor arg + a sequence of synthetic accessors to synthetic fields
+ * #((fieldDescr) this$n access#m... access$p) : available as a first synthetic field + a sequence of synthetic accessors to synthetic fields
+ * nil : not found
+ *
+ * EXACT MATCH VERSION - no type compatibility is performed
+ */
+ public Object[] getExactEmulationPath(ReferenceBinding targetEnclosingType) {
+ MethodScope currentMethodScope = this.methodScope();
+ SourceTypeBinding sourceType = currentMethodScope.enclosingSourceType();
+
+ // identity check
+ if ((!currentMethodScope.isStatic) && (sourceType == targetEnclosingType)) {
+ return EmulationPathToImplicitThis; // implicit this is good enough
+ }
+ if (!sourceType.isNestedType()
+ || sourceType.isStatic()) { // no emulation from within non-inner types
+ return null;
+ }
+ boolean insideConstructor =
+ currentMethodScope.isInsideInitializerOrConstructor();
+ // use synthetic constructor arguments if possible
+ if (insideConstructor) {
+ SyntheticArgumentBinding syntheticArg;
+ if ((syntheticArg =
+ ((NestedTypeBinding) sourceType).getSyntheticArgument(
+ targetEnclosingType,
+ this))
+ != null) {
+ return new Object[] { syntheticArg };
+ }
+ }
+ // use a direct synthetic field then
+ if (!currentMethodScope.isStatic) {
+ FieldBinding syntheticField;
+ if ((syntheticField = sourceType.getSyntheticField(targetEnclosingType, this))
+ != null) {
+ return new Object[] { syntheticField };
+ }
+ // could be reached through a sequence of enclosing instance link (nested members)
+ Object[] path = new Object[2]; // probably at least 2 of them
+ ReferenceBinding currentType = sourceType.enclosingType();
+ if (insideConstructor) {
+ path[0] =
+ ((NestedTypeBinding) sourceType).getSyntheticArgument(
+ (SourceTypeBinding) currentType,
+ this);
+ } else {
+ path[0] = sourceType.getSyntheticField((SourceTypeBinding) currentType, this);
+ }
+ if (path[0] != null) { // keep accumulating
+ int count = 1;
+ ReferenceBinding currentEnclosingType;
+ while ((currentEnclosingType = currentType.enclosingType()) != null) {
+ //done?
+ if (currentType == targetEnclosingType)
+ break;
+ syntheticField =
+ ((NestedTypeBinding) currentType).getSyntheticField(
+ (SourceTypeBinding) currentEnclosingType,
+ this);
+ if (syntheticField == null)
+ break;
+ // append inside the path
+ if (count == path.length) {
+ System.arraycopy(path, 0, (path = new Object[count + 1]), 0, count);
+ }
+ // private access emulation is necessary since synthetic field is private
+ path[count++] = syntheticField.getSyntheticReadAccess();
+ currentType = currentEnclosingType;
+ }
+ if (currentType == targetEnclosingType) {
+ return path;
+ }
+ }
+ }
+ return null;
+ }
+
+ /* API
+
+ Answer the field binding that corresponds to fieldName.
+ Start the lookup at the receiverType.
+ InvocationSite implements
+ isSuperAccess(); this is used to determine if the discovered field is visible.
+ Only fields defined by the receiverType or its supertypes are answered;
+ a field of an enclosing type will not be found using this API.
+
+ If no visible field is discovered, an error binding is answered.
+ */
+
+ public FieldBinding getField(
+ TypeBinding receiverType,
+ char[] fieldName,
+ InvocationSite invocationSite) {
+ FieldBinding field = findField(receiverType, fieldName, invocationSite);
+ if (field == null)
+ return new ProblemFieldBinding(fieldName, NotFound);
+ else
+ return field;
+ }
+
+ /* API
+
+ Answer the method binding that corresponds to selector, argumentTypes.
+ Start the lookup at the enclosing type of the receiver.
+ InvocationSite implements
+ isSuperAccess(); this is used to determine if the discovered method is visible.
+ setDepth(int); this is used to record the depth of the discovered method
+ relative to the enclosing type of the receiver. (If the method is defined
+ in the enclosing type of the receiver, the depth is 0; in the next enclosing
+ type, the depth is 1; and so on
+
+ If no visible method is discovered, an error binding is answered.
+ */
+
+ public MethodBinding getImplicitMethod(
+ char[] selector,
+ TypeBinding[] argumentTypes,
+ InvocationSite invocationSite) {
+ boolean insideStaticContext = false;
+ boolean insideConstructorCall = false;
+ MethodBinding foundMethod = null;
+ ProblemMethodBinding foundFuzzyProblem = null;
+ // the weird method lookup case (matches method name in scope, then arg types, then visibility)
+ ProblemMethodBinding foundInsideProblem = null;
+ // inside Constructor call or inside static context
+ Scope scope = this;
+ int depth = 0;
+ done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found
+ switch (scope.kind) {
+ case METHOD_SCOPE :
+ MethodScope methodScope = (MethodScope) scope;
+ insideStaticContext |= methodScope.isStatic;
+ insideConstructorCall |= methodScope.isConstructorCall;
+ break;
+ case CLASS_SCOPE :
+ ClassScope classScope = (ClassScope) scope;
+ SourceTypeBinding receiverType = classScope.referenceContext.binding;
+ boolean isExactMatch = true;
+ // retrieve an exact visible match (if possible)
+ MethodBinding methodBinding =
+ (foundMethod == null)
+ ? classScope.findExactMethod(
+ receiverType,
+ selector,
+ argumentTypes,
+ invocationSite)
+ : classScope.findExactMethod(
+ receiverType,
+ foundMethod.selector,
+ foundMethod.parameters,
+ invocationSite);
+ // ? findExactMethod(receiverType, selector, argumentTypes, invocationSite)
+ // : findExactMethod(receiverType, foundMethod.selector, foundMethod.parameters, invocationSite);
+ if (methodBinding == null && foundMethod == null) {
+ // answers closest approximation, may not check argumentTypes or visibility
+ isExactMatch = false;
+ methodBinding =
+ classScope.findMethod(receiverType, selector, argumentTypes, invocationSite);
+ // methodBinding = findMethod(receiverType, selector, argumentTypes, invocationSite);
+ }
+ if (methodBinding != null) { // skip it if we did not find anything
+ if (methodBinding.problemId() == Ambiguous) {
+ if (foundMethod == null || foundMethod.problemId() == NotVisible)
+ // supercedes any potential InheritedNameHidesEnclosingName problem
+ return methodBinding;
+ else
+ // make the user qualify the method, likely wants the first inherited method (javac generates an ambiguous error instead)
+ return new ProblemMethodBinding(
+ selector,
+ argumentTypes,
+ InheritedNameHidesEnclosingName);
+ }
+
+ ProblemMethodBinding fuzzyProblem = null;
+ ProblemMethodBinding insideProblem = null;
+ if (methodBinding.isValidBinding()) {
+ if (!isExactMatch) {
+ if (!areParametersAssignable(methodBinding.parameters, argumentTypes)) {
+ fuzzyProblem =
+ new ProblemMethodBinding(methodBinding, selector, argumentTypes, NotFound);
+ } else
+ if (!methodBinding.canBeSeenBy(receiverType, invocationSite, classScope)) {
+ // using <classScope> instead of <this> for visibility check does grant all access to innerclass
+ fuzzyProblem =
+ new ProblemMethodBinding(
+ selector,
+ argumentTypes,
+ methodBinding.declaringClass,
+ NotVisible);
+ }
+ }
+ if (fuzzyProblem == null && !methodBinding.isStatic()) {
+ if (insideConstructorCall) {
+ insideProblem =
+ new ProblemMethodBinding(
+ methodBinding.selector,
+ methodBinding.parameters,
+ NonStaticReferenceInConstructorInvocation);
+ } else
+ if (insideStaticContext) {
+ insideProblem =
+ new ProblemMethodBinding(
+ methodBinding.selector,
+ methodBinding.parameters,
+ NonStaticReferenceInStaticContext);
+ }
+ }
+ if (receiverType == methodBinding.declaringClass
+ || (receiverType.getMethods(selector)) != NoMethods) {
+ // found a valid method in the 'immediate' scope (ie. not inherited)
+ // OR the receiverType implemented a method with the correct name
+ if (foundMethod == null) {
+ if (depth > 0)
+ invocationSite.setDepth(depth);
+ // return the methodBinding if it is not declared in a superclass of the scope's binding (i.e. "inherited")
+ if (fuzzyProblem != null)
+ return fuzzyProblem;
+ if (insideProblem != null)
+ return insideProblem;
+ return methodBinding;
+ }
+ // if a method was found, complain when another is found in an 'immediate' enclosing type (ie. not inherited)
+ // NOTE: Unlike fields, a non visible method hides a visible method
+ if (foundMethod.declaringClass != methodBinding.declaringClass)
+ // ie. have we found the same method - do not trust field identity yet
+ return new ProblemMethodBinding(
+ methodBinding.selector,
+ methodBinding.parameters,
+ InheritedNameHidesEnclosingName);
+ }
+ }
+
+ if (foundMethod == null
+ || (foundMethod.problemId() == NotVisible
+ && methodBinding.problemId() != NotVisible)) {
+ // only remember the methodBinding if its the first one found or the previous one was not visible & methodBinding is...
+ // remember that private methods are visible if defined directly by an enclosing class
+ if (depth > 0)
+ invocationSite.setDepth(depth);
+ foundFuzzyProblem = fuzzyProblem;
+ foundInsideProblem = insideProblem;
+ if (fuzzyProblem == null)
+ foundMethod = methodBinding; // only keep it if no error was found
+ }
+ }
+ depth++;
+ insideStaticContext |= receiverType.isStatic();
+ // 1EX5I8Z - accessing outer fields within a constructor call is permitted
+ // in order to do so, we change the flag as we exit from the type, not the method
+ // itself, because the class scope is used to retrieve the fields.
+ MethodScope enclosingMethodScope = scope.methodScope();
+ insideConstructorCall =
+ enclosingMethodScope == null ? false : enclosingMethodScope.isConstructorCall;
+ break;
+ case COMPILATION_UNIT_SCOPE :
+ break done;
+ }
+ scope = scope.parent;
+ }
+
+ if (foundFuzzyProblem != null)
+ return foundFuzzyProblem;
+ if (foundInsideProblem != null)
+ return foundInsideProblem;
+ if (foundMethod != null)
+ return foundMethod;
+ return new ProblemMethodBinding(selector, argumentTypes, NotFound);
+ }
+
+ /* API
+
+ Answer the method binding that corresponds to selector, argumentTypes.
+ Start the lookup at the receiverType.
+ InvocationSite implements
+ isSuperAccess(); this is used to determine if the discovered method is visible.
+
+ Only methods defined by the receiverType or its supertypes are answered;
+ use getImplicitMethod() to discover methods of enclosing types.
+
+ If no visible method is discovered, an error binding is answered.
+ */
+
+ public MethodBinding getMethod(
+ TypeBinding receiverType,
+ char[] selector,
+ TypeBinding[] argumentTypes,
+ InvocationSite invocationSite) {
+ if (receiverType.isArrayType())
+ return findMethodForArray(
+ (ArrayBinding) receiverType,
+ selector,
+ argumentTypes,
+ invocationSite);
+ if (receiverType.isBaseType())
+ return new ProblemMethodBinding(selector, argumentTypes, NotFound);
+
+ ReferenceBinding currentType = (ReferenceBinding) receiverType;
+ if (!currentType.canBeSeenBy(this))
+ return new ProblemMethodBinding(selector, argumentTypes, NotVisible);
+ // *** Need a new problem id - TypeNotVisible?
+
+ // retrieve an exact visible match (if possible)
+ MethodBinding methodBinding =
+ findExactMethod(currentType, selector, argumentTypes, invocationSite);
+ if (methodBinding != null)
+ return methodBinding;
+
+ // answers closest approximation, may not check argumentTypes or visibility
+ methodBinding =
+ findMethod(currentType, selector, argumentTypes, invocationSite);
+ if (methodBinding == null)
+ return new ProblemMethodBinding(selector, argumentTypes, NotFound);
+ if (methodBinding.isValidBinding()) {
+ if (!areParametersAssignable(methodBinding.parameters, argumentTypes))
+ return new ProblemMethodBinding(
+ methodBinding,
+ selector,
+ argumentTypes,
+ NotFound);
+ if (!methodBinding.canBeSeenBy(currentType, invocationSite, this))
+ return new ProblemMethodBinding(
+ selector,
+ argumentTypes,
+ methodBinding.declaringClass,
+ NotVisible);
+ }
+ return methodBinding;
+ }
+
+ /* Answer the problem reporter to use for raising new problems.
+ *
+ * Note that as a side-effect, this updates the current reference context
+ * (unit, type or method) in case the problem handler decides it is necessary
+ * to abort.
+ */
+
+ public ProblemReporter problemReporter() {
+ return outerMostMethodScope().problemReporter();
+ }
+
+ /**
+ * Code responsible to request some more emulation work inside the invocation type, so as to supply
+ * correct synthetic arguments to any allocation of the target type.
+ */
+ public void propagateInnerEmulation(
+ ReferenceBinding targetType,
+ boolean isEnclosingInstanceSupplied,
+ boolean useDirectReference) {
+
+ // perform some emulation work in case there is some and we are inside a local type only
+ // propage emulation of the enclosing instances
+
+ ReferenceBinding[] syntheticArgumentTypes;
+ if ((syntheticArgumentTypes = targetType.syntheticEnclosingInstanceTypes())
+ != null) {
+ for (int i = 0, max = syntheticArgumentTypes.length; i < max; i++) {
+ ReferenceBinding syntheticArgType = syntheticArgumentTypes[i];
+ // need to filter out the one that could match a supplied enclosing instance
+ if (!(isEnclosingInstanceSupplied
+ && (syntheticArgType == targetType.enclosingType()))) {
+ this.emulateOuterAccess(syntheticArgType, useDirectReference);
+ }
+ }
+ }
+ SyntheticArgumentBinding[] syntheticArguments;
+ if ((syntheticArguments = targetType.syntheticOuterLocalVariables()) != null) {
+ for (int i = 0, max = syntheticArguments.length; i < max; i++) {
+ SyntheticArgumentBinding syntheticArg = syntheticArguments[i];
+ // need to filter out the one that could match a supplied enclosing instance
+ if (!(isEnclosingInstanceSupplied
+ && (syntheticArg.type == targetType.enclosingType()))) {
+ this.emulateOuterAccess(syntheticArg.actualOuterLocalVariable);
+ }
+ }
+ }
+ }
+
+ /* Answer the reference type of this scope.
+ *
+ * i.e. the nearest enclosing type of this scope.
+ */
+
+ public TypeDeclaration referenceType() {
+ return methodScope().referenceType();
+ }
+
+ // start position in this scope - for ordering scopes vs. variables
+ int startIndex() {
+ return startIndex;
+ }
+
+ public String toString() {
+ return toString(0);
+ }
+
+ public String toString(int tab) {
+ String s = basicToString(tab);
+ for (int i = 0; i < scopeIndex; i++)
+ if (subscopes[i] instanceof BlockScope)
+ s += ((BlockScope) subscopes[i]).toString(tab + 1) + "\n";
+ return s;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
new file mode 100644
index 0000000000..b262059508
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
@@ -0,0 +1,993 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class ClassScope extends Scope {
+ public TypeDeclaration referenceContext;
+ public ClassScope(Scope parent, TypeDeclaration context) {
+ super(CLASS_SCOPE, parent);
+ this.referenceContext = context;
+ }
+
+ void buildAnonymousTypeBinding(
+ SourceTypeBinding enclosingType,
+ ReferenceBinding supertype) {
+ buildLocalType(enclosingType, enclosingType.fPackage);
+
+ SourceTypeBinding sourceType = referenceContext.binding;
+ if (supertype.isInterface()) {
+ sourceType.superclass = getJavaLangObject();
+ sourceType.superInterfaces = new ReferenceBinding[] { supertype };
+ } else {
+ sourceType.superclass = supertype;
+ sourceType.superInterfaces = TypeBinding.NoSuperInterfaces;
+ }
+ connectMemberTypes();
+ buildFieldsAndMethods();
+ sourceType.verifyMethods(environment().methodVerifier());
+ }
+
+ private void buildFields() {
+ if (referenceContext.fields == null) {
+ referenceContext.binding.fields = NoFields;
+ return;
+ }
+
+ // count the number of fields vs. initializers
+ FieldDeclaration[] fields = referenceContext.fields;
+ int size = fields.length;
+ int count = 0;
+ for (int i = 0; i < size; i++)
+ if (fields[i].isField())
+ count++;
+
+ // iterate the field declarations to create the bindings, lose all duplicates
+ FieldBinding[] fieldBindings = new FieldBinding[count];
+ HashtableOfObject knownFieldNames = new HashtableOfObject(count);
+ boolean duplicate = false;
+ count = 0;
+ for (int i = 0; i < size; i++) {
+ FieldDeclaration field = fields[i];
+ if (!field.isField()) {
+ if (referenceContext.binding.isInterface())
+ problemReporter().interfaceCannotHaveInitializers(
+ referenceContext.binding,
+ field);
+ } else {
+ FieldBinding fieldBinding =
+ new FieldBinding(field, null, referenceContext.binding);
+ // field's type will be resolved when needed for top level types
+ checkAndSetModifiersForField(fieldBinding, field);
+
+ if (knownFieldNames.containsKey(field.name)) {
+ duplicate = true;
+ FieldBinding previousBinding = (FieldBinding) knownFieldNames.get(field.name);
+ if (previousBinding != null) {
+ for (int f = 0; f < i; f++) {
+ FieldDeclaration previousField = fields[f];
+ if (previousField.binding == previousBinding) {
+ problemReporter().duplicateFieldInType(referenceContext.binding, previousField);
+ previousField.binding = null;
+ break;
+ }
+ }
+ }
+ knownFieldNames.put(field.name, null);
+ // ensure that the duplicate field is found & removed
+ problemReporter().duplicateFieldInType(referenceContext.binding, field);
+ field.binding = null;
+ } else {
+ knownFieldNames.put(field.name, fieldBinding);
+ // remember that we have seen a field with this name
+ if (fieldBinding != null)
+ fieldBindings[count++] = fieldBinding;
+ }
+ }
+ }
+
+ // remove duplicate fields
+ if (duplicate) {
+ FieldBinding[] newFieldBindings = new FieldBinding[knownFieldNames.size() - 1];
+ // we know we'll be removing at least 1 duplicate name
+ size = count;
+ count = 0;
+ for (int i = 0; i < size; i++) {
+ FieldBinding fieldBinding = fieldBindings[i];
+ if (knownFieldNames.get(fieldBinding.name) != null)
+ newFieldBindings[count++] = fieldBinding;
+ }
+ fieldBindings = newFieldBindings;
+ }
+
+ if (count != fieldBindings.length)
+ System.arraycopy(
+ fieldBindings,
+ 0,
+ fieldBindings = new FieldBinding[count],
+ 0,
+ count);
+ for (int i = 0; i < count; i++)
+ fieldBindings[i].id = i;
+ referenceContext.binding.fields = fieldBindings;
+ if (referenceContext.binding.isLocalType())
+ referenceContext.binding.fields();
+ // fault the types for the local type's fields now since we need them
+ }
+
+ void buildFieldsAndMethods() {
+ buildFields();
+ buildMethods();
+
+ SourceTypeBinding sourceType = referenceContext.binding;
+ if (sourceType.isMemberType() && !sourceType.isLocalType())
+ ((MemberTypeBinding) sourceType).checkSyntheticArgsAndFields();
+
+ ReferenceBinding[] memberTypes = sourceType.memberTypes;
+ for (int i = 0, length = memberTypes.length; i < length; i++)
+ ((SourceTypeBinding) memberTypes[i]).scope.buildFieldsAndMethods();
+ }
+
+ private LocalTypeBinding buildLocalType(
+ SourceTypeBinding enclosingType,
+ PackageBinding packageBinding) {
+ referenceContext.scope = this;
+ referenceContext.staticInitializerScope =
+ new MethodScope(this, referenceContext, true);
+ referenceContext.initializerScope =
+ new MethodScope(this, referenceContext, false);
+
+ // build the binding or the local type
+ LocalTypeBinding localType = new LocalTypeBinding(this, enclosingType);
+ referenceContext.binding = localType;
+ checkAndSetModifiers();
+
+ // Look at member types
+ ReferenceBinding[] memberTypeBindings = NoMemberTypes;
+ if (referenceContext.memberTypes != null) {
+ int size = referenceContext.memberTypes.length;
+ memberTypeBindings = new ReferenceBinding[size];
+ int count = 0;
+ nextMember : for (int i = 0; i < size; i++) {
+ TypeDeclaration memberContext = referenceContext.memberTypes[i];
+ if (memberContext.isInterface()) {
+ problemReporter().nestedClassCannotDeclareInterface(memberContext);
+ continue nextMember;
+ }
+ ReferenceBinding type = localType;
+ // check that the member does not conflict with an enclosing type
+ do {
+ if (CharOperation.equals(type.sourceName, memberContext.name)) {
+ problemReporter().hidingEnclosingType(memberContext);
+ continue nextMember;
+ }
+ type = type.enclosingType();
+ } while (type != null);
+ // check the member type does not conflict with another sibling member type
+ for (int j = 0; j < i; j++) {
+ if (CharOperation
+ .equals(referenceContext.memberTypes[j].name, memberContext.name)) {
+ problemReporter().duplicateNestedType(memberContext);
+ continue nextMember;
+ }
+ }
+
+ ClassScope memberScope = new ClassScope(this, referenceContext.memberTypes[i]);
+ LocalTypeBinding memberBinding =
+ memberScope.buildLocalType(localType, packageBinding);
+ memberBinding.setAsMemberType();
+ memberTypeBindings[count++] = memberBinding;
+ }
+ if (count != size)
+ System.arraycopy(
+ memberTypeBindings,
+ 0,
+ memberTypeBindings = new ReferenceBinding[count],
+ 0,
+ count);
+ }
+ localType.memberTypes = memberTypeBindings;
+ return localType;
+ }
+
+ void buildLocalTypeBinding(SourceTypeBinding enclosingType) {
+ buildLocalType(enclosingType, enclosingType.fPackage);
+ connectTypeHierarchy();
+ buildFieldsAndMethods();
+ referenceContext.binding.verifyMethods(environment().methodVerifier());
+ }
+
+ private void buildMethods() {
+ if (referenceContext.methods == null) {
+ referenceContext.binding.methods = NoMethods;
+ return;
+ }
+
+ // iterate the method declarations to create the bindings
+ AbstractMethodDeclaration[] methods = referenceContext.methods;
+ int size = methods.length;
+ int clinitIndex = -1;
+ for (int i = 0; i < size; i++) {
+ if (methods[i] instanceof Clinit) {
+ clinitIndex = i;
+ break;
+ }
+ }
+ MethodBinding[] methodBindings =
+ new MethodBinding[clinitIndex == -1 ? size : size - 1];
+
+ int count = 0;
+ for (int i = 0; i < size; i++) {
+ if (i != clinitIndex) {
+ MethodScope scope = new MethodScope(this, methods[i], false);
+ MethodBinding methodBinding = scope.createMethod(methods[i]);
+ if (methodBinding != null) // is null if binding could not be created
+ methodBindings[count++] = methodBinding;
+ }
+ }
+ if (count != methodBindings.length)
+ System.arraycopy(
+ methodBindings,
+ 0,
+ methodBindings = new MethodBinding[count],
+ 0,
+ count);
+
+ referenceContext.binding.methods = methodBindings;
+ referenceContext.binding.modifiers |= AccUnresolved;
+ // until methods() is sent
+ if (referenceContext.binding.isLocalType())
+ referenceContext.binding.methods();
+ // fault the types for the local type's methods now since we need them
+ }
+
+ SourceTypeBinding buildType(
+ SourceTypeBinding enclosingType,
+ PackageBinding packageBinding) {
+ // provide the typeDeclaration with needed scopes
+ referenceContext.scope = this;
+ referenceContext.staticInitializerScope =
+ new MethodScope(this, referenceContext, true);
+ referenceContext.initializerScope =
+ new MethodScope(this, referenceContext, false);
+
+ if (enclosingType == null) {
+ char[][] className =
+ CharOperation.arrayConcat(packageBinding.compoundName, referenceContext.name);
+ referenceContext.binding =
+ new SourceTypeBinding(className, packageBinding, this);
+ } else {
+ char[][] className = CharOperation.deepCopy(enclosingType.compoundName);
+ className[className.length - 1] =
+ CharOperation.concat(
+ className[className.length - 1],
+ referenceContext.name,
+ '$');
+ referenceContext.binding =
+ new MemberTypeBinding(className, this, enclosingType);
+ }
+
+ SourceTypeBinding sourceType = referenceContext.binding;
+ sourceType.fPackage.addType(sourceType);
+ checkAndSetModifiers();
+
+ // Look at member types
+ ReferenceBinding[] memberTypeBindings = NoMemberTypes;
+ if (referenceContext.memberTypes != null) {
+ int size = referenceContext.memberTypes.length;
+ memberTypeBindings = new ReferenceBinding[size];
+ int count = 0;
+ nextMember : for (int i = 0; i < size; i++) {
+ TypeDeclaration memberContext = referenceContext.memberTypes[i];
+ if (memberContext.isInterface()
+ && sourceType.isNestedType()
+ && sourceType.isClass()
+ && !sourceType.isStatic()) {
+ problemReporter().nestedClassCannotDeclareInterface(memberContext);
+ continue nextMember;
+ }
+ ReferenceBinding type = sourceType;
+ // check that the member does not conflict with an enclosing type
+ do {
+ if (CharOperation.equals(type.sourceName, memberContext.name)) {
+ problemReporter().hidingEnclosingType(memberContext);
+ continue nextMember;
+ }
+ type = type.enclosingType();
+ } while (type != null);
+ // check that the member type does not conflict with another sibling member type
+ for (int j = 0; j < i; j++) {
+ if (CharOperation
+ .equals(referenceContext.memberTypes[j].name, memberContext.name)) {
+ problemReporter().duplicateNestedType(memberContext);
+ continue nextMember;
+ }
+ }
+
+ ClassScope memberScope = new ClassScope(this, memberContext);
+ memberTypeBindings[count++] = memberScope.buildType(sourceType, packageBinding);
+ }
+ if (count != size)
+ System.arraycopy(
+ memberTypeBindings,
+ 0,
+ memberTypeBindings = new ReferenceBinding[count],
+ 0,
+ count);
+ }
+ sourceType.memberTypes = memberTypeBindings;
+ return sourceType;
+ }
+
+ private void checkAndSetModifiers() {
+ SourceTypeBinding sourceType = referenceContext.binding;
+ int modifiers = sourceType.modifiers;
+ if ((modifiers & AccAlternateModifierProblem) != 0)
+ problemReporter().duplicateModifierForType(sourceType);
+
+ if (sourceType.isMemberType()) {
+ // checks for member types before local types to catch local members
+ if (sourceType.enclosingType().isStrictfp())
+ modifiers |= AccStrictfp;
+ if (sourceType.enclosingType().isDeprecated())
+ modifiers |= AccDeprecatedImplicitly;
+ if (sourceType.enclosingType().isInterface())
+ modifiers |= AccPublic;
+ } else
+ if (sourceType.isLocalType()) {
+ if (sourceType.isAnonymousType())
+ modifiers |= AccFinal;
+ ReferenceContext refContext = methodScope().referenceContext;
+ if (refContext instanceof TypeDeclaration) {
+ ReferenceBinding type = ((TypeDeclaration) refContext).binding;
+ if (type.isStrictfp())
+ modifiers |= AccStrictfp;
+ if (type.isDeprecated())
+ modifiers |= AccDeprecatedImplicitly;
+ } else {
+ MethodBinding method = ((AbstractMethodDeclaration) refContext).binding;
+ if (method.isStrictfp())
+ modifiers |= AccStrictfp;
+ if (method.isDeprecated())
+ modifiers |= AccDeprecatedImplicitly;
+ }
+ }
+
+ // after this point, tests on the 16 bits reserved.
+ int realModifiers = modifiers & AccJustFlag;
+
+ if ((realModifiers & AccInterface) != 0) {
+ // detect abnormal cases for interfaces
+ if (sourceType.isMemberType()) {
+ int unexpectedModifiers =
+ ~(
+ AccPublic
+ | AccPrivate
+ | AccProtected
+ | AccStatic
+ | AccAbstract
+ | AccInterface
+ | AccStrictfp);
+ if ((realModifiers & unexpectedModifiers) != 0)
+ problemReporter().illegalModifierForMemberInterface(sourceType);
+ /*
+ } else if (sourceType.isLocalType()) { //interfaces cannot be defined inside a method
+ int unexpectedModifiers = ~(AccAbstract | AccInterface | AccStrictfp);
+ if ((realModifiers & unexpectedModifiers) != 0)
+ problemReporter().illegalModifierForLocalInterface(sourceType);
+ */
+ } else {
+ int unexpectedModifiers =
+ ~(AccPublic | AccAbstract | AccInterface | AccStrictfp);
+ if ((realModifiers & unexpectedModifiers) != 0)
+ problemReporter().illegalModifierForInterface(sourceType);
+ }
+ modifiers |= AccAbstract;
+ } else {
+ // detect abnormal cases for types
+ if (sourceType.isMemberType()) {
+ // includes member types defined inside local types
+ int unexpectedModifiers =
+ ~(
+ AccPublic
+ | AccPrivate
+ | AccProtected
+ | AccStatic
+ | AccAbstract
+ | AccFinal
+ | AccStrictfp);
+ if ((realModifiers & unexpectedModifiers) != 0)
+ problemReporter().illegalModifierForMemberClass(sourceType);
+ } else
+ if (sourceType.isLocalType()) {
+ int unexpectedModifiers = ~(AccAbstract | AccFinal | AccStrictfp);
+ if ((realModifiers & unexpectedModifiers) != 0)
+ problemReporter().illegalModifierForLocalClass(sourceType);
+ } else {
+ int unexpectedModifiers = ~(AccPublic | AccAbstract | AccFinal | AccStrictfp);
+ if ((realModifiers & unexpectedModifiers) != 0)
+ problemReporter().illegalModifierForClass(sourceType);
+ }
+
+ // check that Final and Abstract are not set together
+ if ((realModifiers & (AccFinal | AccAbstract)) == (AccFinal | AccAbstract))
+ problemReporter().illegalModifierCombinationFinalAbstractForClass(sourceType);
+ }
+
+ if (sourceType.isMemberType()) {
+ // test visibility modifiers inconsistency, isolate the accessors bits
+ if (sourceType.enclosingType().isInterface()) {
+ if ((realModifiers & (AccProtected | AccPrivate)) != 0) {
+ problemReporter().illegalVisibilityModifierForInterfaceMemberType(sourceType);
+
+ // need to keep the less restrictive
+ if ((realModifiers & AccProtected) != 0)
+ modifiers ^= AccProtected;
+ if ((realModifiers & AccPrivate) != 0)
+ modifiers ^= AccPrivate;
+ }
+ } else {
+ int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate);
+ if ((accessorBits & (accessorBits - 1)) > 1) {
+ problemReporter().illegalVisibilityModifierCombinationForMemberType(sourceType);
+
+ // need to keep the less restrictive
+ if ((accessorBits & AccPublic) != 0) {
+ if ((accessorBits & AccProtected) != 0)
+ modifiers ^= AccProtected;
+ if ((accessorBits & AccPrivate) != 0)
+ modifiers ^= AccPrivate;
+ }
+ if ((accessorBits & AccProtected) != 0)
+ if ((accessorBits & AccPrivate) != 0)
+ modifiers ^= AccPrivate;
+ }
+ }
+
+ // static modifier test
+ if ((realModifiers & AccStatic) == 0) {
+ if (sourceType.enclosingType().isInterface())
+ modifiers |= AccStatic;
+ } else {
+ if (!sourceType.enclosingType().isStatic())
+ // error the enclosing type of a static field must be static or a top-level type
+ problemReporter().illegalStaticModifierForMemberType(sourceType);
+ }
+ }
+
+ sourceType.modifiers = modifiers;
+ }
+
+ /* This method checks the modifiers of a field.
+ *
+ * 9.3 & 8.3
+ * Need to integrate the check for the final modifiers for nested types
+ *
+ * Note : A scope is accessible by : fieldBinding.declaringClass.scope
+ */
+
+ private void checkAndSetModifiersForField(
+ FieldBinding fieldBinding,
+ FieldDeclaration fieldDecl) {
+ int modifiers = fieldBinding.modifiers;
+ if ((modifiers & AccAlternateModifierProblem) != 0)
+ problemReporter().duplicateModifierForField(
+ fieldBinding.declaringClass,
+ fieldDecl);
+
+ if (fieldBinding.declaringClass.isInterface()) {
+ int expectedValue = AccPublic | AccStatic | AccFinal;
+ // set the modifiers
+ modifiers |= expectedValue;
+
+ // and then check that they are the only ones
+ if ((modifiers & AccJustFlag) != expectedValue)
+ problemReporter().illegalModifierForInterfaceField(
+ fieldBinding.declaringClass,
+ fieldDecl);
+ fieldBinding.modifiers = modifiers;
+ return;
+ }
+
+ // after this point, tests on the 16 bits reserved.
+ int realModifiers = modifiers & AccJustFlag;
+ int unexpectedModifiers =
+ ~(
+ AccPublic
+ | AccPrivate
+ | AccProtected
+ | AccFinal
+ | AccStatic
+ | AccTransient
+ | AccVolatile);
+ if ((realModifiers & unexpectedModifiers) != 0)
+ problemReporter().illegalModifierForField(
+ fieldBinding.declaringClass,
+ fieldDecl);
+
+ int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate);
+ if ((accessorBits & (accessorBits - 1)) > 1) {
+ problemReporter().illegalVisibilityModifierCombinationForField(
+ fieldBinding.declaringClass,
+ fieldDecl);
+
+ // need to keep the less restrictive
+ if ((accessorBits & AccPublic) != 0) {
+ if ((accessorBits & AccProtected) != 0)
+ modifiers ^= AccProtected;
+ if ((accessorBits & AccPrivate) != 0)
+ modifiers ^= AccPrivate;
+ }
+ if ((accessorBits & AccProtected) != 0)
+ if ((accessorBits & AccPrivate) != 0)
+ modifiers ^= AccPrivate;
+ }
+
+ if ((realModifiers & (AccFinal | AccVolatile)) == (AccFinal | AccVolatile))
+ problemReporter().illegalModifierCombinationFinalVolatileForField(
+ fieldBinding.declaringClass,
+ fieldDecl);
+
+ fieldBinding.modifiers = modifiers;
+ }
+
+ private void checkForInheritedMemberTypes(SourceTypeBinding sourceType) {
+ // search up the hierarchy of the sourceType to see if any superType defines a member type
+ // when no member types are defined, tag the sourceType & each superType with the HasNoMemberTypes bit
+ ReferenceBinding currentType = sourceType;
+ ReferenceBinding[][] interfacesToVisit = null;
+ int lastPosition = -1;
+ do {
+ if ((currentType.tagBits & HasNoMemberTypes) != 0)
+ break; // already know it has no inherited member types, can stop looking up
+ if (currentType.memberTypes() != NoMemberTypes)
+ return; // has member types
+ ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (interfacesToVisit == null)
+ interfacesToVisit = new ReferenceBinding[5][];
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(
+ interfacesToVisit,
+ 0,
+ interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
+ 0,
+ lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+ } while ((currentType = currentType.superclass()) != null);
+
+ boolean hasMembers = false;
+ if (interfacesToVisit != null) {
+ done : for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++) {
+ ReferenceBinding anInterface = interfaces[j];
+ if ((anInterface.tagBits & InterfaceVisited) == 0) {
+ // if interface as not already been visited
+ anInterface.tagBits |= InterfaceVisited;
+ if ((anInterface.tagBits & HasNoMemberTypes) != 0)
+ continue; // already know it has no inherited member types
+ if (anInterface.memberTypes() != NoMemberTypes) {
+ hasMembers = true;
+ break done;
+ }
+
+ ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(
+ interfacesToVisit,
+ 0,
+ interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
+ 0,
+ lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++) {
+ interfaces[j].tagBits &= ~InterfaceVisited;
+ if (!hasMembers)
+ interfaces[j].tagBits |= HasNoMemberTypes;
+ }
+ }
+ }
+
+ if (!hasMembers) {
+ currentType = sourceType;
+ do {
+ currentType.tagBits |= HasNoMemberTypes;
+ } while ((currentType = currentType.superclass()) != null);
+ }
+ }
+
+ private void connectMemberTypes() {
+ SourceTypeBinding sourceType = referenceContext.binding;
+ if (sourceType.memberTypes != NoMemberTypes)
+ for (int i = 0, size = sourceType.memberTypes.length; i < size; i++)
+ ((SourceTypeBinding) sourceType.memberTypes[i]).scope.connectTypeHierarchy();
+ }
+
+ /*
+ Our current belief based on available JCK tests is:
+ inherited member types are visible as a potential superclass.
+ inherited interfaces are not visible when defining a superinterface.
+
+ Error recovery story:
+ ensure the superclass is set to java.lang.Object if a problem is detected
+ resolving the superclass.
+
+ Answer false if an error was reported against the sourceType.
+ */
+
+ private boolean connectSuperclass() {
+ SourceTypeBinding sourceType = referenceContext.binding;
+ if (referenceContext.superclass == null) {
+ if (isJavaLangObject(sourceType))
+ return true;
+ sourceType.superclass = getJavaLangObject();
+ compilationUnitScope().addTypeReference(sourceType.superclass);
+ return !detectCycle(sourceType, sourceType.superclass, null);
+ // ensure Object is initialized if it comes from a source file
+ }
+
+ ReferenceBinding superclass = findSupertype(referenceContext.superclass);
+ if (superclass != null) { // is null if a cycle was detected cycle
+ if (!superclass.isValidBinding()) {
+ problemReporter().invalidSuperclass(
+ sourceType,
+ referenceContext.superclass,
+ superclass);
+ } else
+ if (superclass.isInterface()) {
+ problemReporter().superclassMustBeAClass(
+ sourceType,
+ referenceContext.superclass,
+ superclass);
+ } else
+ if (superclass.isFinal()) {
+ problemReporter().classExtendFinalClass(
+ sourceType,
+ referenceContext.superclass,
+ superclass);
+ } else
+ if (isJavaLangObject(sourceType)) {
+ // can only happen if Object extends another type... will never happen unless we're testing for it.
+ sourceType.tagBits |= HierarchyHasProblems;
+ sourceType.superclass = null;
+ return true;
+ } else {
+ // only want to reach here when no errors are reported
+ referenceContext.superclass.binding = superclass;
+ sourceType.superclass = superclass;
+ return true;
+ }
+ }
+
+ sourceType.tagBits |= HierarchyHasProblems;
+ if (!isJavaLangObject(sourceType)) {
+ sourceType.superclass = getJavaLangObject();
+ if ((sourceType.superclass.tagBits & BeginHierarchyCheck) == 0)
+ detectCycle(sourceType, sourceType.superclass, null);
+ // ensure Object is initialized if it comes from a source file
+ }
+ return false; // reported some error against the source type
+ }
+
+ /*
+ Our current belief based on available JCK 1.3 tests is:
+ inherited member types are visible as a potential superclass.
+ inherited interfaces are visible when defining a superinterface.
+
+ Error recovery story:
+ ensure the superinterfaces contain only valid visible interfaces.
+
+ Answer false if an error was reported against the sourceType.
+ */
+
+ private boolean connectSuperInterfaces() {
+ SourceTypeBinding sourceType = referenceContext.binding;
+ sourceType.superInterfaces = NoSuperInterfaces;
+ if (referenceContext.superInterfaces == null)
+ return true;
+
+ boolean noProblems = true;
+ int length = referenceContext.superInterfaces.length;
+ ReferenceBinding[] interfaceBindings = new ReferenceBinding[length];
+ int count = 0;
+ nextInterface : for (int i = 0; i < length; i++) {
+ ReferenceBinding superInterface =
+ findSupertype(referenceContext.superInterfaces[i]);
+ if (superInterface == null) { // detected cycle
+ noProblems = false;
+ continue nextInterface;
+ }
+ if (!superInterface.isValidBinding()) {
+ problemReporter().invalidSuperinterface(
+ sourceType,
+ referenceContext.superInterfaces[i],
+ superInterface);
+ sourceType.tagBits |= HierarchyHasProblems;
+ noProblems = false;
+ continue nextInterface;
+ }
+
+ // Check for a duplicate interface once the name is resolved, otherwise we may be confused (ie : a.b.I and c.d.I)
+ for (int k = 0; k < count; k++) {
+ if (interfaceBindings[k] == superInterface) {
+ // should this be treated as a warning?
+ problemReporter().duplicateSuperinterface(
+ sourceType,
+ referenceContext,
+ superInterface);
+ continue nextInterface;
+ }
+ }
+ if (superInterface.isClass()) {
+ problemReporter().superinterfaceMustBeAnInterface(
+ sourceType,
+ referenceContext,
+ superInterface);
+ sourceType.tagBits |= HierarchyHasProblems;
+ noProblems = false;
+ continue nextInterface;
+ }
+ referenceContext.superInterfaces[i].binding = superInterface;
+ // only want to reach here when no errors are reported
+ interfaceBindings[count++] = superInterface;
+ }
+
+ // hold onto all correctly resolved superinterfaces
+ if (count > 0) {
+ if (count != length)
+ System.arraycopy(
+ interfaceBindings,
+ 0,
+ interfaceBindings = new ReferenceBinding[count],
+ 0,
+ count);
+ sourceType.superInterfaces = interfaceBindings;
+ }
+ return noProblems;
+ }
+
+ void connectTypeHierarchy() {
+ SourceTypeBinding sourceType = referenceContext.binding;
+ if ((sourceType.tagBits & BeginHierarchyCheck) == 0) {
+ boolean noProblems = true;
+ sourceType.tagBits |= BeginHierarchyCheck;
+ if (sourceType.isClass())
+ noProblems &= connectSuperclass();
+ noProblems &= connectSuperInterfaces();
+ sourceType.tagBits |= EndHierarchyCheck;
+ if (noProblems && sourceType.isHierarchyInconsistent())
+ problemReporter().hierarchyHasProblems(sourceType);
+ }
+ connectMemberTypes();
+ checkForInheritedMemberTypes(sourceType);
+ }
+
+ private void connectTypeHierarchyWithoutMembers() {
+ // must ensure the imports are resolved
+ if (parent instanceof CompilationUnitScope) {
+ if (((CompilationUnitScope) parent).imports == null)
+ ((CompilationUnitScope) parent).checkAndSetImports();
+ } else
+ if (parent instanceof ClassScope) {
+ // ensure that the enclosing type has already been checked
+ ((ClassScope) parent).connectTypeHierarchyWithoutMembers();
+ }
+
+ // double check that the hierarchy search has not already begun...
+ SourceTypeBinding sourceType = referenceContext.binding;
+ if ((sourceType.tagBits & BeginHierarchyCheck) != 0)
+ return;
+
+ boolean noProblems = true;
+ sourceType.tagBits |= BeginHierarchyCheck;
+ if (sourceType.isClass())
+ noProblems &= connectSuperclass();
+ noProblems &= connectSuperInterfaces();
+ sourceType.tagBits |= EndHierarchyCheck;
+ if (noProblems && sourceType.isHierarchyInconsistent())
+ problemReporter().hierarchyHasProblems(sourceType);
+ }
+
+ // Answer whether a cycle was found between the sourceType & the superType
+
+ private boolean detectCycle(
+ SourceTypeBinding sourceType,
+ ReferenceBinding superType,
+ TypeReference reference) {
+ if (sourceType == superType) {
+ problemReporter().hierarchyCircularity(sourceType, superType, reference);
+ sourceType.tagBits |= HierarchyHasProblems;
+ return true;
+ }
+
+ if (superType.isBinaryBinding()) {
+ // force its superclass & superinterfaces to be found... 2 possibilities exist - the source type is included in the hierarchy of:
+ // - a binary type... this case MUST be caught & reported here
+ // - another source type... this case is reported against the other source type
+ boolean hasCycle = false;
+ if (superType.superclass() != null) {
+ if (sourceType == superType.superclass()) {
+ problemReporter().hierarchyCircularity(sourceType, superType, reference);
+ sourceType.tagBits |= HierarchyHasProblems;
+ superType.tagBits |= HierarchyHasProblems;
+ return true;
+ }
+ hasCycle |= detectCycle(sourceType, superType.superclass(), reference);
+ if ((superType.superclass().tagBits & HierarchyHasProblems) != 0) {
+ sourceType.tagBits |= HierarchyHasProblems;
+ superType.tagBits |= HierarchyHasProblems; // propagate down the hierarchy
+ }
+ }
+
+ ReferenceBinding[] itsInterfaces = superType.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ for (int i = 0, length = itsInterfaces.length; i < length; i++) {
+ ReferenceBinding anInterface = itsInterfaces[i];
+ if (sourceType == anInterface) {
+ problemReporter().hierarchyCircularity(sourceType, superType, reference);
+ sourceType.tagBits |= HierarchyHasProblems;
+ superType.tagBits |= HierarchyHasProblems;
+ return true;
+ }
+ hasCycle |= detectCycle(sourceType, anInterface, reference);
+ if ((anInterface.tagBits & HierarchyHasProblems) != 0) {
+ sourceType.tagBits |= HierarchyHasProblems;
+ superType.tagBits |= HierarchyHasProblems;
+ }
+ }
+ }
+ return hasCycle;
+ }
+
+ if ((superType.tagBits & EndHierarchyCheck) == 0
+ && (superType.tagBits & BeginHierarchyCheck) != 0) {
+ problemReporter().hierarchyCircularity(sourceType, superType, reference);
+ sourceType.tagBits |= HierarchyHasProblems;
+ superType.tagBits |= HierarchyHasProblems;
+ return true;
+ }
+ if ((superType.tagBits & BeginHierarchyCheck) == 0)
+ // ensure if this is a source superclass that it has already been checked
+ ((SourceTypeBinding) superType).scope.connectTypeHierarchyWithoutMembers();
+ if ((superType.tagBits & HierarchyHasProblems) != 0)
+ sourceType.tagBits |= HierarchyHasProblems;
+ return false;
+ }
+
+ private ReferenceBinding findSupertype(TypeReference typeReference) {
+ typeReference.aboutToResolve(this);
+ // allows us to trap completion & selection nodes
+ char[][] compoundName = typeReference.getTypeName();
+ SourceTypeBinding sourceType = referenceContext.binding;
+ int size = compoundName.length;
+ int n = 1;
+ ReferenceBinding superType;
+
+ // resolve the first name of the compoundName
+ if (CharOperation.equals(compoundName[0], sourceType.sourceName)) {
+ superType = sourceType;
+ // match against the sourceType even though nested members cannot be supertypes
+ } else {
+ Binding typeOrPackage =
+ parent.getTypeOrPackage(compoundName[0], TYPE | PACKAGE);
+ if (typeOrPackage == null || !typeOrPackage.isValidBinding()) {
+ compilationUnitScope().addNamespaceReference(
+ new ProblemPackageBinding(compoundName[0], NotFound));
+ // record package ref
+ return new ProblemReferenceBinding(
+ compoundName[0],
+ typeOrPackage == null ? NotFound : typeOrPackage.problemId());
+ }
+ boolean checkVisibility = false;
+ for (; n < size; n++) {
+ if (!(typeOrPackage instanceof PackageBinding))
+ break;
+
+ PackageBinding packageBinding = (PackageBinding) typeOrPackage;
+ compilationUnitScope().addNamespaceReference(packageBinding);
+ typeOrPackage = packageBinding.getTypeOrPackage(compoundName[n]);
+ if (typeOrPackage == null || !typeOrPackage.isValidBinding())
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, n + 1),
+ typeOrPackage == null ? NotFound : typeOrPackage.problemId());
+ checkVisibility = true;
+ }
+
+ // convert to a ReferenceBinding
+ if (typeOrPackage instanceof PackageBinding)
+ // error, the compoundName is a packageName
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, n),
+ NotFound);
+ superType = (ReferenceBinding) typeOrPackage;
+ compilationUnitScope().addTypeReference(superType);
+
+ if (checkVisibility
+ && n == size) {
+ // if we're finished and know the final superinterface then check visibility
+ SourceTypeBinding enclosingSourceType = enclosingSourceType();
+ if (enclosingSourceType == null
+ ? !superType.canBeSeenBy(sourceType.fPackage)
+ : !superType.canBeSeenBy(sourceType, enclosingSourceType))
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, n),
+ NotVisible);
+ }
+ }
+
+ // at this point we know we have a type but we have to look for cycles
+ while (true) {
+ // must detect cycles & force connection up the hierarchy... also handle cycles with binary types.
+ // must be guaranteed that the superType knows its entire hierarchy
+ if (detectCycle(sourceType, superType, typeReference))
+ return null; // cycle error was already reported
+
+ if (n >= size)
+ break;
+
+ // retrieve the next member type
+ char[] typeName = compoundName[n++];
+ superType = findMemberType(typeName, superType);
+ if (superType == null)
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, n),
+ NotFound);
+ if (!superType.isValidBinding()) {
+ superType.compoundName = CharOperation.subarray(compoundName, 0, n);
+ return superType;
+ }
+ }
+ return superType;
+ }
+
+ /* Answer the problem reporter to use for raising new problems.
+ *
+ * Note that as a side-effect, this updates the current reference context
+ * (unit, type or method) in case the problem handler decides it is necessary
+ * to abort.
+ */
+
+ public ProblemReporter problemReporter() {
+ MethodScope outerMethodScope;
+ if ((outerMethodScope = outerMostMethodScope()) == null) {
+ ProblemReporter problemReporter = referenceCompilationUnit().problemReporter;
+ problemReporter.referenceContext = referenceContext;
+ return problemReporter;
+ } else {
+ return outerMethodScope.problemReporter();
+ }
+ }
+
+ /* Answer the reference type of this scope.
+ *
+ * i.e. the nearest enclosing type of this scope.
+ */
+
+ public TypeDeclaration referenceType() {
+ return referenceContext;
+ }
+
+ public String toString() {
+ if (referenceContext != null)
+ return "--- Class Scope ---\n\n" + referenceContext.binding.toString();
+ else
+ return "--- Class Scope ---\n\n Binding not initialized";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java
new file mode 100644
index 0000000000..80f9e7f4ee
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java
@@ -0,0 +1,503 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class CompilationUnitScope extends Scope {
+ public LookupEnvironment environment;
+ public CompilationUnitDeclaration referenceContext;
+ public char[][] currentPackageName;
+ public PackageBinding fPackage;
+ public ImportBinding[] imports;
+ public SourceTypeBinding[] topLevelTypes;
+
+ private ObjectVector namespaceDependencies;
+ private ObjectVector typeDependencies;
+ public CompilationUnitScope(
+ CompilationUnitDeclaration unit,
+ LookupEnvironment environment) {
+ super(COMPILATION_UNIT_SCOPE, null);
+ this.environment = environment;
+ this.referenceContext = unit;
+ unit.scope = this;
+ this.currentPackageName =
+ unit.currentPackage == null ? NoCharChar : unit.currentPackage.tokens;
+
+ if (environment.options.produceReferenceInfo) {
+ this.namespaceDependencies = new ObjectVector();
+ this.typeDependencies = new ObjectVector();
+ } else {
+ this.namespaceDependencies = null;
+ // used to test if dependencies should be recorded
+ this.typeDependencies = null;
+ }
+ }
+
+ public void addNamespaceReference(PackageBinding packageBinding) {
+ if (namespaceDependencies == null)
+ return; // we're not recording dependencies
+
+ if (packageBinding.isValidBinding()) {
+ if (!namespaceDependencies.contains(packageBinding))
+ namespaceDependencies.add(packageBinding);
+ } else {
+ for (int i = namespaceDependencies.size; --i >= 0;) {
+ PackageBinding next = (PackageBinding) namespaceDependencies.elementAt(i);
+ if (!next.isValidBinding()
+ && CharOperation.equals(packageBinding.compoundName, next.compoundName))
+ return;
+ }
+ namespaceDependencies.add(packageBinding);
+ }
+ }
+
+ public void addTypeReference(TypeBinding type) {
+ if (typeDependencies == null)
+ return; // we're not recording dependencies
+
+ if (type.isArrayType())
+ type = ((ArrayBinding) type).leafComponentType;
+ if (!type.isBaseType()) {
+ ReferenceBinding actualType = (ReferenceBinding) type;
+ if (!typeDependencies.contains(actualType))
+ typeDependencies.add(actualType);
+ }
+ }
+
+ public void addTypeReferences(TypeBinding[] types) {
+ if (typeDependencies == null)
+ return; // we're not recording dependencies
+ if (types == null || types == NoExceptions)
+ return;
+
+ for (int i = 0, max = types.length; i < max; i++)
+ addTypeReference(types[i]);
+ }
+
+ void buildFieldsAndMethods() {
+ for (int i = 0, length = topLevelTypes.length; i < length; i++)
+ topLevelTypes[i].scope.buildFieldsAndMethods();
+ }
+
+ void buildTypeBindings() {
+ topLevelTypes = new SourceTypeBinding[0];
+ // want it initialized if the package cannot be resolved
+ if (currentPackageName == NoCharChar) {
+ if ((fPackage = environment.defaultPackage) == null) {
+ problemReporter().mustSpecifyPackage(referenceContext);
+ return;
+ }
+ } else {
+ if ((fPackage = environment.createPackage(currentPackageName)) == null) {
+ problemReporter().packageCollidesWithType(referenceContext);
+ return;
+ }
+ }
+
+ // Skip typeDeclarations which know of previously reported errors
+ TypeDeclaration[] types = referenceContext.types;
+ int typeLength = (types == null) ? 0 : types.length;
+ topLevelTypes = new SourceTypeBinding[typeLength];
+ int count = 0;
+ nextType : for (int i = 0; i < typeLength; i++) {
+ TypeDeclaration typeDecl = types[i];
+ ReferenceBinding typeBinding = fPackage.getType0(typeDecl.name);
+ if (typeBinding != null
+ && !(typeBinding instanceof UnresolvedReferenceBinding)) {
+ // if a type exists, it must be a valid type - cannot be a NotFound problem type
+ // unless its an unresolved type which is now being defined
+ problemReporter().duplicateTypes(referenceContext, typeDecl);
+ continue nextType;
+ }
+ if (currentPackageName != NoCharChar) {
+ if ((fPackage.getPackage0(typeDecl.name)) != null
+ || environment.isPackage(currentPackageName, typeDecl.name)) {
+ // if a package exists, it must be a valid package - cannot be a NotFound problem package
+ problemReporter().typeCollidesWithPackage(referenceContext, typeDecl);
+ continue nextType;
+ }
+ }
+
+ if ((typeDecl.modifiers & AccPublic) != 0) {
+ if (!CharOperation.equals(referenceContext.getMainTypeName(), typeDecl.name)) {
+ problemReporter().publicClassMustMatchFileName(referenceContext, typeDecl);
+ continue nextType;
+ }
+ }
+
+ ClassScope child = new ClassScope(this, typeDecl);
+ topLevelTypes[count++] = child.buildType(null, fPackage);
+ }
+
+ // shrink topLevelTypes... only happens if an error was reported
+ if (count != topLevelTypes.length)
+ System.arraycopy(
+ topLevelTypes,
+ 0,
+ topLevelTypes = new SourceTypeBinding[count],
+ 0,
+ count);
+ }
+
+ void checkAndSetImports() {
+ // initialize the default imports if necessary... share the default java.lang.* import
+ if (environment.defaultImports == null) {
+ Binding importBinding = environment.getTopLevelPackage(JAVA);
+ if (importBinding != null)
+ importBinding = ((PackageBinding) importBinding).getTypeOrPackage(JAVA_LANG[1]);
+
+ // abort if java.lang cannot be found...
+ if (importBinding == null || !importBinding.isValidBinding())
+ problemReporter().isClassPathCorrect(
+ JAVA_LANG_OBJECT,
+ referenceCompilationUnit());
+
+ environment.defaultImports =
+ new ImportBinding[] { new ImportBinding(JAVA_LANG, true, importBinding)};
+ }
+ if (referenceContext.imports == null) {
+ imports = environment.defaultImports;
+ return;
+ }
+
+ // allocate the import array, add java.lang.* by default
+ int numberOfStatements = referenceContext.imports.length;
+ int numberOfImports = numberOfStatements + 1;
+ for (int i = 0; i < numberOfStatements; i++) {
+ ImportReference importReference = referenceContext.imports[i];
+ if (importReference.onDemand
+ && CharOperation.equals(JAVA_LANG, importReference.tokens)) {
+ numberOfImports--;
+ break;
+ }
+ }
+ ImportBinding[] resolvedImports = new ImportBinding[numberOfImports];
+ resolvedImports[0] = environment.defaultImports[0];
+ int index = 1;
+
+ nextImport : for (int i = 0; i < numberOfStatements; i++) {
+ ImportReference importReference = referenceContext.imports[i];
+ char[][] compoundName = importReference.tokens;
+
+ // skip duplicates or imports of the current package
+ for (int j = 0; j < index; j++)
+ if (resolvedImports[j].onDemand == importReference.onDemand)
+ if (CharOperation.equals(compoundName, resolvedImports[j].compoundName))
+ continue nextImport;
+ if (importReference.onDemand == true)
+ if (CharOperation.equals(compoundName, currentPackageName))
+ continue nextImport;
+
+ if (importReference.onDemand) {
+ Binding importBinding = findOnDemandImport(compoundName);
+ if (!importBinding.isValidBinding())
+ continue nextImport; // we report all problems in faultInImports()
+ resolvedImports[index++] = new ImportBinding(compoundName, true, importBinding);
+ } else {
+ resolvedImports[index++] = new ImportBinding(compoundName, false, null);
+ }
+ }
+
+ // shrink resolvedImports... only happens if an error was reported
+ if (resolvedImports.length > index)
+ System.arraycopy(
+ resolvedImports,
+ 0,
+ resolvedImports = new ImportBinding[index],
+ 0,
+ index);
+ imports = resolvedImports;
+ }
+
+ void connectTypeHierarchy() {
+ for (int i = 0, length = topLevelTypes.length; i < length; i++)
+ topLevelTypes[i].scope.connectTypeHierarchy();
+ }
+
+ void faultInImports() {
+ if (referenceContext.imports == null)
+ return;
+
+ // collect the top level type names if a single type import exists
+ int numberOfStatements = referenceContext.imports.length;
+ HashtableOfType typesBySimpleNames = null;
+ for (int i = 0; i < numberOfStatements; i++) {
+ if (!referenceContext.imports[i].onDemand) {
+ typesBySimpleNames =
+ new HashtableOfType(topLevelTypes.length + numberOfStatements);
+ for (int j = 0, length = topLevelTypes.length; j < length; j++)
+ typesBySimpleNames.put(topLevelTypes[j].sourceName, topLevelTypes[j]);
+ break;
+ }
+ }
+
+ // allocate the import array, add java.lang.* by default
+ int numberOfImports = numberOfStatements + 1;
+ for (int i = 0; i < numberOfStatements; i++) {
+ ImportReference importReference = referenceContext.imports[i];
+ if (importReference.onDemand
+ && CharOperation.equals(JAVA_LANG, importReference.tokens)) {
+ numberOfImports--;
+ break;
+ }
+ }
+ ImportBinding[] resolvedImports = new ImportBinding[numberOfImports];
+ resolvedImports[0] = environment.defaultImports[0];
+ int index = 1;
+
+ nextImport : for (int i = 0; i < numberOfStatements; i++) {
+ ImportReference importReference = referenceContext.imports[i];
+ char[][] compoundName = importReference.tokens;
+
+ // skip duplicates or imports of the current package
+ for (int j = 0; j < index; j++)
+ if (resolvedImports[j].onDemand == importReference.onDemand)
+ if (CharOperation.equals(compoundName, resolvedImports[j].compoundName))
+ continue nextImport;
+ if (importReference.onDemand == true)
+ if (CharOperation.equals(compoundName, currentPackageName))
+ continue nextImport;
+
+ if (importReference.onDemand) {
+ Binding importBinding = findOnDemandImport(compoundName);
+ if (!importBinding.isValidBinding()) {
+ problemReporter().importProblem(importReference, importBinding);
+ continue nextImport;
+ }
+ resolvedImports[index++] = new ImportBinding(compoundName, true, importBinding);
+ } else {
+ Binding typeBinding = findSingleTypeImport(compoundName);
+ if (!typeBinding.isValidBinding()) {
+ problemReporter().importProblem(importReference, typeBinding);
+ continue nextImport;
+ }
+ if (typeBinding instanceof PackageBinding) {
+ problemReporter().cannotImportPackage(importReference);
+ continue nextImport;
+ }
+ ReferenceBinding existingType =
+ typesBySimpleNames.get(compoundName[compoundName.length - 1]);
+ if (existingType != null) {
+ // duplicate test above should have caught this case, but make sure
+ if (existingType == typeBinding)
+ continue nextImport;
+
+ // either the type collides with a top level type or another imported type
+ for (int j = 0, length = topLevelTypes.length; j < length; j++) {
+ if (CharOperation
+ .equals(topLevelTypes[j].sourceName, existingType.sourceName)) {
+ problemReporter().conflictingImport(importReference);
+ continue nextImport;
+ }
+ }
+ problemReporter().duplicateImport(importReference);
+ continue nextImport;
+ }
+ resolvedImports[index++] = new ImportBinding(compoundName, false, typeBinding);
+ typesBySimpleNames.put(
+ compoundName[compoundName.length - 1],
+ (ReferenceBinding) typeBinding);
+ }
+ }
+
+ // shrink resolvedImports... only happens if an error was reported
+ if (resolvedImports.length > index)
+ System.arraycopy(
+ resolvedImports,
+ 0,
+ resolvedImports = new ImportBinding[index],
+ 0,
+ index);
+ imports = resolvedImports;
+ }
+
+ public void faultInTypes() {
+ faultInImports();
+
+ for (int i = 0, length = topLevelTypes.length; i < length; i++)
+ topLevelTypes[i].faultInTypesForFieldsAndMethods();
+ }
+
+ private Binding findOnDemandImport(char[][] compoundName) {
+ Binding binding = environment.getPackage0(compoundName[0]);
+ if (binding == null) {
+ if (environment.isPackage(null, compoundName[0]))
+ binding = environment.getTopLevelPackage(compoundName[0]);
+ else // hold onto a problem package since a real one will never be created
+ addNamespaceReference(new ProblemPackageBinding(compoundName[0], NotFound));
+ } else {
+ if (binding == environment.theNotFoundPackage)
+ binding = null; // forget the NotFound package
+ }
+ int i = 1;
+ int length = compoundName.length;
+ foundNothingOrType : if (binding != null) {
+ PackageBinding packageBinding = (PackageBinding) binding;
+ addNamespaceReference(packageBinding);
+
+ while (i < length) {
+ binding = packageBinding.getTypeOrPackage(compoundName[i++]);
+ if (binding == null || !binding.isValidBinding()) {
+ binding = null;
+ break foundNothingOrType;
+ }
+ if (!(binding instanceof PackageBinding))
+ break foundNothingOrType;
+
+ packageBinding = (PackageBinding) binding;
+ addNamespaceReference(packageBinding);
+ }
+ return packageBinding;
+ }
+
+ ReferenceBinding type;
+ if (binding == null) {
+ if (environment.defaultPackage == null)
+ return new ProblemReferenceBinding(compoundName, NotFound);
+ type =
+ findType(
+ compoundName[0],
+ environment.defaultPackage,
+ environment.defaultPackage);
+ if (type == null || !type.isValidBinding())
+ return new ProblemReferenceBinding(compoundName, NotFound);
+ i = 1; // reset to look for member types inside the default package type
+ } else {
+ type = (ReferenceBinding) binding;
+ }
+
+ for (; i < length; i++) {
+ addTypeReference(type);
+ // does not look for inherited member types on purpose
+ if ((type = type.getMemberType(compoundName[i])) == null)
+ return new ProblemReferenceBinding(compoundName, NotFound);
+ }
+ addTypeReference(type);
+ if (!type.canBeSeenBy(fPackage))
+ return new ProblemReferenceBinding(compoundName, NotVisible);
+ return type;
+ }
+
+ private Binding findSingleTypeImport(char[][] compoundName) {
+ if (compoundName.length == 1) {
+ // the name cannot be a package
+ if (environment.defaultPackage == null)
+ return new ProblemReferenceBinding(compoundName, NotFound);
+ ReferenceBinding typeBinding =
+ findType(compoundName[0], environment.defaultPackage, fPackage);
+ if (typeBinding == null)
+ return new ProblemReferenceBinding(compoundName, NotFound);
+ else
+ return typeBinding;
+ }
+ return findOnDemandImport(compoundName);
+ }
+
+ /* Answer the problem reporter to use for raising new problems.
+ *
+ * Note that as a side-effect, this updates the current reference context
+ * (unit, type or method) in case the problem handler decides it is necessary
+ * to abort.
+ */
+
+ public ProblemReporter problemReporter() {
+ ProblemReporter problemReporter = referenceContext.problemReporter;
+ problemReporter.referenceContext = referenceContext;
+ return problemReporter;
+ }
+
+ Binding resolveSingleTypeImport(ImportBinding importBinding) {
+ if (importBinding.resolvedImport == null) {
+ importBinding.resolvedImport = findSingleTypeImport(importBinding.compoundName);
+ if (!importBinding.resolvedImport.isValidBinding()
+ || importBinding.resolvedImport instanceof PackageBinding) {
+ ImportBinding[] newImports = new ImportBinding[imports.length - 1];
+ for (int i = 0, n = 0, max = imports.length; i < max; i++)
+ if (imports[i] != importBinding)
+ newImports[n++] = imports[i];
+ imports = newImports;
+ return null;
+ }
+ }
+ return importBinding.resolvedImport;
+ }
+
+ public void storeDependencyInfo() {
+ for (int i = 0;
+ i < typeDependencies.size;
+ i++) { // grows as more types are added
+ // add all the supertypes & associated packages
+ ReferenceBinding type = (ReferenceBinding) typeDependencies.elementAt(i);
+
+ addNamespaceReference(type.fPackage);
+ // is this necessary? If so what about a & a.b from a.b.c?
+ if (type.enclosingType() != null)
+ addTypeReference(type.enclosingType());
+ if (type.superclass() != null)
+ addTypeReference(type.superclass());
+ ReferenceBinding[] interfaces = type.superInterfaces();
+ for (int j = 0, length = interfaces.length; j < length; j++)
+ addTypeReference(interfaces[j]);
+ }
+
+ int length = namespaceDependencies.size;
+ char[][] namespaceNames = new char[length][];
+ for (int i = 0; i < length; i++)
+ namespaceNames[i] =
+ ((PackageBinding) namespaceDependencies.elementAt(i)).readableName();
+ referenceContext.compilationResult.namespaceDependencies = namespaceNames;
+
+ length = typeDependencies.size;
+ int toplevelTypeCount = 0;
+ for (int i = 0; i < length; i++)
+ if (!((ReferenceBinding) typeDependencies.elementAt(i)).isNestedType())
+ toplevelTypeCount++;
+ char[][] fileNames = new char[toplevelTypeCount][];
+ for (int i = 0; i < length; i++)
+ if (!((ReferenceBinding) typeDependencies.elementAt(i)).isNestedType())
+ fileNames[--toplevelTypeCount] =
+ ((ReferenceBinding) typeDependencies.elementAt(i)).getFileName();
+
+ // eliminate duplicates
+ int unique = 0;
+ char[] ownFileName = referenceContext.getFileName();
+ next : for (int i = 0, l = fileNames.length; i < l; i++) {
+ char[] fileName = fileNames[i];
+ if (CharOperation.equals(fileName, ownFileName)) {
+ fileNames[i] = null;
+ continue next;
+ }
+ for (int j = i + 1; j < l; j++) {
+ if (CharOperation.equals(fileName, fileNames[j])) {
+ fileNames[i] = null;
+ continue next;
+ }
+ }
+ unique++;
+ }
+ if (unique < fileNames.length) {
+ char[][] uniqueFileNames = new char[unique][];
+ for (int i = fileNames.length; --i >= 0;)
+ if (fileNames[i] != null)
+ uniqueFileNames[--unique] = fileNames[i];
+ fileNames = uniqueFileNames;
+ }
+ referenceContext.compilationResult.fileDependencies = fileNames;
+ }
+
+ public String toString() {
+ return "--- CompilationUnit Scope : "
+ + new String(referenceContext.getFileName());
+ }
+
+ public void verifyMethods(MethodVerifier verifier) {
+ for (int i = 0, length = topLevelTypes.length; i < length; i++)
+ topLevelTypes[i].verifyMethods(verifier);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilerModifiers.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilerModifiers.java
new file mode 100644
index 0000000000..5666c70982
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilerModifiers.java
@@ -0,0 +1,29 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.classfmt.*;
+
+public interface CompilerModifiers
+ extends ClassFileConstants { // modifier constant
+ // those constants are depending upon ClassFileConstants (relying that classfiles only use the 16 lower bits)
+ final int AccDefault = 0;
+ final int AccJustFlag = 0xFFFF;
+ final int AccCatchesExceptions = 0x10000;
+ final int AccThrowsExceptions = 0x20000;
+ final int AccProblem = 0x40000;
+ final int AccFromClassFile = 0x80000;
+ final int AccIsConstantValue = 0x80000;
+ final int AccDefaultAbstract = 0x80000;
+ final int AccDeprecatedImplicitly = 0x200000;
+ // ie. is deprecated itself or contained by a deprecated type
+ final int AccAlternateModifierProblem = 0x400000;
+ final int AccModifierProblem = 0x800000;
+ final int AccSemicolonBody = 0x1000000;
+ final int AccUnresolved = 0x2000000;
+ final int AccClearPrivateModifier = 0x4000000;
+ // might be requested during private access emulation
+ final int AccVisibilityMASK = AccPublic | AccProtected | AccPrivate;
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java
new file mode 100644
index 0000000000..173bbcd444
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java
@@ -0,0 +1,232 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class FieldBinding extends VariableBinding {
+ public ReferenceBinding declaringClass;
+ protected FieldBinding() {
+ }
+
+ public FieldBinding(
+ char[] name,
+ TypeBinding type,
+ int modifiers,
+ ReferenceBinding declaringClass,
+ Constant constant) {
+ this.modifiers = modifiers;
+ this.type = type;
+ this.name = name;
+ this.declaringClass = declaringClass;
+ this.constant = constant;
+
+ // propagate the deprecated modifier
+ if (this.declaringClass != null)
+ if (this.declaringClass.isViewedAsDeprecated() && !isDeprecated())
+ this.modifiers |= AccDeprecatedImplicitly;
+ }
+
+ public FieldBinding(
+ FieldDeclaration field,
+ TypeBinding type,
+ ReferenceBinding declaringClass) {
+ this(field.name, type, field.modifiers, declaringClass, null);
+
+ field.binding = this;
+ }
+
+ // special API used to change field declaring class for runtime visibility check
+ public FieldBinding(
+ FieldBinding initialFieldBinding,
+ ReferenceBinding declaringClass) {
+ this.modifiers = initialFieldBinding.modifiers;
+ this.type = initialFieldBinding.type;
+ this.name = initialFieldBinding.name;
+ this.declaringClass = declaringClass;
+ this.constant = initialFieldBinding.constant;
+ this.id = initialFieldBinding.id;
+ }
+
+ /* API
+ * Answer the receiver's binding type from Binding.BindingID.
+ */
+
+ public final int bindingType() {
+ return FIELD;
+ }
+
+ /* 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.
+ *
+ * NOTE: Cannot invoke this method with a compilation unit scope.
+ */
+
+ public final boolean canBeSeenBy(
+ TypeBinding receiverType,
+ InvocationSite invocationSite,
+ Scope scope) {
+ if (isPublic())
+ return true;
+
+ SourceTypeBinding invocationType = scope.enclosingSourceType();
+ if (invocationType == declaringClass && invocationType == receiverType)
+ return true;
+
+ if (isProtected()) {
+ // answer true if the invocationType is the declaringClass or they are in the same package
+ // OR the invocationType is a subclass of the declaringClass
+ // AND the receiverType is the invocationType or its subclass
+ // OR the field is a static field accessed directly through a type
+ if (invocationType == declaringClass)
+ return true;
+ if (invocationType.fPackage == declaringClass.fPackage)
+ return true;
+ if (declaringClass.isSuperclassOf(invocationType)) {
+ if (invocationSite.isSuperAccess())
+ return true;
+ // receiverType can be an array binding in one case... see if you can change it
+ if (receiverType instanceof ArrayBinding)
+ return false;
+ if (invocationType == receiverType
+ || invocationType.isSuperclassOf((ReferenceBinding) receiverType))
+ return true;
+ if (isStatic())
+ return true; // see 1FMEPDL - return invocationSite.isTypeAccess();
+ }
+ return false;
+ }
+
+ if (isPrivate()) {
+ // answer true if the receiverType is the declaringClass
+ // AND the invocationType and the declaringClass have a common enclosingType
+ if (receiverType != declaringClass)
+ return false;
+
+ if (invocationType != declaringClass) {
+ ReferenceBinding outerInvocationType = invocationType;
+ ReferenceBinding temp = outerInvocationType.enclosingType();
+ while (temp != null) {
+ outerInvocationType = temp;
+ temp = temp.enclosingType();
+ }
+
+ ReferenceBinding outerDeclaringClass = declaringClass;
+ temp = outerDeclaringClass.enclosingType();
+ while (temp != null) {
+ outerDeclaringClass = temp;
+ temp = temp.enclosingType();
+ }
+ if (outerInvocationType != outerDeclaringClass)
+ return false;
+ }
+ return true;
+ }
+
+ // isDefault()
+ if (invocationType.fPackage != declaringClass.fPackage)
+ return false;
+
+ // receiverType can be an array binding in one case... see if you can change it
+ if (receiverType instanceof ArrayBinding)
+ return false;
+ ReferenceBinding type = (ReferenceBinding) receiverType;
+ PackageBinding declaringPackage = declaringClass.fPackage;
+ do {
+ if (declaringClass == type)
+ return true;
+ if (declaringPackage != type.fPackage)
+ return false;
+ } while ((type = type.superclass()) != null);
+ return false;
+ }
+
+ public final int getAccessFlags() {
+ return modifiers & AccJustFlag;
+ }
+
+ public SyntheticAccessMethodBinding getSyntheticReadAccess() {
+ return ((SourceTypeBinding) declaringClass).addSyntheticMethod(this, true);
+ }
+
+ public SyntheticAccessMethodBinding getSyntheticWriteAccess() {
+ return ((SourceTypeBinding) declaringClass).addSyntheticMethod(this, false);
+ }
+
+ /* Answer true if the receiver has default visibility
+ */
+
+ public final boolean isDefault() {
+ return !isPublic() && !isProtected() && !isPrivate();
+ }
+
+ /* Answer true if the receiver is a deprecated field
+ */
+
+ public final boolean isDeprecated() {
+ return (modifiers & AccDeprecated) != 0;
+ }
+
+ /* Answer true if the receiver has private visibility
+ */
+
+ public final boolean isPrivate() {
+ return (modifiers & AccPrivate) != 0;
+ }
+
+ /* Answer true if the receiver has protected visibility
+ */
+
+ public final boolean isProtected() {
+ return (modifiers & AccProtected) != 0;
+ }
+
+ /* Answer true if the receiver has public visibility
+ */
+
+ public final boolean isPublic() {
+ return (modifiers & AccPublic) != 0;
+ }
+
+ /* Answer true if the receiver is a static field
+ */
+
+ public final boolean isStatic() {
+ return (modifiers & AccStatic) != 0;
+ }
+
+ /* Answer true if the receiver is not defined in the source of the declaringClass
+ */
+
+ public final boolean isSynthetic() {
+ return (modifiers & AccSynthetic) != 0;
+ }
+
+ /* Answer true if the receiver is a transient field
+ */
+
+ public final boolean isTransient() {
+ return (modifiers & AccTransient) != 0;
+ }
+
+ /* Answer true if the receiver's declaring type is deprecated (or any of its enclosing types)
+ */
+
+ public final boolean isViewedAsDeprecated() {
+ return (modifiers & AccDeprecated) != 0
+ || (modifiers & AccDeprecatedImplicitly) != 0;
+ }
+
+ /* Answer true if the receiver is a volatile field
+ */
+
+ public final boolean isVolatile() {
+ return (modifiers & AccVolatile) != 0;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImportBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImportBinding.java
new file mode 100644
index 0000000000..a09db89eb1
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImportBinding.java
@@ -0,0 +1,44 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class ImportBinding extends Binding {
+ public char[][] compoundName;
+ public boolean onDemand;
+
+ Binding resolvedImport; // must ensure the import is resolved
+ public ImportBinding(
+ char[][] compoundName,
+ boolean isOnDemand,
+ Binding binding) {
+ this.compoundName = compoundName;
+ this.onDemand = isOnDemand;
+ this.resolvedImport = binding;
+ }
+
+ /* API
+ * Answer the receiver's binding type from Binding.BindingID.
+ */
+
+ public final int bindingType() {
+ return IMPORT;
+ }
+
+ public char[] readableName() {
+ if (onDemand)
+ return CharOperation.concat(
+ CharOperation.concatWith(compoundName, '.'),
+ ".*".toCharArray());
+ else
+ return CharOperation.concatWith(compoundName, '.');
+ }
+
+ public String toString() {
+ return "import : " + new String(readableName());
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InnerEmulationDependency.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InnerEmulationDependency.java
new file mode 100644
index 0000000000..f8daf4a83c
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InnerEmulationDependency.java
@@ -0,0 +1,16 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+public class InnerEmulationDependency {
+ public BlockScope scope;
+ public boolean wasEnclosingInstanceSupplied;
+ public boolean useDirectAccess;
+ public InnerEmulationDependency(
+ BlockScope scope,
+ boolean wasEnclosingInstanceSupplied,
+ boolean useDirectAccess) {
+ this.scope = scope;
+ this.wasEnclosingInstanceSupplied = wasEnclosingInstanceSupplied;
+ this.useDirectAccess = useDirectAccess;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InvocationSite.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InvocationSite.java
new file mode 100644
index 0000000000..41e14bd863
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InvocationSite.java
@@ -0,0 +1,8 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+public interface InvocationSite {
+ boolean isSuperAccess();
+ boolean isTypeAccess();
+ void setDepth(int depth);
+ void setFieldIndex(int depth);
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalTypeBinding.java
new file mode 100644
index 0000000000..af8eb4fb69
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalTypeBinding.java
@@ -0,0 +1,134 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public final class LocalTypeBinding extends NestedTypeBinding {
+ final static char[] LocalTypePrefix = { '$', 'L', 'o', 'c', 'a', 'l', '$' };
+
+ private InnerEmulationDependency[] dependents;
+ public LocalTypeBinding(ClassScope scope, SourceTypeBinding enclosingType) {
+ super(
+ new char[][] {
+ CharOperation.concat(LocalTypePrefix, scope.referenceContext.name)},
+ scope,
+ enclosingType);
+
+ if (this.sourceName == AnonymousLocalTypeDeclaration.ANONYMOUS_EMPTY_NAME)
+ this.tagBits |= AnonymousTypeMask;
+ else
+ this.tagBits |= LocalTypeMask;
+ }
+
+ /* Record a dependency onto a source target type which may be altered
+ * by the end of the innerclass emulation. Later on, we will revisit
+ * all its dependents so as to update them (see updateInnerEmulationDependents()).
+ */
+
+ public void addInnerEmulationDependent(
+ BlockScope scope,
+ boolean wasEnclosingInstanceSupplied,
+ boolean useDirectAccess) {
+ int index;
+ if (dependents == null) {
+ index = 0;
+ dependents = new InnerEmulationDependency[1];
+ } else {
+ index = dependents.length;
+ for (int i = 0; i < index; i++)
+ if (dependents[i].scope == scope)
+ return; // already stored
+ System.arraycopy(
+ dependents,
+ 0,
+ (dependents = new InnerEmulationDependency[index + 1]),
+ 0,
+ index);
+ }
+ dependents[index] =
+ new InnerEmulationDependency(
+ scope,
+ wasEnclosingInstanceSupplied,
+ useDirectAccess);
+ // System.out.println("Adding dependency: "+ new String(scope.enclosingType().readableName()) + " --> " + new String(this.readableName()));
+ }
+
+ /* Answer the receiver's constant pool name.
+ *
+ * NOTE: This method should only be used during/after code gen.
+ */
+
+ public char[] constantPoolName() /* java/lang/Object */ {
+ return constantPoolName;
+ }
+
+ public void constantPoolName(char[] computedConstantPoolName) /* java/lang/Object */ {
+ this.constantPoolName = computedConstantPoolName;
+ }
+
+ public char[] readableName() {
+ if (isAnonymousType()) {
+ if (superInterfaces == NoSuperInterfaces)
+ return (
+ "<anonymous subclass of " + new String(superclass.readableName()) + ">")
+ .toCharArray();
+ else
+ return (
+ "<anonymous implementation of "
+ + new String(superInterfaces[0].readableName())
+ + ">")
+ .toCharArray();
+ } else
+ if (isMemberType()) {
+ return CharOperation.concat(enclosingType().readableName(), sourceName, '.');
+ } else {
+ return sourceName;
+ }
+ }
+
+ // Record that the type is a local member type
+
+ public void setAsMemberType() {
+ tagBits |= MemberTypeMask;
+ }
+
+ public char[] sourceName() {
+ if (isAnonymousType())
+ return readableName();
+ else
+ return sourceName;
+ }
+
+ public String toString() {
+ if (isAnonymousType())
+ return "Anonymous type : " + super.toString();
+ if (isMemberType())
+ return "Local member type : "
+ + new String(sourceName())
+ + " "
+ + super.toString();
+ return "Local type : " + new String(sourceName()) + " " + super.toString();
+ }
+
+ /* Trigger the dependency mechanism forcing the innerclass emulation
+ * to be propagated to all dependent source types.
+ */
+
+ public void updateInnerEmulationDependents() {
+ if (dependents != null) {
+ for (int i = 0; i < dependents.length; i++) {
+ InnerEmulationDependency dependency = dependents[i];
+ // System.out.println("Updating " + new String(this.readableName()) + " --> " + new String(dependency.scope.enclosingType().readableName()));
+ dependency.scope.propagateInnerEmulation(
+ this,
+ dependency.wasEnclosingInstanceSupplied,
+ dependency.useDirectAccess);
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java
new file mode 100644
index 0000000000..f46c488f5b
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java
@@ -0,0 +1,111 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+
+public class LocalVariableBinding extends VariableBinding {
+ public boolean isArgument;
+
+ public int resolvedPosition;
+ // for code generation (position in method context)
+ public boolean used; // for flow analysis
+ public BlockScope declaringScope; // back-pointer to its declaring scope
+ public LocalDeclaration declaration; // for source-positions
+
+ public int[] initializationPCs;
+ public int initializationCount = 0;
+ public LocalVariableBinding(char[] name, TypeBinding type, int modifiers) {
+ this(name, type, modifiers, false);
+ }
+
+ public LocalVariableBinding(
+ char[] name,
+ TypeBinding type,
+ int modifiers,
+ boolean isArgument) {
+ this.name = name;
+ this.type = type;
+ this.modifiers = modifiers;
+ if (this.isArgument = isArgument)
+ this.constant = Constant.NotAConstant;
+ }
+
+ public LocalVariableBinding(
+ LocalDeclaration declaration,
+ TypeBinding type,
+ int modifiers) {
+ this(declaration.name, type, modifiers, false);
+ this.declaration = declaration;
+ }
+
+ /* API
+ * Answer the receiver's binding type from Binding.BindingID.
+ */
+
+ public final int bindingType() {
+ return LOCAL;
+ }
+
+ // Answer whether the variable binding is a secret variable added for code gen purposes
+
+ public boolean isSecret() {
+ return declaration == null && !isArgument;
+ }
+
+ public void recordInitializationEndPC(int pc) {
+ if (initializationPCs[((initializationCount - 1) << 1) + 1] == -1)
+ initializationPCs[((initializationCount - 1) << 1) + 1] = pc;
+ }
+
+ public void recordInitializationStartPC(int pc) {
+ if (initializationPCs == null)
+ return;
+ // optimize cases where reopening a contiguous interval
+ if ((initializationCount > 0)
+ && (initializationPCs[((initializationCount - 1) << 1) + 1] == pc)) {
+ initializationPCs[((initializationCount - 1) << 1) + 1] = -1;
+ // reuse previous interval (its range will be augmented)
+ } else {
+ int index = initializationCount << 1;
+ if (index == initializationPCs.length) {
+ System.arraycopy(
+ initializationPCs,
+ 0,
+ (initializationPCs = new int[initializationCount << 2]),
+ 0,
+ index);
+ }
+ initializationPCs[index] = pc;
+ initializationPCs[index + 1] = -1;
+ initializationCount++;
+ }
+ }
+
+ public String toString() {
+ String s = super.toString();
+ if (!used)
+ s += "[pos: unused]";
+ else
+ s += "[pos: " + String.valueOf(resolvedPosition) + "]";
+ s += "[id:" + String.valueOf(id) + "]";
+ if (initializationCount > 0) {
+ s += "[pc: ";
+ for (int i = 0; i < initializationCount; i++) {
+ if (i > 0)
+ s += ", ";
+ s += String.valueOf(initializationPCs[i << 1])
+ + "-"
+ + ((initializationPCs[(i << 1) + 1] == -1)
+ ? "?"
+ : String.valueOf(initializationPCs[(i << 1) + 1]));
+ }
+ s += "]";
+ }
+ return s;
+ }
+
+}
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
new file mode 100644
index 0000000000..97b5142c58
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java
@@ -0,0 +1,665 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.env.*;
+
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class LookupEnvironment
+ implements BaseTypes, ProblemReasons, TypeConstants {
+ public CompilerOptions options;
+ public ProblemReporter problemReporter;
+ public ITypeRequestor typeRequestor;
+
+ PackageBinding defaultPackage;
+ ImportBinding[] defaultImports;
+ HashtableOfPackage knownPackages;
+ static final ProblemPackageBinding theNotFoundPackage =
+ new ProblemPackageBinding(new char[0], NotFound);
+ static final ProblemReferenceBinding theNotFoundType =
+ new ProblemReferenceBinding(new char[0], NotFound);
+
+ private INameEnvironment nameEnvironment;
+ private MethodVerifier verifier;
+ private ArrayBinding[][] uniqueArrayBindings;
+
+ private CompilationUnitDeclaration[] units = new CompilationUnitDeclaration[4];
+ private int lastUnitIndex = -1;
+ private int lastCompletedUnitIndex = -1;
+
+ // indicate in which step on the compilation we are.
+ // step 1 : build the reference binding
+ // step 2 : conect the hierarchy (connect bindings)
+ // step 3 : build fields and method bindings.
+ private int stepCompleted;
+ final static int BUILD_TYPE_HIERARCHY = 1;
+ final static int CHECK_AND_SET_IMPORTS = 2;
+ final static int CONNECT_TYPE_HIERARCHY = 3;
+ final static int BUILD_FIELDS_AND_METHODS = 4;
+ public LookupEnvironment(
+ ITypeRequestor typeRequestor,
+ CompilerOptions options,
+ ProblemReporter problemReporter,
+ INameEnvironment nameEnvironment) {
+ this.typeRequestor = typeRequestor;
+ this.options = options;
+ this.problemReporter = problemReporter;
+ this.defaultPackage = new PackageBinding(this);
+ // assume the default package always exists
+ this.defaultImports = null;
+ this.nameEnvironment = nameEnvironment;
+ this.knownPackages = new HashtableOfPackage();
+ this.uniqueArrayBindings = new ArrayBinding[5][];
+ this.uniqueArrayBindings[0] = new ArrayBinding[50];
+ // start off the most common 1 dimension array @ 50
+ }
+
+ /* Ask the oracle for a type which corresponds to the compoundName.
+ * Answer null if the name cannot be found.
+ */
+
+ ReferenceBinding askForType(char[][] compoundName) {
+ NameEnvironmentAnswer answer = nameEnvironment.findType(compoundName);
+ if (answer == null)
+ return null;
+
+ if (answer.isBinaryType())
+ // the type was found as a .class file
+ typeRequestor.accept(answer.getBinaryType(), computePackageFrom(compoundName));
+ else
+ if (answer.isCompilationUnit())
+ // the type was found as a .java file, try to build it then search the cache
+ typeRequestor.accept(answer.getCompilationUnit());
+ else
+ if (answer.isSourceType())
+ // the type was found as a source model
+ typeRequestor.accept(answer.getSourceType(), computePackageFrom(compoundName));
+
+ return getCachedType(compoundName);
+ }
+
+ /* Ask the oracle for a type named name in the packageBinding.
+ * Answer null if the name cannot be found.
+ */
+
+ ReferenceBinding askForType(PackageBinding packageBinding, char[] name) {
+ if (packageBinding == null) {
+ if (defaultPackage == null)
+ return null;
+ packageBinding = defaultPackage;
+ }
+ NameEnvironmentAnswer answer =
+ nameEnvironment.findType(name, packageBinding.compoundName);
+ if (answer == null)
+ return null;
+
+ if (answer.isBinaryType())
+ // the type was found as a .class file
+ typeRequestor.accept(answer.getBinaryType(), packageBinding);
+ else
+ if (answer.isCompilationUnit())
+ // the type was found as a .java file, try to build it then search the cache
+ typeRequestor.accept(answer.getCompilationUnit());
+ else
+ if (answer.isSourceType())
+ // the type was found as a source model
+ typeRequestor.accept(answer.getSourceType(), packageBinding);
+
+ return packageBinding.getType0(name);
+ }
+
+ /* Create the initial type bindings for the compilation unit.
+ *
+ * See completeTypeBindings() for a description of the remaining steps
+ *
+ * NOTE: This method can be called multiple times as additional source files are needed
+ */
+
+ public void buildTypeBindings(CompilationUnitDeclaration unit) {
+ CompilationUnitScope scope = new CompilationUnitScope(unit, this);
+ scope.buildTypeBindings();
+
+ int unitsLength = units.length;
+ if (++lastUnitIndex >= unitsLength)
+ System.arraycopy(
+ units,
+ 0,
+ units = new CompilationUnitDeclaration[2 * unitsLength],
+ 0,
+ unitsLength);
+ units[lastUnitIndex] = unit;
+ }
+
+ /* Cache the binary type since we know it is needed during this compile.
+ *
+ * Answer the created BinaryTypeBinding or null if the type is already in the cache.
+ */
+
+ public BinaryTypeBinding cacheBinaryType(IBinaryType binaryType) {
+ return cacheBinaryType(binaryType, true);
+ }
+
+ /* Cache the binary type since we know it is needed during this compile.
+ *
+ * Answer the created BinaryTypeBinding or null if the type is already in the cache.
+ */
+
+ public BinaryTypeBinding cacheBinaryType(
+ IBinaryType binaryType,
+ boolean needFieldsAndMethods) {
+ char[][] compoundName = CharOperation.splitOn('/', binaryType.getName());
+ ReferenceBinding existingType = getCachedType(compoundName);
+
+ if (existingType == null || existingType instanceof UnresolvedReferenceBinding)
+ // only add the binary type if its not already in the cache
+ return createBinaryTypeFrom(
+ binaryType,
+ computePackageFrom(compoundName),
+ needFieldsAndMethods);
+ return null; // the type already exists & can be retrieved from the cache
+ }
+
+ /*
+ * 1. Connect the type hierarchy for the type bindings created for parsedUnits.
+ * 2. Create the field bindings
+ * 3. Create the method bindings
+ */
+
+ /* We know each known compilationUnit is free of errors at this point...
+ *
+ * Each step will create additional bindings unless a problem is detected, in which
+ * case either the faulty import/superinterface/field/method will be skipped or a
+ * suitable replacement will be substituted (such as Object for a missing superclass)
+ */
+
+ public void completeTypeBindings() {
+ stepCompleted = BUILD_TYPE_HIERARCHY;
+
+ for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) {
+ units[i].scope.checkAndSetImports();
+ }
+ stepCompleted = CHECK_AND_SET_IMPORTS;
+
+ for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) {
+ units[i].scope.connectTypeHierarchy();
+ }
+ stepCompleted = CONNECT_TYPE_HIERARCHY;
+
+ for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) {
+ units[i].scope.buildFieldsAndMethods();
+ units[i] = null; // release unnecessary reference to the parsed unit
+ }
+ stepCompleted = BUILD_FIELDS_AND_METHODS;
+ lastCompletedUnitIndex = lastUnitIndex;
+ }
+
+ /*
+ * 1. Connect the type hierarchy for the type bindings created for parsedUnits.
+ * 2. Create the field bindings
+ * 3. Create the method bindings
+ */
+
+ /*
+ * Each step will create additional bindings unless a problem is detected, in which
+ * case either the faulty import/superinterface/field/method will be skipped or a
+ * suitable replacement will be substituted (such as Object for a missing superclass)
+ */
+
+ public void completeTypeBindings(CompilationUnitDeclaration parsedUnit) {
+ if (stepCompleted == BUILD_FIELDS_AND_METHODS) {
+ // This can only happen because the original set of units are completely built and
+ // are now being processed, so we want to treat all the additional units as a group
+ // until they too are completely processed.
+ completeTypeBindings();
+ } else {
+ if (parsedUnit.scope == null)
+ return; // parsing errors were too severe
+
+ if (stepCompleted >= CHECK_AND_SET_IMPORTS)
+ parsedUnit.scope.checkAndSetImports();
+
+ if (stepCompleted >= CONNECT_TYPE_HIERARCHY)
+ parsedUnit.scope.connectTypeHierarchy();
+ }
+ }
+
+ /*
+ * Used by other compiler tools which do not start by calling completeTypeBindings().
+ *
+ * 1. Connect the type hierarchy for the type bindings created for parsedUnits.
+ * 2. Create the field bindings
+ * 3. Create the method bindings
+ */
+
+ public void completeTypeBindings(
+ CompilationUnitDeclaration parsedUnit,
+ boolean buildFieldsAndMethods) {
+ if (parsedUnit.scope == null)
+ return; // parsing errors were too severe
+
+ parsedUnit.scope.checkAndSetImports();
+ parsedUnit.scope.connectTypeHierarchy();
+
+ if (buildFieldsAndMethods)
+ parsedUnit.scope.buildFieldsAndMethods();
+ }
+
+ private PackageBinding computePackageFrom(char[][] constantPoolName) {
+ if (constantPoolName.length == 1)
+ return defaultPackage;
+
+ PackageBinding packageBinding = getPackage0(constantPoolName[0]);
+ if (packageBinding == null || packageBinding == theNotFoundPackage) {
+ packageBinding = new PackageBinding(constantPoolName[0], this);
+ knownPackages.put(constantPoolName[0], packageBinding);
+ }
+
+ for (int i = 1, length = constantPoolName.length - 1; i < length; i++) {
+ PackageBinding parent = packageBinding;
+ if ((packageBinding = parent.getPackage0(constantPoolName[i])) == null
+ || packageBinding == theNotFoundPackage) {
+ packageBinding =
+ new PackageBinding(
+ CharOperation.subarray(constantPoolName, 0, i + 1),
+ parent,
+ this);
+ parent.addPackage(packageBinding);
+ }
+ }
+ return packageBinding;
+ }
+
+ /* Used to guarantee array type identity.
+ */
+
+ ArrayBinding createArrayType(TypeBinding type, int dimensionCount) {
+ // find the array binding cache for this dimension
+ int dimIndex = dimensionCount - 1;
+ int length = uniqueArrayBindings.length;
+ ArrayBinding[] arrayBindings;
+ if (dimIndex < length) {
+ if ((arrayBindings = uniqueArrayBindings[dimIndex]) == null)
+ uniqueArrayBindings[dimIndex] = arrayBindings = new ArrayBinding[10];
+ } else {
+ System.arraycopy(
+ uniqueArrayBindings,
+ 0,
+ uniqueArrayBindings = new ArrayBinding[dimensionCount][],
+ 0,
+ length);
+ uniqueArrayBindings[dimIndex] = arrayBindings = new ArrayBinding[10];
+ }
+
+ // find the cached array binding for this leaf component type (if any)
+ int index = -1;
+ length = arrayBindings.length;
+ while (++index < length) {
+ ArrayBinding currentBinding = arrayBindings[index];
+ if (currentBinding == null) // no matching array, but space left
+ return arrayBindings[index] = new ArrayBinding(type, dimensionCount);
+ if (currentBinding.leafComponentType == type)
+ return currentBinding;
+ }
+
+ // no matching array, no space left
+ System.arraycopy(
+ arrayBindings,
+ 0,
+ (arrayBindings = new ArrayBinding[length * 2]),
+ 0,
+ length);
+ uniqueArrayBindings[dimIndex] = arrayBindings;
+ return arrayBindings[length] = new ArrayBinding(type, dimensionCount);
+ }
+
+ public BinaryTypeBinding createBinaryTypeFrom(
+ IBinaryType binaryType,
+ PackageBinding packageBinding) {
+ return createBinaryTypeFrom(binaryType, packageBinding, true);
+ }
+
+ public BinaryTypeBinding createBinaryTypeFrom(
+ IBinaryType binaryType,
+ PackageBinding packageBinding,
+ boolean needFieldsAndMethods) {
+ BinaryTypeBinding binaryBinding =
+ new BinaryTypeBinding(packageBinding, binaryType, this);
+
+ // resolve any array bindings which reference the unresolvedType
+ ReferenceBinding cachedType =
+ packageBinding.getType0(
+ binaryBinding.compoundName[binaryBinding.compoundName.length - 1]);
+ if (cachedType != null) {
+ if (cachedType.isBinaryBinding())
+ // sanity check before the cast... at this point the cache should ONLY contain unresolved types
+ return (BinaryTypeBinding) cachedType;
+
+ UnresolvedReferenceBinding unresolvedType =
+ (UnresolvedReferenceBinding) cachedType;
+ unresolvedType.resolvedType = binaryBinding;
+ updateArrayCache(unresolvedType, binaryBinding);
+ }
+
+ packageBinding.addType(binaryBinding);
+ binaryBinding.cachePartsFrom(binaryType, needFieldsAndMethods);
+ return binaryBinding;
+ }
+
+ /* Used to create packages from the package statement.
+ */
+
+ PackageBinding createPackage(char[][] compoundName) {
+ PackageBinding packageBinding = getPackage0(compoundName[0]);
+ if (packageBinding == null || packageBinding == theNotFoundPackage) {
+ packageBinding = new PackageBinding(compoundName[0], this);
+ knownPackages.put(compoundName[0], packageBinding);
+ }
+
+ for (int i = 1, length = compoundName.length; i < length; i++) {
+ // check to see if it collides with a known type...
+ // this case can only happen if the package does not exist as a directory in the file system
+ // otherwise when the source type was defined, the correct error would have been reported
+ // unless its an unresolved type which is referenced from an inconsistent class file
+ ReferenceBinding type = packageBinding.getType0(compoundName[i]);
+ if (type != null
+ && type != theNotFoundType
+ && !(type instanceof UnresolvedReferenceBinding))
+ return null;
+
+ PackageBinding parent = packageBinding;
+ if ((packageBinding = parent.getPackage0(compoundName[i])) == null
+ || packageBinding == theNotFoundPackage) {
+ // if the package is unknown, check to see if a type exists which would collide with the new package
+ // catches the case of a package statement of: package java.lang.Object;
+ // since the package can be added after a set of source files have already been compiled, we need
+ // whenever a package statement is encountered
+ if (nameEnvironment.findType(compoundName[i], parent.compoundName) != null)
+ return null;
+
+ packageBinding =
+ new PackageBinding(
+ CharOperation.subarray(compoundName, 0, i + 1),
+ parent,
+ this);
+ parent.addPackage(packageBinding);
+ }
+ }
+ return packageBinding;
+ }
+
+ /* Answer the type for the compoundName if it exists in the cache.
+ * Answer theNotFoundType if it could not be resolved the first time
+ * it was looked up, otherwise answer null.
+ *
+ * NOTE: Do not use for nested types... the answer is NOT the same for a.b.C or a.b.C.D.E
+ * assuming C is a type in both cases. In the a.b.C.D.E case, null is the answer.
+ */
+
+ public ReferenceBinding getCachedType(char[][] compoundName) {
+ if (compoundName.length == 1) {
+ if (defaultPackage == null)
+ return null;
+ return defaultPackage.getType0(compoundName[0]);
+ }
+
+ PackageBinding packageBinding = getPackage0(compoundName[0]);
+ if (packageBinding == null || packageBinding == theNotFoundPackage)
+ return null;
+
+ for (int i = 1, packageLength = compoundName.length - 1;
+ i < packageLength;
+ i++)
+ if ((packageBinding = packageBinding.getPackage0(compoundName[i])) == null
+ || packageBinding == theNotFoundPackage)
+ return null;
+ return packageBinding.getType0(compoundName[compoundName.length - 1]);
+ }
+
+ /* Answer the top level package named name if it exists in the cache.
+ * Answer theNotFoundPackage if it could not be resolved the first time
+ * it was looked up, otherwise answer null.
+ *
+ * NOTE: Senders must convert theNotFoundPackage into a real problem
+ * package if its to returned.
+ */
+
+ PackageBinding getPackage0(char[] name) {
+ return knownPackages.get(name);
+ }
+
+ /* Answer the top level package named name.
+ * Ask the oracle for the package if its not in the cache.
+ * Answer null if the package cannot be found.
+ */
+
+ PackageBinding getTopLevelPackage(char[] name) {
+ PackageBinding packageBinding = getPackage0(name);
+ if (packageBinding != null) {
+ if (packageBinding == theNotFoundPackage)
+ return null;
+ else
+ return packageBinding;
+ }
+
+ if (nameEnvironment.isPackage(null, name)) {
+ knownPackages.put(name, packageBinding = new PackageBinding(name, this));
+ return packageBinding;
+ }
+
+ knownPackages.put(name, theNotFoundPackage);
+ // saves asking the oracle next time
+ return null;
+ }
+
+ /* Answer the type corresponding to the compoundName.
+ * Ask the oracle for the type if its not in the cache.
+ * Answer null if the type cannot be found... likely a fatal error.
+ */
+
+ ReferenceBinding getType(char[][] compoundName) {
+ ReferenceBinding referenceBinding;
+
+ if (compoundName.length == 1) {
+ if (defaultPackage == null)
+ return null;
+
+ if ((referenceBinding = defaultPackage.getType0(compoundName[0])) == null) {
+ PackageBinding packageBinding = getPackage0(compoundName[0]);
+ if (packageBinding != null && packageBinding != theNotFoundPackage)
+ return null;
+ // collides with a known package... should not call this method in such a case
+ referenceBinding = askForType(defaultPackage, compoundName[0]);
+ }
+ } else {
+ PackageBinding packageBinding = getPackage0(compoundName[0]);
+ if (packageBinding == null || packageBinding == theNotFoundPackage)
+ return null;
+
+ for (int i = 1, packageLength = compoundName.length - 1;
+ i < packageLength;
+ i++) {
+ if ((packageBinding = packageBinding.getPackage0(compoundName[i])) == null)
+ break;
+ if (packageBinding == theNotFoundPackage)
+ return null;
+ }
+
+ if (packageBinding == null)
+ referenceBinding = askForType(compoundName);
+ else
+ if ((referenceBinding =
+ packageBinding.getType0(compoundName[compoundName.length - 1]))
+ == null)
+ referenceBinding =
+ askForType(packageBinding, compoundName[compoundName.length - 1]);
+ }
+
+ if (referenceBinding == null || referenceBinding == theNotFoundType)
+ return null;
+ if (referenceBinding instanceof UnresolvedReferenceBinding)
+ referenceBinding =
+ ((UnresolvedReferenceBinding) referenceBinding).resolve(this);
+
+ // compoundName refers to a nested type incorrectly (i.e. package1.A$B)
+ if (referenceBinding.isNestedType())
+ return new ProblemReferenceBinding(compoundName, InternalNameProvided);
+ else
+ return referenceBinding;
+ }
+
+ /* Answer the type corresponding to the name from the binary file.
+ * Does not ask the oracle for the type if its not found in the cache... instead an
+ * unresolved type is returned which must be resolved before used.
+ *
+ * NOTE: Does NOT answer base types nor array types!
+ *
+ * NOTE: Aborts compilation if the class file cannot be found.
+ */
+
+ ReferenceBinding getTypeFromConstantPoolName(
+ char[] signature,
+ int start,
+ int end) {
+ if (end == -1)
+ end = signature.length - 1;
+
+ char[][] compoundName = CharOperation.splitOn('/', signature, start, end);
+ ReferenceBinding binding = getCachedType(compoundName);
+ if (binding == null) {
+ PackageBinding packageBinding = computePackageFrom(compoundName);
+ binding = new UnresolvedReferenceBinding(compoundName, packageBinding);
+ packageBinding.addType(binding);
+ } else
+ if (binding == theNotFoundType) {
+ problemReporter.isClassPathCorrect(compoundName, null);
+ return null; // will not get here since the above error aborts the compilation
+ }
+ return binding;
+ }
+
+ /* Answer the type corresponding to the signature from the binary file.
+ * Does not ask the oracle for the type if its not found in the cache... instead an
+ * unresolved type is returned which must be resolved before used.
+ *
+ * NOTE: Does answer base types & array types.
+ *
+ * NOTE: Aborts compilation if the class file cannot be found.
+ */
+
+ TypeBinding getTypeFromSignature(char[] signature, int start, int end) {
+ int dimension = 0;
+ while (signature[start] == '[') {
+ start++;
+ dimension++;
+ }
+ if (end == -1)
+ end = signature.length - 1;
+
+ // Just switch on signature[start] - the L case is the else
+ TypeBinding binding = null;
+ if (start == end) {
+ switch (signature[start]) {
+ case 'I' :
+ binding = IntBinding;
+ break;
+ case 'Z' :
+ binding = BooleanBinding;
+ break;
+ case 'V' :
+ binding = VoidBinding;
+ break;
+ case 'C' :
+ binding = CharBinding;
+ break;
+ case 'D' :
+ binding = DoubleBinding;
+ break;
+ case 'B' :
+ binding = ByteBinding;
+ break;
+ case 'F' :
+ binding = FloatBinding;
+ break;
+ case 'J' :
+ binding = LongBinding;
+ break;
+ case 'S' :
+ binding = ShortBinding;
+ break;
+ default :
+ throw new Error("Undefined base type: " + signature[start]);
+ }
+ } else {
+ binding = getTypeFromConstantPoolName(signature, start + 1, end - 1);
+ }
+
+ if (dimension == 0)
+ return binding;
+ else
+ return createArrayType(binding, dimension);
+ }
+
+ /* Ask the oracle if a package exists named name in the package named compoundName.
+ */
+
+ boolean isPackage(char[][] compoundName, char[] name) {
+ if (compoundName == null || compoundName.length == 0)
+ return nameEnvironment.isPackage(null, name);
+ else
+ return nameEnvironment.isPackage(compoundName, name);
+ }
+
+ // The method verifier is lazily initialized to guarantee the receiver, the compiler & the oracle are ready.
+
+ public MethodVerifier methodVerifier() {
+ if (verifier == null)
+ verifier = new MethodVerifier(this);
+ return verifier;
+ }
+
+ public void reset() {
+ this.defaultPackage = new PackageBinding(this);
+ // assume the default package always exists
+ this.defaultImports = null;
+ this.knownPackages = new HashtableOfPackage();
+
+ this.verifier = null;
+ for (int i = this.uniqueArrayBindings.length; --i >= 0;)
+ this.uniqueArrayBindings[i] = null;
+ this.uniqueArrayBindings[0] = new ArrayBinding[50];
+ // start off the most common 1 dimension array @ 50
+
+ for (int i = this.units.length; --i >= 0;)
+ this.units[i] = null;
+ this.lastUnitIndex = -1;
+ this.lastCompletedUnitIndex = -1;
+ }
+
+ void updateArrayCache(
+ UnresolvedReferenceBinding unresolvedType,
+ ReferenceBinding resolvedType) {
+ nextDimension : for (
+ int i = 0, length = uniqueArrayBindings.length; i < length; i++) {
+ ArrayBinding[] arrayBindings = uniqueArrayBindings[i];
+ if (arrayBindings != null) {
+ for (int j = 0, max = arrayBindings.length; j < max; j++) {
+ ArrayBinding currentBinding = arrayBindings[j];
+ if (currentBinding == null)
+ continue nextDimension;
+ if (currentBinding.leafComponentType == unresolvedType) {
+ currentBinding.leafComponentType = resolvedType;
+ continue nextDimension;
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MemberTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MemberTypeBinding.java
new file mode 100644
index 0000000000..d40f7ad662
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MemberTypeBinding.java
@@ -0,0 +1,43 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public final class MemberTypeBinding extends NestedTypeBinding {
+ public MemberTypeBinding(
+ char[][] compoundName,
+ ClassScope scope,
+ SourceTypeBinding enclosingType) {
+ super(compoundName, scope, enclosingType);
+ this.tagBits |= MemberTypeMask;
+ }
+
+ void checkSyntheticArgsAndFields() {
+ if (this.isStatic())
+ return;
+ if (this.isInterface())
+ return;
+ this.addSyntheticArgumentAndField(this.enclosingType);
+ }
+
+ /* Answer the receiver's constant pool name.
+ *
+ * NOTE: This method should only be used during/after code gen.
+ */
+
+ public char[] constantPoolName() /* java/lang/Object */ {
+ if (constantPoolName != null)
+ return constantPoolName;
+
+ return constantPoolName =
+ CharOperation.concat(enclosingType().constantPoolName(), sourceName, '$');
+ }
+
+ public String toString() {
+ return "Member type : " + new String(sourceName()) + " " + super.toString();
+ }
+
+}
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
new file mode 100644
index 0000000000..e92ef4c5c6
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java
@@ -0,0 +1,499 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class MethodBinding
+ extends Binding
+ implements BaseTypes, TypeConstants {
+ public int modifiers;
+ public char[] selector;
+ public TypeBinding returnType;
+ public TypeBinding[] parameters;
+ public ReferenceBinding[] thrownExceptions;
+ public ReferenceBinding declaringClass;
+
+ char[] signature;
+ protected MethodBinding() {
+ }
+
+ public MethodBinding(
+ int modifiers,
+ char[] selector,
+ TypeBinding returnType,
+ TypeBinding[] args,
+ ReferenceBinding[] exceptions,
+ ReferenceBinding declaringClass) {
+ this.modifiers = modifiers;
+ this.selector = selector;
+ this.returnType = returnType;
+ this.parameters = (args == null || args.length == 0) ? NoParameters : args;
+ this.thrownExceptions =
+ (exceptions == null || exceptions.length == 0) ? NoExceptions : exceptions;
+ this.declaringClass = declaringClass;
+
+ // propagate the strictfp & deprecated modifiers
+ if (this.declaringClass != null) {
+ if (this.declaringClass.isStrictfp())
+ if (!(isNative() || isAbstract()))
+ this.modifiers |= AccStrictfp;
+ if (this.declaringClass.isViewedAsDeprecated() && !isDeprecated())
+ this.modifiers |= AccDeprecatedImplicitly;
+ }
+ }
+
+ public MethodBinding(
+ int modifiers,
+ TypeBinding[] args,
+ ReferenceBinding[] exceptions,
+ ReferenceBinding declaringClass) {
+ this(
+ modifiers,
+ ConstructorDeclaration.ConstantPoolName,
+ VoidBinding,
+ args,
+ exceptions,
+ declaringClass);
+ }
+
+ // special API used to change method declaring class for runtime visibility check
+ public MethodBinding(
+ MethodBinding initialMethodBinding,
+ ReferenceBinding declaringClass) {
+ this.modifiers = initialMethodBinding.modifiers;
+ this.selector = initialMethodBinding.selector;
+ this.returnType = initialMethodBinding.returnType;
+ this.parameters = initialMethodBinding.parameters;
+ this.thrownExceptions = initialMethodBinding.thrownExceptions;
+ this.declaringClass = declaringClass;
+ }
+
+ /* Answer true if the argument types & the receiver's parameters are equal
+ */
+
+ public final boolean areParametersEqual(MethodBinding method) {
+ TypeBinding[] args = method.parameters;
+ if (parameters == args)
+ return true;
+
+ int length = parameters.length;
+ if (length != args.length)
+ return false;
+
+ for (int i = 0; i < length; i++)
+ if (parameters[i] != args[i])
+ return false;
+ return true;
+ }
+
+ /* API
+ * Answer the receiver's binding type from Binding.BindingID.
+ */
+
+ public final int bindingType() {
+ return METHOD;
+ }
+
+ /* 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.
+ *
+ * NOTE: This method should ONLY be sent if the receiver is a constructor.
+ *
+ * NOTE: Cannot invoke this method with a compilation unit scope.
+ */
+
+ public final boolean canBeSeenBy(InvocationSite invocationSite, Scope scope) {
+ if (isPublic())
+ return true;
+
+ SourceTypeBinding invocationType = scope.enclosingSourceType();
+ if (invocationType == declaringClass)
+ return true;
+
+ if (isProtected()) {
+ // answer true if the receiver is in the same package as the invocationType
+ if (invocationType.fPackage == declaringClass.fPackage)
+ return true;
+ return invocationSite.isSuperAccess();
+ }
+
+ if (isPrivate()) {
+ // answer true if the invocationType and the declaringClass have a common enclosingType
+ // already know they are not the identical type
+ ReferenceBinding outerInvocationType = invocationType;
+ ReferenceBinding temp = outerInvocationType.enclosingType();
+ while (temp != null) {
+ outerInvocationType = temp;
+ temp = temp.enclosingType();
+ }
+
+ ReferenceBinding outerDeclaringClass = declaringClass;
+ temp = outerDeclaringClass.enclosingType();
+ while (temp != null) {
+ outerDeclaringClass = temp;
+ temp = temp.enclosingType();
+ }
+ return outerInvocationType == outerDeclaringClass;
+ }
+
+ // isDefault()
+ return invocationType.fPackage == declaringClass.fPackage;
+ }
+
+ /* 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.
+ *
+ * NOTE: Cannot invoke this method with a compilation unit scope.
+ */
+
+ public final boolean canBeSeenBy(
+ TypeBinding receiverType,
+ InvocationSite invocationSite,
+ Scope scope) {
+ if (isPublic())
+ return true;
+
+ SourceTypeBinding invocationType = scope.enclosingSourceType();
+ if (invocationType == declaringClass && invocationType == receiverType)
+ return true;
+
+ if (isProtected()) {
+ // answer true if the invocationType is the declaringClass or they are in the same package
+ // OR the invocationType is a subclass of the declaringClass
+ // AND the receiverType is the invocationType or its subclass
+ // OR the method is a static method accessed directly through a type
+ if (invocationType == declaringClass)
+ return true;
+ if (invocationType.fPackage == declaringClass.fPackage)
+ return true;
+ if (declaringClass.isSuperclassOf(invocationType)) {
+ if (invocationSite.isSuperAccess())
+ return true;
+ // receiverType can be an array binding in one case... see if you can change it
+ if (receiverType instanceof ArrayBinding)
+ return false;
+ if (invocationType == receiverType
+ || invocationType.isSuperclassOf((ReferenceBinding) receiverType))
+ return true;
+ if (isStatic())
+ return true; // see 1FMEPDL - return invocationSite.isTypeAccess();
+ }
+ return false;
+ }
+
+ if (isPrivate()) {
+ // answer true if the receiverType is the declaringClass
+ // AND the invocationType and the declaringClass have a common enclosingType
+ if (receiverType != declaringClass)
+ return false;
+
+ if (invocationType != declaringClass) {
+ ReferenceBinding outerInvocationType = invocationType;
+ ReferenceBinding temp = outerInvocationType.enclosingType();
+ while (temp != null) {
+ outerInvocationType = temp;
+ temp = temp.enclosingType();
+ }
+
+ ReferenceBinding outerDeclaringClass = declaringClass;
+ temp = outerDeclaringClass.enclosingType();
+ while (temp != null) {
+ outerDeclaringClass = temp;
+ temp = temp.enclosingType();
+ }
+ if (outerInvocationType != outerDeclaringClass)
+ return false;
+ }
+ return true;
+ }
+
+ // isDefault()
+ if (invocationType.fPackage != declaringClass.fPackage)
+ return false;
+
+ // receiverType can be an array binding in one case... see if you can change it
+ if (receiverType instanceof ArrayBinding)
+ return false;
+ ReferenceBinding type = (ReferenceBinding) receiverType;
+ PackageBinding declaringPackage = declaringClass.fPackage;
+ do {
+ if (declaringClass == type)
+ return true;
+ if (declaringPackage != type.fPackage)
+ return false;
+ } while ((type = type.superclass()) != null);
+ return false;
+ }
+
+ /* Answer the receiver's constant pool name.
+ *
+ * <init> for constructors
+ * <clinit> for clinit methods
+ * or the source name of the method
+ */
+
+ public final char[] constantPoolName() {
+ return selector;
+ }
+
+ public final int getAccessFlags() {
+ return modifiers & AccJustFlag;
+ }
+
+ /* Answer true if the receiver is an abstract method
+ */
+
+ public final boolean isAbstract() {
+ return (modifiers & AccAbstract) != 0;
+ }
+
+ /* Answer true if the receiver is a constructor
+ */
+
+ public final boolean isConstructor() {
+ return selector == ConstructorDeclaration.ConstantPoolName;
+ }
+
+ protected boolean isConstructorRelated() {
+ return isConstructor();
+ }
+
+ /* Answer true if the receiver has default visibility
+ */
+
+ public final boolean isDefault() {
+ return !isPublic() && !isProtected() && !isPrivate();
+ }
+
+ /* Answer true if the receiver is a system generated default abstract method
+ */
+
+ public final boolean isDefaultAbstract() {
+ return (modifiers & AccDefaultAbstract) != 0;
+ }
+
+ /* Answer true if the receiver is a deprecated method
+ */
+
+ public final boolean isDeprecated() {
+ return (modifiers & AccDeprecated) != 0;
+ }
+
+ /* Answer true if the receiver is final and cannot be overridden
+ */
+
+ public final boolean isFinal() {
+ return (modifiers & AccFinal) != 0;
+ }
+
+ /* Answer true if the receiver is a native method
+ */
+
+ public final boolean isNative() {
+ return (modifiers & AccNative) != 0;
+ }
+
+ /* Answer true if the receiver has private visibility
+ */
+
+ public final boolean isPrivate() {
+ return (modifiers & AccPrivate) != 0;
+ }
+
+ /* Answer true if the receiver has protected visibility
+ */
+
+ public final boolean isProtected() {
+ return (modifiers & AccProtected) != 0;
+ }
+
+ /* Answer true if the receiver has public visibility
+ */
+
+ public final boolean isPublic() {
+ return (modifiers & AccPublic) != 0;
+ }
+
+ /* Answer true if the receiver got requested to clear the private modifier
+ * during private access emulation.
+ */
+
+ public final boolean isRequiredToClearPrivateModifier() {
+ return (modifiers & AccClearPrivateModifier) != 0;
+ }
+
+ /* Answer true if the receiver is a static method
+ */
+
+ public final boolean isStatic() {
+ return (modifiers & AccStatic) != 0;
+ }
+
+ /* Answer true if all float operations must adher to IEEE 754 float/double rules
+ */
+
+ public final boolean isStrictfp() {
+ return (modifiers & AccStrictfp) != 0;
+ }
+
+ /* Answer true if the receiver is a synchronized method
+ */
+
+ public final boolean isSynchronized() {
+ return (modifiers & AccSynchronized) != 0;
+ }
+
+ /* Answer true if the receiver has public visibility
+ */
+
+ public final boolean isSynthetic() {
+ return (modifiers & AccSynthetic) != 0;
+ }
+
+ /* Answer true if the receiver's declaring type is deprecated (or any of its enclosing types)
+ */
+
+ public final boolean isViewedAsDeprecated() {
+ return (modifiers & AccDeprecated) != 0
+ || (modifiers & AccDeprecatedImplicitly) != 0;
+ }
+
+ public char[] readableName() /* foo(int, Thread) */ {
+ StringBuffer buffer = new StringBuffer(parameters.length + 1 * 20);
+ if (isConstructor())
+ buffer.append(declaringClass.sourceName());
+ else
+ buffer.append(selector);
+ buffer.append('(');
+ if (parameters != NoParameters) {
+ for (int i = 0, length = parameters.length; i < length; i++) {
+ if (i > 0)
+ buffer.append(", ");
+ buffer.append(parameters[i].sourceName());
+ }
+ }
+ buffer.append(')');
+ return buffer.toString().toCharArray();
+ }
+
+ protected final void selector(char[] selector) {
+ this.selector = selector;
+ this.signature = null;
+ }
+
+ /* Answer the receiver's signature.
+ *
+ * NOTE: This method should only be used during/after code gen.
+ * The signature is cached so if the signature of the return type or any parameter
+ * type changes, the cached state is invalid.
+ */
+
+ public final char[] signature() /* (ILjava/lang/Thread;)Ljava/lang/Object; */ {
+ if (signature != null)
+ return signature;
+
+ StringBuffer buffer = new StringBuffer(parameters.length + 1 * 20);
+ buffer.append('(');
+ if (isConstructorRelated() && declaringClass.isNestedType()) {
+ // take into account the synthetic argument type signatures as well
+ ReferenceBinding[] syntheticArgumentTypes =
+ declaringClass.syntheticEnclosingInstanceTypes();
+ int count = syntheticArgumentTypes == null ? 0 : syntheticArgumentTypes.length;
+ for (int i = 0; i < count; i++)
+ buffer.append(syntheticArgumentTypes[i].signature());
+ SyntheticArgumentBinding[] syntheticArguments =
+ declaringClass.syntheticOuterLocalVariables();
+ count = syntheticArguments == null ? 0 : syntheticArguments.length;
+ for (int i = 0; i < count; i++)
+ buffer.append(syntheticArguments[i].type.signature());
+ }
+ if (parameters != NoParameters)
+ for (int i = 0, length = parameters.length; i < length; i++)
+ buffer.append(parameters[i].signature());
+ buffer.append(')');
+ buffer.append(returnType.signature());
+ return signature = buffer.toString().toCharArray();
+ }
+
+ public final int sourceEnd() {
+ AbstractMethodDeclaration method = sourceMethod();
+ if (method == null)
+ return 0;
+ else
+ return method.sourceEnd;
+ }
+
+ AbstractMethodDeclaration sourceMethod() {
+ SourceTypeBinding sourceType;
+ try {
+ sourceType = (SourceTypeBinding) declaringClass;
+ } catch (ClassCastException e) {
+ return null;
+ }
+
+ AbstractMethodDeclaration[] methods = sourceType.scope.referenceContext.methods;
+ for (int i = methods.length; --i >= 0;)
+ if (this == methods[i].binding)
+ return methods[i];
+ return null;
+ }
+
+ public final int sourceStart() {
+ AbstractMethodDeclaration method = sourceMethod();
+ if (method == null)
+ return 0;
+ else
+ return method.sourceStart;
+ }
+
+ /* During private access emulation, the binding can be requested to loose its
+ * private visibility when the class file is dumped.
+ */
+
+ public final void tagForClearingPrivateModifier() {
+ modifiers |= AccClearPrivateModifier;
+ }
+
+ public String toString() {
+ String s = (returnType != null) ? returnType.debugName() : "NULL TYPE";
+ s += " ";
+ s += (selector != null) ? new String(selector) : "UNNAMED METHOD";
+
+ s += "(";
+ if (parameters != null) {
+ if (parameters != NoParameters) {
+ for (int i = 0, length = parameters.length; i < length; i++) {
+ if (i > 0)
+ s += ", ";
+ s += (parameters[i] != null) ? parameters[i].debugName() : "NULL TYPE";
+ }
+ }
+ } else {
+ s += "NULL PARAMETERS";
+ }
+ s += ") ";
+
+ if (thrownExceptions != null) {
+ if (thrownExceptions != NoExceptions) {
+ s += "throws ";
+ for (int i = 0, length = thrownExceptions.length; i < length; i++) {
+ if (i > 0)
+ s += ", ";
+ s += (thrownExceptions[i] != null)
+ ? thrownExceptions[i].debugName()
+ : "NULL TYPE";
+ }
+ }
+ } else {
+ s += "NULL THROWN EXCEPTIONS";
+ }
+ return s;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java
new file mode 100644
index 0000000000..7a9d7db64c
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java
@@ -0,0 +1,388 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+/**
+ * Particular block scope used for methods, constructors or clinits, representing
+ * its outermost blockscope. Note also that such a scope will be provided to enclose
+ * field initializers subscopes as well.
+ */
+public class MethodScope extends BlockScope {
+ public ReferenceContext referenceContext;
+ public boolean needToCompactLocalVariables;
+ public boolean isStatic; // method modifier or initializer one
+
+ //fields used in the TC process (no real meaning)
+ public static final int NotInFieldDecl = -1; //must be a negative value
+ public boolean isConstructorCall = false; //modified on the fly by the TC
+ public int fieldDeclarationIndex = NotInFieldDecl;
+ //modified on the fly by the TC
+
+ public int analysisIndex; // for setting flow-analysis id
+
+ public boolean isPropagatingInnerClassEmulation;
+
+ // for local variables table attributes
+ public int lastIndex = 0;
+ public long[] definiteInits = new long[4];
+ public long[][] extraDefiniteInits = new long[4][];
+ public MethodScope(
+ ClassScope parent,
+ ReferenceContext context,
+ boolean isStatic) {
+ super(METHOD_SCOPE, parent);
+ locals = new LocalVariableBinding[5];
+ this.referenceContext = context;
+ this.isStatic = isStatic;
+ this.startIndex = 0;
+ }
+
+ String basicToString(int tab) {
+ String newLine = "\n";
+ for (int i = tab; --i >= 0;)
+ newLine += "\t";
+
+ String s = newLine + "--- Method Scope ---";
+ newLine += "\t";
+ s += newLine + "locals:";
+ for (int i = 0; i < localIndex; i++)
+ s += newLine + "\t" + locals[i].toString();
+ s += newLine + "startIndex = " + startIndex;
+ s += newLine + "isConstructorCall = " + isConstructorCall;
+ s += newLine + "fieldDeclarationIndex = " + fieldDeclarationIndex;
+ return s;
+ }
+
+ /* Spec : 8.4.3 & 9.4
+ */
+
+ private void checkAndSetModifiersForConstructor(MethodBinding methodBinding) {
+ int modifiers = methodBinding.modifiers;
+ if ((modifiers & AccAlternateModifierProblem) != 0)
+ problemReporter().duplicateModifierForMethod(
+ methodBinding.declaringClass,
+ (AbstractMethodDeclaration) referenceContext);
+
+ if (((ConstructorDeclaration) referenceContext).isDefaultConstructor) {
+ if (methodBinding.declaringClass.isPublic())
+ modifiers |= AccPublic;
+ else
+ if (methodBinding.declaringClass.isProtected())
+ modifiers |= AccProtected;
+ }
+
+ // after this point, tests on the 16 bits reserved.
+ int realModifiers = modifiers & AccJustFlag;
+
+ // check for abnormal modifiers
+ int unexpectedModifiers =
+ ~(AccPublic | AccPrivate | AccProtected | AccStrictfp);
+ if ((realModifiers & unexpectedModifiers) != 0)
+ problemReporter().illegalModifierForMethod(
+ methodBinding.declaringClass,
+ (AbstractMethodDeclaration) referenceContext);
+ else
+ if ((((AbstractMethodDeclaration) referenceContext).modifiers & AccStrictfp)
+ != 0) // must check the parse node explicitly
+ problemReporter().illegalModifierForMethod(
+ methodBinding.declaringClass,
+ (AbstractMethodDeclaration) referenceContext);
+
+ // check for incompatible modifiers in the visibility bits, isolate the visibility bits
+ int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate);
+ if ((accessorBits & (accessorBits - 1)) != 0) {
+ problemReporter().illegalVisibilityModifierCombinationForMethod(
+ methodBinding.declaringClass,
+ (AbstractMethodDeclaration) referenceContext);
+
+ // need to keep the less restrictive
+ if ((accessorBits & AccPublic) != 0) {
+ if ((accessorBits & AccProtected) != 0)
+ modifiers ^= AccProtected;
+ if ((accessorBits & AccPrivate) != 0)
+ modifiers ^= AccPrivate;
+ }
+ if ((accessorBits & AccProtected) != 0)
+ if ((accessorBits & AccPrivate) != 0)
+ modifiers ^= AccPrivate;
+ }
+
+ // if the receiver's declaring class is a private nested type, then make sure the receiver is not private (causes problems for inner type emulation)
+ if (methodBinding.declaringClass.isPrivate())
+ if ((modifiers & AccPrivate) != 0)
+ modifiers ^= AccPrivate;
+
+ methodBinding.modifiers = modifiers;
+ }
+
+ /* Spec : 8.4.3 & 9.4
+ */
+
+ private void checkAndSetModifiersForMethod(MethodBinding methodBinding) {
+ int modifiers = methodBinding.modifiers;
+ if ((modifiers & AccAlternateModifierProblem) != 0)
+ problemReporter().duplicateModifierForMethod(
+ methodBinding.declaringClass,
+ (AbstractMethodDeclaration) referenceContext);
+
+ // after this point, tests on the 16 bits reserved.
+ int realModifiers = modifiers & AccJustFlag;
+
+ // set the requested modifiers for a method in an interface
+ if (methodBinding.declaringClass.isInterface()) {
+ if ((realModifiers & ~(AccPublic | AccAbstract)) != 0)
+ problemReporter().illegalModifierForInterfaceMethod(
+ methodBinding.declaringClass,
+ (AbstractMethodDeclaration) referenceContext);
+ return;
+ }
+
+ // check for abnormal modifiers
+ int unexpectedModifiers =
+ ~(
+ AccPublic
+ | AccPrivate
+ | AccProtected
+ | AccAbstract
+ | AccStatic
+ | AccFinal
+ | AccSynchronized
+ | AccNative
+ | AccStrictfp);
+ if ((realModifiers & unexpectedModifiers) != 0)
+ problemReporter().illegalModifierForMethod(
+ methodBinding.declaringClass,
+ (AbstractMethodDeclaration) referenceContext);
+
+ // check for incompatible modifiers in the visibility bits, isolate the visibility bits
+ int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate);
+ if ((accessorBits & (accessorBits - 1)) != 0) {
+ problemReporter().illegalVisibilityModifierCombinationForMethod(
+ methodBinding.declaringClass,
+ (AbstractMethodDeclaration) referenceContext);
+
+ // need to keep the less restrictive
+ if ((accessorBits & AccPublic) != 0) {
+ if ((accessorBits & AccProtected) != 0)
+ modifiers ^= AccProtected;
+ if ((accessorBits & AccPrivate) != 0)
+ modifiers ^= AccPrivate;
+ }
+ if ((accessorBits & AccProtected) != 0)
+ if ((accessorBits & AccPrivate) != 0)
+ modifiers ^= AccPrivate;
+ }
+
+ // check for modifiers incompatible with abstract modifier
+ if ((modifiers & AccAbstract) != 0) {
+ int incompatibleWithAbstract =
+ AccPrivate | AccStatic | AccFinal | AccSynchronized | AccNative | AccStrictfp;
+ if ((modifiers & incompatibleWithAbstract) != 0)
+ problemReporter().illegalAbstractModifierCombinationForMethod(
+ methodBinding.declaringClass,
+ (AbstractMethodDeclaration) referenceContext);
+ if (!methodBinding.declaringClass.isAbstract())
+ problemReporter().abstractMethodInAbstractClass(
+ (SourceTypeBinding) methodBinding.declaringClass,
+ (AbstractMethodDeclaration) referenceContext);
+ }
+
+ /* DISABLED for backward compatibility with javac (if enabled should also mark private methods as final)
+ // methods from a final class are final : 8.4.3.3
+ if (methodBinding.declaringClass.isFinal())
+ modifiers |= AccFinal;
+ */
+ // native methods cannot also be tagged as strictfp
+ if ((modifiers & AccNative) != 0 && (modifiers & AccStrictfp) != 0)
+ problemReporter().nativeMethodsCannotBeStrictfp(
+ methodBinding.declaringClass,
+ (AbstractMethodDeclaration) referenceContext);
+
+ // static members are only authorized in a static member or top level type
+ if (((realModifiers & AccStatic) != 0)
+ && methodBinding.declaringClass.isNestedType()
+ && !methodBinding.declaringClass.isStatic())
+ problemReporter().unexpectedStaticModifierForMethod(
+ methodBinding.declaringClass,
+ (AbstractMethodDeclaration) referenceContext);
+
+ methodBinding.modifiers = modifiers;
+ }
+
+ /* Error management:
+ * keep null for all the errors that prevent the method to be created
+ * otherwise return a correct method binding (but without the element
+ * that caused the problem) : ie : Incorrect thrown exception
+ */
+
+ MethodBinding createMethod(AbstractMethodDeclaration method) {
+ // is necessary to ensure error reporting
+ this.referenceContext = method;
+ method.scope = this;
+ SourceTypeBinding declaringClass = referenceType().binding;
+ int modifiers = method.modifiers | AccUnresolved;
+ if (method.isConstructor()) {
+ method.binding = new MethodBinding(modifiers, null, null, declaringClass);
+ checkAndSetModifiersForConstructor(method.binding);
+ } else {
+ if (((MethodDeclaration) method).returnType == null) {
+ problemReporter().missingReturnType(method);
+ return null;
+ }
+ if (declaringClass.isInterface())
+ modifiers |= AccPublic | AccAbstract;
+ method.binding =
+ new MethodBinding(modifiers, method.selector, null, null, null, declaringClass);
+ checkAndSetModifiersForMethod(method.binding);
+ }
+
+ this.isStatic = method.binding.isStatic();
+ return method.binding;
+ }
+
+ /* Overridden to detect the error case inside an explicit constructor call:
+
+ class X {
+ int i;
+ X myX;
+ X(X x) {
+ this(i, myX.i, x.i); // same for super calls... only the first 2 field accesses are errors
+ }
+ }
+
+ */
+
+ public FieldBinding findField(
+ TypeBinding receiverType,
+ char[] fieldName,
+ InvocationSite invocationSite) {
+ FieldBinding field = super.findField(receiverType, fieldName, invocationSite);
+ if (field == null)
+ return null;
+ if (!field.isValidBinding())
+ return field; // answer the error field
+ if (field.isStatic())
+ return field; // static fields are always accessible
+
+ if (!isConstructorCall || receiverType != enclosingSourceType())
+ return field;
+
+ if (invocationSite instanceof SingleNameReference)
+ return new ProblemFieldBinding(
+ fieldName,
+ NonStaticReferenceInConstructorInvocation);
+ if (invocationSite instanceof QualifiedNameReference) {
+ // look to see if the field is the first binding
+ QualifiedNameReference name = (QualifiedNameReference) invocationSite;
+ if (name.binding == null)
+ // only true when the field is the fieldbinding at the beginning of name's tokens
+ return new ProblemFieldBinding(
+ fieldName,
+ NonStaticReferenceInConstructorInvocation);
+ }
+ return field;
+ }
+
+ public boolean isInsideInitializer() {
+ return (referenceContext instanceof TypeDeclaration);
+ }
+
+ public boolean isInsideInitializerOrConstructor() {
+ return (referenceContext instanceof TypeDeclaration)
+ || (referenceContext instanceof ConstructorDeclaration);
+ }
+
+ /* Answer the problem reporter to use for raising new problems.
+ *
+ * Note that as a side-effect, this updates the current reference context
+ * (unit, type or method) in case the problem handler decides it is necessary
+ * to abort.
+ */
+
+ public ProblemReporter problemReporter() {
+ MethodScope outerMethodScope;
+ if ((outerMethodScope = outerMostMethodScope()) == this) {
+ ProblemReporter problemReporter = referenceCompilationUnit().problemReporter;
+ problemReporter.referenceContext = referenceContext;
+ return problemReporter;
+ } else {
+ return outerMethodScope.problemReporter();
+ }
+ }
+
+ public final int recordInitializationStates(FlowInfo flowInfo) {
+ if ((flowInfo == FlowInfo.DeadEnd) || (flowInfo.isFakeReachable())) {
+ return -1;
+ }
+ UnconditionalFlowInfo unconditionalFlowInfo = flowInfo.unconditionalInits();
+ long[] extraInits = unconditionalFlowInfo.extraDefiniteInits;
+ long inits = unconditionalFlowInfo.definiteInits;
+ checkNextEntry : for (int i = lastIndex; --i >= 0;) {
+ if (definiteInits[i] == inits) {
+ long[] otherInits = extraDefiniteInits[i];
+ if ((extraInits != null) && (otherInits != null)) {
+ if (extraInits.length == otherInits.length) {
+ int j, max;
+ for (j = 0, max = extraInits.length; j < max; j++) {
+ if (extraInits[j] != otherInits[j]) {
+ continue checkNextEntry;
+ }
+ }
+ return i;
+ }
+ } else {
+ if ((extraInits == null) && (otherInits == null)) {
+ return i;
+ }
+ }
+ }
+ }
+
+ // add a new entry
+ if (definiteInits.length == lastIndex) {
+ // need a resize
+ System.arraycopy(
+ definiteInits,
+ 0,
+ (definiteInits = new long[lastIndex + 20]),
+ 0,
+ lastIndex);
+ System.arraycopy(
+ extraDefiniteInits,
+ 0,
+ (extraDefiniteInits = new long[lastIndex + 20][]),
+ 0,
+ lastIndex);
+ }
+ definiteInits[lastIndex] = inits;
+ if (extraInits != null) {
+ extraDefiniteInits[lastIndex] = new long[extraInits.length];
+ System.arraycopy(
+ extraInits,
+ 0,
+ extraDefiniteInits[lastIndex],
+ 0,
+ extraInits.length);
+ }
+ return lastIndex++;
+ }
+
+ /* Answer the reference type of this scope.
+ *
+ * i.e. the nearest enclosing type of this scope.
+ */
+
+ public TypeDeclaration referenceType() {
+ return (TypeDeclaration) ((ClassScope) parent).referenceContext;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java
new file mode 100644
index 0000000000..dcb2e79cae
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java
@@ -0,0 +1,983 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.*;
+
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public final class MethodVerifier implements TagBits, TypeConstants {
+ SourceTypeBinding type;
+ HashtableOfObject inheritedMethods;
+ HashtableOfObject currentMethods;
+ ReferenceBinding runtimeException;
+ ReferenceBinding errorException;
+ /*
+ Binding creation is responsible for reporting all problems with types:
+ - all modifier problems (duplicates & multiple visibility modifiers + incompatible combinations - abstract/final)
+ - plus invalid modifiers given the context (the verifier did not do this before)
+ - qualified name collisions between a type and a package (types in default packages are excluded)
+ - all type hierarchy problems:
+ - cycles in the superclass or superinterface hierarchy
+ - an ambiguous, invisible or missing superclass or superinterface
+ - extending a final class
+ - extending an interface instead of a class
+ - implementing a class instead of an interface
+ - implementing the same interface more than once (ie. duplicate interfaces)
+ - with nested types:
+ - shadowing an enclosing type's source name
+ - defining a static class or interface inside a non-static nested class
+ - defining an interface as a local type (local types can only be classes)
+
+ verifyTypeStructure
+
+ | hasHierarchyProblem superclass current names interfaces interfacesByIndentity duplicateExists invalidType |
+
+ (type basicModifiers anyMask: AccModifierProblem | AccAlternateModifierProblem) ifTrue: [
+ self reportModifierProblemsOnType: type].
+
+ type controller isJavaDefaultPackage ifFalse: [
+ (nameEnvironment class doesPackageExistNamed: type javaQualifiedName) ifTrue: [
+ problemSummary
+ reportVerificationProblem: #CollidesWithPackage
+ args: (Array with: type javaQualifiedName)
+ severity: nil
+ forType: type]].
+
+ hasHierarchyProblem := false.
+
+ type isJavaClass
+ ifTrue: [
+ (superclass := self superclassFor: type) ~~ nil ifTrue: [
+ superclass isBuilderClass ifTrue: [
+ superclass := superclass newClass].
+ superclass isJavaMissing
+ ifTrue: [
+ hasHierarchyProblem := true.
+ type javaSuperclassIsMissing ifTrue: [
+ problemSummary
+ reportVerificationProblem: #MissingSuperclass
+ args: (Array with: superclass javaQualifiedName with: superclass unmatchedDescriptor)
+ severity: nil
+ forType: type].
+ type javaSuperclassCreatesCycle ifTrue: [
+ problemSummary
+ reportVerificationProblem: #CyclicSuperclass
+ args: (Array with: superclass javaQualifiedName)
+ severity: nil
+ forType: type].
+ type javaSuperclassIsInterface ifTrue: [
+ problemSummary
+ reportVerificationProblem: #ClassCannotExtendAnInterface
+ args: (Array with: superclass javaQualifiedName)
+ severity: nil
+ forType: type]]
+ ifFalse: [
+ "NOTE: If type is a Java class and its superclass is
+ a valid descriptor then it should NEVER be an interface."
+
+ superclass isJavaFinal ifTrue: [
+ problemSummary
+ reportVerificationProblem: #ClassCannotExtendFinalClass
+ args: nil
+ severity: nil
+ forType: type]]]]
+ ifFalse: [
+ type isJavaLocalType ifTrue: [
+ problemSummary
+ reportVerificationProblem: #CannotDefineLocalInterface
+ args: nil
+ severity: nil
+ forType: type]].
+
+ type isJavaNestedType ifTrue: [
+ (current := type) sourceName notEmpty ifTrue: [
+ names := Set new.
+ [(current := current enclosingType) ~~ nil] whileTrue: [
+ names add: current sourceName].
+
+ (names includes: type sourceName) ifTrue: [
+ problemSummary
+ reportVerificationProblem: #NestedTypeCannotShadowTypeName
+ args: nil
+ severity: nil
+ forType: type]].
+
+ (type enclosingType isJavaNestedType and: [type enclosingType isJavaClass]) ifTrue: [
+ type enclosingType isJavaStatic ifFalse: [
+ type isJavaClass
+ ifTrue: [
+ type isJavaStatic ifTrue: [
+ problemSummary
+ reportVerificationProblem: #StaticClassCannotExistInNestedClass
+ args: nil
+ severity: nil
+ forType: type]]
+ ifFalse: [
+ problemSummary
+ reportVerificationProblem: #InterfaceCannotExistInNestedClass
+ args: nil
+ severity: nil
+ forType: type]]]].
+
+ (interfaces := newClass superinterfaces) notEmpty ifTrue: [
+ interfacesByIndentity := interfaces asSet.
+ duplicateExists := interfaces size ~~ interfacesByIndentity size.
+
+ interfacesByIndentity do: [:interface |
+ duplicateExists ifTrue: [
+ (interfaces occurrencesOf: interface) > 1 ifTrue: [
+ problemSummary
+ reportVerificationProblem: #InterfaceIsSpecifiedMoreThanOnce
+ args: (Array with: interface javaQualifiedName)
+ severity: nil
+ forType: type]].
+
+ interface isJavaMissing ifTrue: [
+ hasHierarchyProblem := true.
+ interface basicClass == JavaInterfaceIsClass basicClass
+ ifTrue: [
+ problemSummary
+ reportVerificationProblem: #UsingClassWhereInterfaceIsRequired
+ args: (Array with: interface javaQualifiedName)
+ severity: nil
+ forType: type]
+ ifFalse: [
+ interface basicClass == JavaMissingInterface basicClass
+ ifTrue: [
+ problemSummary
+ reportVerificationProblem: #MissingInterface
+ args: (Array with: interface javaQualifiedName with: interface unmatchedDescriptor)
+ severity: nil
+ forType: type]
+ ifFalse: [
+ problemSummary
+ reportVerificationProblem: #CyclicSuperinterface
+ args: (Array with: interface javaQualifiedName)
+ severity: nil
+ forType: type]]]]].
+
+ hasHierarchyProblem ifFalse: [
+ "Search up the type's hierarchy for
+ 1. missing superclass,
+ 2. superclass cycle, or
+ 3. superclass is interface."
+ (invalidType := newClass findFirstInvalidSupertypeSkipping: EsIdentitySet new) ~~ nil ifTrue: [
+ problemSummary
+ reportVerificationProblem: #HasHierarchyProblem
+ args: (Array with: invalidType javaReadableName)
+ severity: nil
+ forType: type]]
+
+ reportModifierProblemsOnType: aType
+
+ (type basicModifiers anyMask: AccAlternateModifierProblem) ifTrue: [
+ (type basicModifiers anyMask: AccModifierProblem)
+ ifTrue: [
+ ^problemSummary
+ reportVerificationProblem: #OnlyOneVisibilityModifierAllowed
+ args: nil
+ severity: nil
+ forType: aType]
+ ifFalse: [
+ ^problemSummary
+ reportVerificationProblem: #DuplicateModifier
+ args: nil
+ severity: nil
+ forType: aType]].
+
+ type isJavaInterface ifTrue: [
+ ^problemSummary
+ reportVerificationProblem: #IllegalModifierForInterface
+ args: nil
+ severity: nil
+ forType: aType].
+
+ (type basicModifiers allMask: AccAbstract | AccFinal) ifTrue: [
+ ^problemSummary
+ reportVerificationProblem: #IllegalModifierCombinationAbstractFinal
+ args: nil
+ severity: nil
+ forType: aType].
+
+ ^problemSummary
+ reportVerificationProblem: #IllegalModifierForClass
+ args: nil
+ severity: nil
+ forType: aType
+
+ void reportModifierProblems() {
+ if (this.type.isAbstract() && this.type.isFinal())
+ this.problemReporter.illegalModifierCombinationAbstractFinal(this.type);
+
+ // Should be able to detect all 3 problems NOT just 1
+ if ((type.modifiers() & Modifiers.AccAlternateModifierProblem) == 0) {
+ if (this.type.isInterface())
+ this.problemReporter.illegalModifierForInterface(this.type);
+ else
+ this.problemReporter.illegalModifier(this.type);
+ } else {
+ if ((type.modifiers() & Modifiers.AccModifierProblem) != 0)
+ this.problemReporter.onlyOneVisibilityModifierAllowed(this.type);
+ else
+ this.problemReporter.duplicateModifier(this.type);
+ }
+ }
+
+ */
+ public MethodVerifier(LookupEnvironment environment) {
+ this.type = null;
+ // Initialized with the public method verify(SourceTypeBinding)
+ this.inheritedMethods = null;
+ this.currentMethods = null;
+ this.runtimeException = null;
+ this.errorException = null;
+ }
+
+ private void checkAgainstInheritedMethods(
+ MethodBinding currentMethod,
+ MethodBinding[] methods,
+ int length) {
+ for (int i = length; --i >= 0;) {
+ MethodBinding inheritedMethod = methods[i];
+ if (currentMethod.returnType != inheritedMethod.returnType) {
+ this.problemReporter(currentMethod).incompatibleReturnType(
+ currentMethod,
+ inheritedMethod);
+ } else
+ if (currentMethod.isStatic() != inheritedMethod.isStatic()) {
+ // Cannot override a static method or hide an instance method
+ this.problemReporter(currentMethod).staticAndInstanceConflict(
+ currentMethod,
+ inheritedMethod);
+ } else {
+ if (currentMethod.thrownExceptions != NoExceptions)
+ this.checkExceptions(currentMethod, inheritedMethod);
+ if (inheritedMethod.isFinal())
+ this.problemReporter(currentMethod).finalMethodCannotBeOverridden(
+ currentMethod,
+ inheritedMethod);
+ if (!this.isAsVisible(currentMethod, inheritedMethod))
+ this.problemReporter(currentMethod).visibilityConflict(
+ currentMethod,
+ inheritedMethod);
+ if (inheritedMethod.isViewedAsDeprecated())
+ if (!currentMethod.isViewedAsDeprecated())
+ this.problemReporter(currentMethod).overridesDeprecatedMethod(
+ currentMethod,
+ inheritedMethod);
+ }
+ }
+ }
+
+ /*
+ "8.4.4"
+ Verify that newExceptions are all included in inheritedExceptions.
+ Assumes all exceptions are valid and throwable.
+ Unchecked exceptions (compatible with runtime & error) are ignored (see the spec on pg. 203).
+ */
+
+ private void checkExceptions(
+ MethodBinding newMethod,
+ MethodBinding inheritedMethod) {
+ ReferenceBinding[] newExceptions = newMethod.thrownExceptions;
+ ReferenceBinding[] inheritedExceptions = inheritedMethod.thrownExceptions;
+ for (int i = newExceptions.length; --i >= 0;) {
+ ReferenceBinding newException = newExceptions[i];
+ int j = inheritedExceptions.length;
+ while (--j > -1
+ && !this.isSameClassOrSubclassOf(newException, inheritedExceptions[j]));
+ if (j == -1)
+ if (!(newException.isCompatibleWith(this.runtimeException())
+ || newException.isCompatibleWith(this.errorException())))
+ this.problemReporter(newMethod).incompatibleExceptionInThrowsClause(
+ this.type,
+ newMethod,
+ inheritedMethod,
+ newException);
+ }
+ }
+
+ private void checkInheritedMethods(MethodBinding[] methods, int length) {
+ TypeBinding returnType = methods[0].returnType;
+ int index = length;
+ while ((--index > 0) && (returnType == methods[index].returnType));
+ if (index > 0) { // All inherited methods do NOT have the same vmSignature
+ this.problemReporter().inheritedMethodsHaveIncompatibleReturnTypes(
+ this.type,
+ methods,
+ length);
+ return;
+ }
+
+ MethodBinding concreteMethod = null;
+ for (int i = length;
+ --i >= 0;
+ ) // Remember that only one of the methods can be non-abstract
+ if (!methods[i].isAbstract()) {
+ concreteMethod = methods[i];
+ break;
+ }
+ if (concreteMethod == null) {
+ if (this.type.isClass() && !this.type.isAbstract()) {
+ for (int i = length; --i >= 0;)
+ if (!mustImplementAbstractMethod(methods[i]))
+ return;
+ // in this case, we have already reported problem against the concrete superclass
+ this.problemReporter().abstractMethodMustBeImplemented(this.type, methods[0]);
+ }
+ return;
+ }
+
+ MethodBinding[] abstractMethods = new MethodBinding[length - 1];
+ index = 0;
+ for (int i = length; --i >= 0;)
+ if (methods[i] != concreteMethod)
+ abstractMethods[index++] = methods[i];
+
+ // Remember that interfaces can only define public instance methods
+ if (concreteMethod.isStatic())
+ // Cannot inherit a static method which is specified as an instance method by an interface
+ this.problemReporter().staticInheritedMethodConflicts(
+ type,
+ concreteMethod,
+ abstractMethods);
+ if (!concreteMethod.isPublic())
+ // Cannot reduce visibility of a public method specified by an interface
+ this.problemReporter().inheritedMethodReducesVisibility(
+ type,
+ concreteMethod,
+ abstractMethods);
+ if (concreteMethod.thrownExceptions != NoExceptions)
+ for (int i = abstractMethods.length; --i >= 0;)
+ this.checkExceptions(concreteMethod, abstractMethods[i]);
+ }
+
+ /*
+ For each inherited method identifier (message pattern - vm signature minus the return type)
+ if current method exists
+ if current's vm signature does not match an inherited signature then complain
+ else compare current's exceptions & visibility against each inherited method
+ else
+ if inherited methods = 1
+ if inherited is abstract && type is NOT an interface or abstract, complain
+ else
+ if vm signatures do not match complain
+ else
+ find the concrete implementation amongst the abstract methods (can only be 1)
+ if one exists then
+ it must be a public instance method
+ compare concrete's exceptions against each abstract method
+ else
+ complain about missing implementation only if type is NOT an interface or abstract
+ */
+
+ private void checkMethods() {
+ boolean mustImplementAbstractMethods =
+ this.type.isClass() && !this.type.isAbstract();
+ char[][] methodSelectors = this.inheritedMethods.keyTable;
+ for (int s = methodSelectors.length; --s >= 0;) {
+ if (methodSelectors[s] != null) {
+ MethodBinding[] current =
+ (MethodBinding[]) this.currentMethods.get(methodSelectors[s]);
+ MethodBinding[] inherited =
+ (MethodBinding[]) this.inheritedMethods.valueTable[s];
+
+ int index = -1;
+ MethodBinding[] matchingInherited = new MethodBinding[inherited.length];
+ if (current != null) {
+ for (int i = 0, length1 = current.length; i < length1; i++) {
+ while (index >= 0)
+ matchingInherited[index--] = null;
+ // clear the previous contents of the matching methods
+ MethodBinding currentMethod = current[i];
+ for (int j = 0, length2 = inherited.length; j < length2; j++) {
+ if (inherited[j] != null && currentMethod.areParametersEqual(inherited[j])) {
+ matchingInherited[++index] = inherited[j];
+ inherited[j] = null; // do not want to find it again
+ }
+ }
+ if (index >= 0)
+ this.checkAgainstInheritedMethods(currentMethod, matchingInherited, index + 1);
+ // pass in the length of matching
+ }
+ }
+ for (int i = 0, length = inherited.length; i < length; i++) {
+ while (index >= 0)
+ matchingInherited[index--] = null;
+ // clear the previous contents of the matching methods
+ if (inherited[i] != null) {
+ matchingInherited[++index] = inherited[i];
+ for (int j = i + 1; j < length; j++) {
+ if (inherited[j] != null && inherited[i].areParametersEqual(inherited[j])) {
+ matchingInherited[++index] = inherited[j];
+ inherited[j] = null; // do not want to find it again
+ }
+ }
+ }
+ if (index > 0) {
+ this.checkInheritedMethods(matchingInherited, index + 1);
+ // pass in the length of matching
+ } else {
+ if (mustImplementAbstractMethods
+ && index == 0
+ && matchingInherited[0].isAbstract())
+ if (mustImplementAbstractMethod(matchingInherited[0]))
+ this.problemReporter().abstractMethodMustBeImplemented(
+ this.type,
+ matchingInherited[0]);
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ Binding creation is responsible for reporting:
+ - all modifier problems (duplicates & multiple visibility modifiers + incompatible combinations)
+ - plus invalid modifiers given the context... examples:
+ - interface methods can only be public
+ - abstract methods can only be defined by abstract classes
+ - collisions... 2 methods with identical vmSelectors
+ - multiple methods with the same message pattern but different return types
+ - ambiguous, invisible or missing return/argument/exception types
+ - check the type of any array is not void
+ - check that each exception type is Throwable or a subclass of it
+ */
+ private void computeInheritedMethods() {
+ this.inheritedMethods = new HashtableOfObject(51);
+ // maps method selectors to an array of methods... must search to match paramaters & return type
+ ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][];
+ int lastPosition = 0;
+ interfacesToVisit[lastPosition] = type.superInterfaces();
+
+ if (this.type.isClass()) {
+ ReferenceBinding superType = this.type;
+ MethodBinding[] nonVisibleDefaultMethods = null;
+ int nonVisibleCount = 0;
+
+ while ((superType = superType.superclass()) != null) {
+ if (superType.isValidBinding()) {
+ ReferenceBinding[] itsInterfaces = superType.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(
+ interfacesToVisit,
+ 0,
+ interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
+ 0,
+ lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+
+ MethodBinding[] methods = superType.methods();
+ nextMethod : for (int m = methods.length; --m >= 0;) {
+ MethodBinding method = methods[m];
+ if (!(method.isPrivate()
+ || method.isConstructor()
+ || method.isDefaultAbstract())) {
+ // look at all methods which are NOT private or constructors or default abstract
+ MethodBinding[] existingMethods =
+ (MethodBinding[]) this.inheritedMethods.get(method.selector);
+ if (existingMethods != null)
+ for (int i = 0, length = existingMethods.length; i < length; i++)
+ if (method.returnType == existingMethods[i].returnType)
+ if (method.areParametersEqual(existingMethods[i]))
+ continue nextMethod;
+ if (nonVisibleDefaultMethods != null)
+ for (int i = 0; i < nonVisibleCount; i++)
+ if (method.returnType == nonVisibleDefaultMethods[i].returnType)
+ if (CharOperation
+ .equals(method.selector, nonVisibleDefaultMethods[i].selector))
+ if (method.areParametersEqual(nonVisibleDefaultMethods[i]))
+ continue nextMethod;
+
+ if (!(method.isDefault()
+ && (method.declaringClass.fPackage != type.fPackage))) {
+ // ignore methods which have default visibility and are NOT defined in another package
+ if (existingMethods == null)
+ existingMethods = new MethodBinding[1];
+ else
+ System.arraycopy(
+ existingMethods,
+ 0,
+ (existingMethods = new MethodBinding[existingMethods.length + 1]),
+ 0,
+ existingMethods.length - 1);
+ existingMethods[existingMethods.length - 1] = method;
+ this.inheritedMethods.put(method.selector, existingMethods);
+ } else {
+ if (nonVisibleDefaultMethods == null)
+ nonVisibleDefaultMethods = new MethodBinding[10];
+ else
+ if (nonVisibleCount == nonVisibleDefaultMethods.length)
+ System.arraycopy(
+ nonVisibleDefaultMethods,
+ 0,
+ (nonVisibleDefaultMethods = new MethodBinding[nonVisibleCount * 2]),
+ 0,
+ nonVisibleCount);
+ nonVisibleDefaultMethods[nonVisibleCount++] = method;
+
+ if (method.isAbstract()
+ && !this.type.isAbstract())
+ // non visible abstract methods cannot be overridden so the type must be defined abstract
+ this.problemReporter().abstractMethodCannotBeOverridden(this.type, method);
+
+ MethodBinding[] current =
+ (MethodBinding[]) this.currentMethods.get(method.selector);
+ if (current != null) {
+ // non visible methods cannot be overridden so a warning is issued
+ foundMatch : for (int i = 0, length = current.length; i < length; i++) {
+ if (method.returnType == current[i].returnType) {
+ if (method.areParametersEqual(current[i])) {
+ this.problemReporter().overridesPackageDefaultMethod(current[i], method);
+ break foundMatch;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++) {
+ ReferenceBinding superType = interfaces[j];
+ if ((superType.tagBits & InterfaceVisited) == 0) {
+ superType.tagBits |= InterfaceVisited;
+ if (superType.isValidBinding()) {
+ ReferenceBinding[] itsInterfaces = superType.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(
+ interfacesToVisit,
+ 0,
+ interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
+ 0,
+ lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+
+ MethodBinding[] methods = superType.methods();
+ for (int m = methods.length;
+ --m >= 0;
+ ) { // Interface methods are all abstract public
+ MethodBinding method = methods[m];
+ MethodBinding[] existingMethods =
+ (MethodBinding[]) this.inheritedMethods.get(method.selector);
+ if (existingMethods == null)
+ existingMethods = new MethodBinding[1];
+ else
+ System.arraycopy(
+ existingMethods,
+ 0,
+ (existingMethods = new MethodBinding[existingMethods.length + 1]),
+ 0,
+ existingMethods.length - 1);
+ existingMethods[existingMethods.length - 1] = method;
+ this.inheritedMethods.put(method.selector, existingMethods);
+ }
+ }
+ }
+ }
+ }
+
+ // bit reinitialization
+ for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++)
+ interfaces[j].tagBits &= ~InterfaceVisited;
+ }
+ }
+
+ /*
+ computeInheritedMethodMembers
+
+ "8.4.6.4"
+ "Compute all of the members for the type that are inherited from its supertypes.
+ This includes:
+ All of the methods implemented in the supertype hierarchy that are not overridden.
+ PROBLEM: Currently we do not remove overridden methods in the interface hierarchy.
+ This could cause a non-existent exception error to be detected."
+
+ | supertype allSuperinterfaces methodsSeen interfacesSeen |
+ inheritedMethodMembers := LookupTable new: 50.
+ allSuperinterfaces := OrderedCollection new.
+
+ type isJavaClass ifTrue: [
+ supertype := type.
+ methodsSeen := EsIdentitySet new: 20.
+ [(supertype := self superclassFor: supertype) == nil] whileFalse: [
+ (supertype isBuilderClass or: [supertype isValidDescriptor]) ifTrue: [
+ allSuperinterfaces addAll: (self superinterfacesFor: supertype).
+ supertype javaUserDefinedMethodsDo: [:method |
+ (method isJavaPrivate or: [method isJavaConstructor]) ifFalse: [
+ (method isJavaDefault and: [method declaringClass package symbol ~= type package symbol]) ifFalse: [
+ (methodsSeen includes: method selector) ifFalse: [
+ methodsSeen add: method selector.
+ (inheritedMethodMembers
+ at: (self methodSignatureFor: method selector)
+ ifAbsentPut: [OrderedCollection new: 3])
+ add: method]]]]]]].
+
+ allSuperinterfaces addAll: (self superinterfacesFor: type).
+ interfacesSeen := EsIdentitySet new: allSuperinterfaces size * 2.
+ [allSuperinterfaces notEmpty] whileTrue: [
+ supertype := allSuperinterfaces removeFirst.
+ (interfacesSeen includes: supertype) ifFalse: [
+ interfacesSeen add: supertype.
+ (supertype isBuilderClass or: [supertype isValidDescriptor]) ifTrue: [
+ allSuperinterfaces addAll: (self superinterfacesFor: supertype).
+ supertype javaUserDefinedMethodsDo: [:method | "Interface methods are all abstract public."
+ (inheritedMethodMembers
+ at: (self methodSignatureFor: method selector)
+ ifAbsentPut: [OrderedCollection new: 3])
+ add: method]]]]
+ */
+ private void computeMethods() {
+ MethodBinding[] methods = type.methods();
+ int size = methods.length;
+ this.currentMethods = new HashtableOfObject(size == 0 ? 1 : size);
+ // maps method selectors to an array of methods... must search to match paramaters & return type
+ for (int m = size; --m >= 0;) {
+ MethodBinding method = methods[m];
+ if (!(method.isConstructor()
+ || method.isDefaultAbstract())) {
+ // keep all methods which are NOT constructors or default abstract
+ MethodBinding[] existingMethods =
+ (MethodBinding[]) this.currentMethods.get(method.selector);
+ if (existingMethods == null)
+ existingMethods = new MethodBinding[1];
+ else
+ System.arraycopy(
+ existingMethods,
+ 0,
+ (existingMethods = new MethodBinding[existingMethods.length + 1]),
+ 0,
+ existingMethods.length - 1);
+ existingMethods[existingMethods.length - 1] = method;
+ this.currentMethods.put(method.selector, existingMethods);
+ }
+ }
+ }
+
+ private ReferenceBinding errorException() {
+ if (errorException == null)
+ this.errorException = this.type.scope.getJavaLangError();
+ return errorException;
+ }
+
+ private boolean isAsVisible(
+ MethodBinding newMethod,
+ MethodBinding inheritedMethod) {
+ if (inheritedMethod.modifiers == newMethod.modifiers)
+ return true;
+
+ if (newMethod.isPublic())
+ return true; // Covers everything
+ if (inheritedMethod.isPublic())
+ return false;
+
+ if (newMethod.isProtected())
+ return true;
+ if (inheritedMethod.isProtected())
+ return false;
+
+ return !newMethod.isPrivate();
+ // The inheritedMethod cannot be private since it would not be visible
+ }
+
+ private boolean isSameClassOrSubclassOf(
+ ReferenceBinding testClass,
+ ReferenceBinding superclass) {
+ do {
+ if (testClass == superclass)
+ return true;
+ } while ((testClass = testClass.superclass()) != null);
+ return false;
+ }
+
+ private boolean mustImplementAbstractMethod(MethodBinding abstractMethod) {
+ // if the type's superclass is an abstract class, then all abstract methods must be implemented
+ // otherwise, skip it if the type's superclass must implement any of the inherited methods
+ ReferenceBinding superclass = this.type.superclass();
+ ReferenceBinding declaringClass = abstractMethod.declaringClass;
+ if (declaringClass.isClass()) {
+ while (superclass.isAbstract() && superclass != declaringClass)
+ superclass = superclass.superclass();
+ // find the first concrete superclass or the abstract declaringClass
+ } else {
+ if (this.type.implementsInterface(declaringClass, false))
+ return !this.type.isAbstract();
+ while (superclass.isAbstract()
+ && !superclass.implementsInterface(declaringClass, false))
+ superclass = superclass.superclass();
+ // find the first concrete superclass or the superclass which implements the interface
+ }
+ return superclass.isAbstract();
+ // if it is a concrete class then we have already reported problem against it
+ }
+
+ private ProblemReporter problemReporter() {
+ return this.type.scope.problemReporter();
+ }
+
+ private ProblemReporter problemReporter(MethodBinding currentMethod) {
+ ProblemReporter reporter = problemReporter();
+ if (currentMethod.declaringClass == type)
+ // only report against the currentMethod if its implemented by the type
+ reporter.referenceContext = currentMethod.sourceMethod();
+ return reporter;
+ }
+
+ private ReferenceBinding runtimeException() {
+ if (runtimeException == null)
+ this.runtimeException = this.type.scope.getJavaLangRuntimeException();
+ return runtimeException;
+ }
+
+ public void verify(SourceTypeBinding type) {
+ this.type = type;
+ this.computeMethods();
+ this.computeInheritedMethods();
+ this.checkMethods();
+ }
+
+ private void zzFieldProblems() {
+ }
+
+ /*
+ Binding creation is responsible for reporting all problems with fields:
+ - all modifier problems (duplicates & multiple visibility modifiers + incompatible combinations - final/volatile)
+ - plus invalid modifiers given the context (the verifier did not do this before)
+ - include initializers in the modifier checks even though bindings are not created
+ - collisions... 2 fields with same name
+ - interfaces cannot define initializers
+ - nested types cannot define static fields
+ - with the type of the field:
+ - void is not a valid type (or for an array)
+ - an ambiguous, invisible or missing type
+
+ verifyFields
+
+ | toSearch |
+ (toSearch := newClass fields) notEmpty ifTrue: [
+ newClass fromJavaClassFile
+ ifTrue: [
+ toSearch do: [:field |
+ field isJavaInitializer ifFalse: [
+ self verifyFieldType: field]]]
+ ifFalse: [
+ toSearch do: [:field |
+ field isJavaInitializer
+ ifTrue: [self verifyFieldInitializer: field]
+ ifFalse: [self verifyField: field]]]]
+
+ verifyFieldInitializer: field
+
+ type isJavaInterface
+ ifTrue: [
+ problemSummary
+ reportVerificationProblem: #InterfacesCannotHaveInitializers
+ args: #()
+ severity: nil
+ forField: field]
+ ifFalse: [
+ field isJavaStatic
+ ifTrue: [
+ field modifiers == AccStatic ifFalse: [
+ problemSummary
+ reportVerificationProblem: #IllegalModifierForStaticInitializer
+ args: #()
+ severity: nil
+ forField: field]]
+ ifFalse: [
+ field modifiers == 0 ifFalse: [
+ problemSummary
+ reportVerificationProblem: #IllegalModifierForInitializer
+ args: #()
+ severity: nil
+ forField: field]]]
+
+ verifyField: field
+
+ (field basicModifiers anyMask: AccAlternateModifierProblem | AccModifierProblem) ifTrue: [
+ self reportModifierProblemsOnField: field].
+
+ field isJavaStatic ifTrue: [
+ type isJavaStatic ifFalse: [
+ (type isJavaNestedType and: [type isJavaClass]) ifTrue: [
+ problemSummary
+ reportVerificationProblem: #NestedClassCannotHaveStaticField
+ args: #()
+ severity: nil
+ forField: field]]].
+
+ self verifyFieldType: field
+
+ verifyFieldType: field
+
+ | descriptor fieldType |
+ "8.3 (Class) 9.3 (Interface)"
+ "Optimize the base type case"
+ field typeIsBaseType
+ ifTrue: [
+ field typeName = 'V' ifTrue: [ "$NON-NLS$"
+ problemSummary
+ reportVerificationProblem: #IllegalTypeForField
+ args: (Array with: JavaVoid)
+ severity: nil
+ forField: field]]
+ ifFalse: [
+ descriptor := field asDescriptorIn: nameEnvironment.
+ (fieldType := descriptor type) isValidDescriptor
+ ifTrue: [
+ (fieldType isArrayType and: [fieldType leafComponentType isVoidType]) ifTrue: [
+ problemSummary
+ reportVerificationProblem: #InvalidArrayType
+ args: (Array with: fieldType javaReadableName)
+ severity: nil
+ forField: field]]
+ ifFalse: [
+ problemSummary
+ reportVerificationProblem: #UnboundTypeForField
+ args: (Array with: fieldType javaReadableName with: fieldType leafComponentType)
+ severity: nil
+ forField: field]].
+
+ reportModifierProblemsOnField: field
+
+ (field basicModifiers anyMask: AccAlternateModifierProblem) ifTrue: [
+ (field basicModifiers anyMask: AccModifierProblem)
+ ifTrue: [
+ ^problemSummary
+ reportVerificationProblem: #OnlyOneVisibilityModifierAllowed
+ args: #()
+ severity: ErrorInfo::ConflictingModifier
+ forField: field]
+ ifFalse: [
+ ^problemSummary
+ reportVerificationProblem: #DuplicateModifier
+ args: #()
+ severity: ErrorInfo::ConflictingModifier
+ forField: field]].
+
+ type isJavaInterface ifTrue: [
+ ^problemSummary
+ reportVerificationProblem: #IllegalModifierForInterfaceField
+ args: #()
+ severity: nil
+ forField: field].
+
+ (field basicModifiers allMask: AccFinal | AccVolatile) ifTrue: [
+ ^problemSummary
+ reportVerificationProblem: #IllegalModifierCombinationFinalVolatile
+ args: #()
+ severity: nil
+ forField: field].
+
+ ^problemSummary
+ reportVerificationProblem: #IllegalModifierForField
+ args: #()
+ severity: nil
+ forField: field
+
+ void reportModifierProblems(FieldBinding field) {
+ if (field.isFinal() && field.isVolatile())
+ this.problemReporter.illegalModifierCombinationFinalVolatile(field);
+
+ // Should be able to detect all 3 problems NOT just 1
+ if ((type.modifiers() & Modifiers.AccAlternateModifierProblem) == 0) {
+ if (this.type.isInterface())
+ this.problemReporter.illegalModifierForInterfaceField(field);
+ else
+ this.problemReporter.illegalModifier(field);
+ } else {
+ if ((field.modifiers & Modifiers.AccModifierProblem) != 0)
+ this.problemReporter.onlyOneVisibilityModifierAllowed(field);
+ else
+ this.problemReporter.duplicateModifier(field);
+ }
+ }
+
+ */
+ private void zzImportProblems() {
+ }
+
+ /*
+ Binding creation is responsible for reporting all problems with imports:
+ - on demand imports which refer to missing packages
+ - with single type imports:
+ - resolves to an ambiguous, invisible or missing type
+ - conflicts with the type's source name
+ - has the same simple name as another import
+
+ Note: VAJ ignored duplicate imports (only one was kept)
+
+ verifyImports
+
+ | importsBySimpleName nameEnvClass imports cl first |
+ importsBySimpleName := LookupTable new.
+ nameEnvClass := nameEnvironment class.
+
+ "7.5.2"
+ type imports do: [:import |
+ import isOnDemand
+ ifTrue: [
+ (nameEnvClass doesPackageExistNamed: import javaPackageName) ifFalse: [
+ (nameEnvClass findJavaClassNamedFrom: import javaPackageName) == nil ifTrue: [
+ problemSummary
+ reportVerificationProblem: #OnDemandImportRefersToMissingPackage
+ args: (Array with: import asString)
+ severity: ErrorInfo::ImportVerification
+ forType: type]]]
+ ifFalse: [
+ (imports := importsBySimpleName at: import javaSimpleName ifAbsent: []) == nil
+ ifTrue: [
+ importsBySimpleName at: import javaSimpleName put: (Array with: import)]
+ ifFalse: [
+ (imports includes: import) ifFalse: [
+ importsBySimpleName at: import javaSimpleName put: imports, (Array with: import)]].
+
+ "Ignore any imports which are simple names - we will treat these as no-ops."
+
+ import javaPackageName notEmpty ifTrue: [
+ cl := nameEnvClass findJavaClassNamedFrom: import asString.
+
+ (cl ~~ nil and: [cl isJavaPublic or: [cl controller symbol == type controller symbol]]) ifFalse: [
+ problemSummary
+ reportVerificationProblem: #SingleTypeImportRefersToInvisibleType
+ args: (Array with: import asString)
+ severity: ErrorInfo::ImportVerification
+ forType: type]]]].
+
+ importsBySimpleName notEmpty ifTrue: [
+ importsBySimpleName keysAndValuesDo: [:simpleName :matching |
+ matching size == 1
+ ifTrue: [
+ simpleName = type sourceName ifTrue: [
+ matching first javaReadableName = type javaReadableName ifFalse: [
+ problemSummary
+ reportVerificationProblem: #SingleTypeImportConflictsWithType
+ args: #()
+ severity: nil
+ forType: type]]]
+ ifFalse: [
+ problemSummary
+ reportVerificationProblem: #SingleTypeImportsHaveSameSimpleName
+ args: (Array with: simpleName)
+ severity: nil
+ forType: type]]]
+ */
+ private void zzTypeProblems() {
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java
new file mode 100644
index 0000000000..b271ca3e7b
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java
@@ -0,0 +1,239 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class NestedTypeBinding extends SourceTypeBinding {
+ public SourceTypeBinding enclosingType;
+
+ public SyntheticArgumentBinding[] enclosingInstances;
+ public SyntheticArgumentBinding[] outerLocalVariables;
+ public int syntheticArgumentsOffset;
+ // amount of slots used by synthetic constructor arguments
+ public NestedTypeBinding(
+ char[][] typeName,
+ ClassScope scope,
+ SourceTypeBinding enclosingType) {
+ super(typeName, enclosingType.fPackage, scope);
+ this.tagBits |= IsNestedType;
+ this.enclosingType = enclosingType;
+ }
+
+ /* Add a new synthetic argument for <actualOuterLocalVariable>.
+ * Answer the new argument or the existing argument if one already existed.
+ */
+
+ public SyntheticArgumentBinding addSyntheticArgument(LocalVariableBinding actualOuterLocalVariable) {
+ SyntheticArgumentBinding synthLocal = null;
+
+ if (outerLocalVariables == null) {
+ synthLocal = new SyntheticArgumentBinding(actualOuterLocalVariable);
+ outerLocalVariables = new SyntheticArgumentBinding[] { synthLocal };
+ } else {
+ int size = outerLocalVariables.length;
+ int newArgIndex = size;
+ for (int i = size; --i >= 0;) { // must search backwards
+ if (outerLocalVariables[i].actualOuterLocalVariable
+ == actualOuterLocalVariable)
+ return outerLocalVariables[i]; // already exists
+ if (outerLocalVariables[i].id > actualOuterLocalVariable.id)
+ newArgIndex = i;
+ }
+ SyntheticArgumentBinding[] synthLocals = new SyntheticArgumentBinding[size + 1];
+ System.arraycopy(outerLocalVariables, 0, synthLocals, 0, newArgIndex);
+ synthLocals[newArgIndex] =
+ synthLocal = new SyntheticArgumentBinding(actualOuterLocalVariable);
+ System.arraycopy(
+ outerLocalVariables,
+ newArgIndex,
+ synthLocals,
+ newArgIndex + 1,
+ size - newArgIndex);
+ outerLocalVariables = synthLocals;
+ }
+ //System.out.println("Adding synth arg for local var: " + new String(actualOuterLocalVariable.name) + " to: " + new String(this.readableName()));
+ if (scope.referenceCompilationUnit().isPropagatingInnerClassEmulation)
+ this.updateInnerEmulationDependents();
+ return synthLocal;
+ }
+
+ /* Add a new synthetic argument for <enclosingType>.
+ * Answer the new argument or the existing argument if one already existed.
+ */
+
+ public SyntheticArgumentBinding addSyntheticArgument(ReferenceBinding enclosingType) {
+ SyntheticArgumentBinding synthLocal = null;
+ if (enclosingInstances == null) {
+ synthLocal = new SyntheticArgumentBinding(enclosingType);
+ enclosingInstances = new SyntheticArgumentBinding[] { synthLocal };
+ } else {
+ int size = enclosingInstances.length;
+ int newArgIndex = size;
+ for (int i = size; --i >= 0;) {
+ if (enclosingInstances[i].type == enclosingType)
+ return enclosingInstances[i]; // already exists
+ if (this.enclosingType() == enclosingType)
+ newArgIndex = 0;
+ }
+ SyntheticArgumentBinding[] newInstances =
+ new SyntheticArgumentBinding[size + 1];
+ System.arraycopy(
+ enclosingInstances,
+ 0,
+ newInstances,
+ newArgIndex == 0 ? 1 : 0,
+ size);
+ newInstances[newArgIndex] =
+ synthLocal = new SyntheticArgumentBinding(enclosingType);
+ enclosingInstances = newInstances;
+ }
+ //System.out.println("Adding synth arg for enclosing type: " + new String(enclosingType.readableName()) + " to: " + new String(this.readableName()));
+ if (scope.referenceCompilationUnit().isPropagatingInnerClassEmulation)
+ this.updateInnerEmulationDependents();
+ return synthLocal;
+ }
+
+ /* Add a new synthetic argument and field for <actualOuterLocalVariable>.
+ * Answer the new argument or the existing argument if one already existed.
+ */
+
+ public SyntheticArgumentBinding addSyntheticArgumentAndField(LocalVariableBinding actualOuterLocalVariable) {
+ SyntheticArgumentBinding synthLocal =
+ addSyntheticArgument(actualOuterLocalVariable);
+ if (synthLocal == null)
+ return null;
+
+ if (synthLocal.matchingField == null)
+ synthLocal.matchingField = addSyntheticField(actualOuterLocalVariable);
+ return synthLocal;
+ }
+
+ /* Add a new synthetic argument and field for <enclosingType>.
+ * Answer the new argument or the existing argument if one already existed.
+ */
+
+ public SyntheticArgumentBinding addSyntheticArgumentAndField(ReferenceBinding enclosingType) {
+ SyntheticArgumentBinding synthLocal = addSyntheticArgument(enclosingType);
+ if (synthLocal == null)
+ return null;
+
+ if (synthLocal.matchingField == null)
+ synthLocal.matchingField = addSyntheticField(enclosingType);
+ return synthLocal;
+ }
+
+ /**
+ * Compute the resolved positions for all the synthetic arguments
+ */
+ final public void computeSyntheticArgumentsOffset() {
+
+ int position = 1; // inside constructor, reserve room for receiver
+
+ // insert enclosing instances first, followed by the outerLocals
+ SyntheticArgumentBinding[] enclosingInstances =
+ this.syntheticEnclosingInstances();
+ int enclosingInstancesCount =
+ enclosingInstances == null ? 0 : enclosingInstances.length;
+ for (int i = 0; i < enclosingInstancesCount; i++) {
+ SyntheticArgumentBinding syntheticArg = enclosingInstances[i];
+ syntheticArg.resolvedPosition = position;
+ if ((syntheticArg.type == LongBinding)
+ || (syntheticArg.type == DoubleBinding)) {
+ position += 2;
+ } else {
+ position++;
+ }
+ }
+ SyntheticArgumentBinding[] outerLocals = this.syntheticOuterLocalVariables();
+ int outerLocalsCount = outerLocals == null ? 0 : outerLocals.length;
+ for (int i = 0; i < outerLocalsCount; i++) {
+ SyntheticArgumentBinding syntheticArg = outerLocals[i];
+ syntheticArg.resolvedPosition = position;
+ if ((syntheticArg.type == LongBinding)
+ || (syntheticArg.type == DoubleBinding)) {
+ position += 2;
+ } else {
+ position++;
+ }
+ }
+ this.syntheticArgumentsOffset = position;
+ }
+
+ /* Answer the receiver's enclosing type... null if the receiver is a top level type.
+ */
+
+ public ReferenceBinding enclosingType() {
+ return enclosingType;
+ }
+
+ /* Answer the synthetic argument for <actualOuterLocalVariable> or null if one does not exist.
+ */
+
+ public SyntheticArgumentBinding getSyntheticArgument(LocalVariableBinding actualOuterLocalVariable) {
+ if (outerLocalVariables == null)
+ return null; // is null if no outer local variables are known
+
+ for (int i = outerLocalVariables.length; --i >= 0;)
+ if (outerLocalVariables[i].actualOuterLocalVariable
+ == actualOuterLocalVariable)
+ return outerLocalVariables[i];
+ return null;
+ }
+
+ /* Answer the synthetic argument for <targetEnclosingType> or null if one does not exist.
+ */
+
+ public SyntheticArgumentBinding getSyntheticArgument(
+ ReferenceBinding targetEnclosingType,
+ BlockScope scope) {
+ if (enclosingInstances == null)
+ return null; // is null if no enclosing instances are known
+
+ // exact match
+ for (int i = enclosingInstances.length; --i >= 0;)
+ if (enclosingInstances[i].type == targetEnclosingType)
+ if (enclosingInstances[i].actualOuterLocalVariable == null)
+ return enclosingInstances[i];
+
+ // type compatibility : to handle cases such as
+ // class T { class M{}}
+ // class S extends T { class N extends M {}} --> need to use S as a default enclosing instance for the super constructor call in N().
+ for (int i = enclosingInstances.length; --i >= 0;)
+ if (enclosingInstances[i].actualOuterLocalVariable == null)
+ if (targetEnclosingType
+ .isSuperclassOf((ReferenceBinding) enclosingInstances[i].type))
+ return enclosingInstances[i];
+ return null;
+ }
+
+ public SyntheticArgumentBinding[] syntheticEnclosingInstances() {
+ return enclosingInstances; // is null if no enclosing instances are required
+ }
+
+ public ReferenceBinding[] syntheticEnclosingInstanceTypes() {
+ if (enclosingInstances == null)
+ return null;
+
+ int length = enclosingInstances.length;
+ ReferenceBinding types[] = new ReferenceBinding[length];
+ for (int i = 0; i < length; i++)
+ types[i] = (ReferenceBinding) enclosingInstances[i].type;
+ return types;
+ }
+
+ public SyntheticArgumentBinding[] syntheticOuterLocalVariables() {
+ return outerLocalVariables; // is null if no enclosing instances are required
+ }
+
+ /*
+ * Trigger the dependency mechanism forcing the innerclass emulation
+ * to be propagated to all dependent source types.
+ */
+ public void updateInnerEmulationDependents() {
+ // nothing to do in general, only local types are doing anything
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java
new file mode 100644
index 0000000000..14d9a675c6
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java
@@ -0,0 +1,225 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class PackageBinding extends Binding implements TypeConstants {
+ public char[][] compoundName;
+ PackageBinding parent;
+ LookupEnvironment environment;
+ HashtableOfType knownTypes;
+ HashtableOfPackage knownPackages;
+ protected PackageBinding() {
+ }
+
+ public PackageBinding(
+ char[][] compoundName,
+ PackageBinding parent,
+ LookupEnvironment environment) {
+ this.compoundName = compoundName;
+ this.parent = parent;
+ this.environment = environment;
+ this.knownTypes = null;
+ // initialized if used... class counts can be very large 300-600
+ this.knownPackages = new HashtableOfPackage(3);
+ // sub-package counts are typically 0-3
+ }
+
+ public PackageBinding(
+ char[] topLevelPackageName,
+ LookupEnvironment environment) {
+ this(new char[][] { topLevelPackageName }, null, environment);
+ }
+
+ /* Create the default package.
+ */
+
+ public PackageBinding(LookupEnvironment environment) {
+ this(NoCharChar, null, environment);
+ }
+
+ private void addNotFoundPackage(char[] simpleName) {
+ knownPackages.put(simpleName, environment.theNotFoundPackage);
+ }
+
+ private void addNotFoundType(char[] simpleName) {
+ if (knownTypes == null)
+ knownTypes = new HashtableOfType(25);
+ knownTypes.put(simpleName, environment.theNotFoundType);
+ }
+
+ void addPackage(PackageBinding element) {
+ knownPackages.put(
+ element.compoundName[element.compoundName.length - 1],
+ element);
+ }
+
+ void addType(ReferenceBinding element) {
+ if (knownTypes == null)
+ knownTypes = new HashtableOfType(25);
+ knownTypes.put(element.compoundName[element.compoundName.length - 1], element);
+ }
+
+ /* API
+ * Answer the receiver's binding type from Binding.BindingID.
+ */
+
+ public final int bindingType() {
+ return PACKAGE;
+ }
+
+ private PackageBinding findPackage(char[] name) {
+ if (!environment.isPackage(this.compoundName, name))
+ return null;
+
+ char[][] compoundName = CharOperation.arrayConcat(this.compoundName, name);
+ PackageBinding newPackageBinding =
+ new PackageBinding(compoundName, this, environment);
+ addPackage(newPackageBinding);
+ return newPackageBinding;
+ }
+
+ /* Answer the subpackage named name; ask the oracle for the package if its not in the cache.
+ * Answer null if it could not be resolved.
+ *
+ * NOTE: This should only be used when we know there is NOT a type with the same name.
+ */
+
+ PackageBinding getPackage(char[] name) {
+ PackageBinding binding = getPackage0(name);
+ if (binding != null) {
+ if (binding == environment.theNotFoundPackage)
+ return null;
+ else
+ return binding;
+ }
+ if ((binding = findPackage(name)) != null)
+ return binding;
+
+ // not found so remember a problem package binding in the cache for future lookups
+ addNotFoundPackage(name);
+ return null;
+ }
+
+ /* Answer the subpackage named name if it exists in the cache.
+ * Answer theNotFoundPackage if it could not be resolved the first time
+ * it was looked up, otherwise answer null.
+ *
+ * NOTE: Senders must convert theNotFoundPackage into a real problem
+ * package if its to returned.
+ */
+
+ PackageBinding getPackage0(char[] name) {
+ return knownPackages.get(name);
+ }
+
+ /* Answer the type named name; ask the oracle for the type if its not in the cache.
+ * Answer a NotVisible problem type if the type is not visible from the invocationPackage.
+ * Answer null if it could not be resolved.
+ *
+ * NOTE: This should only be used by source types/scopes which know there is NOT a
+ * package with the same name.
+ */
+
+ ReferenceBinding getType(char[] name) {
+ ReferenceBinding binding = getType0(name);
+ if (binding == null) {
+ if ((binding = environment.askForType(this, name)) == null) {
+ // not found so remember a problem type binding in the cache for future lookups
+ addNotFoundType(name);
+ return null;
+ }
+ }
+
+ if (binding == environment.theNotFoundType)
+ return null;
+ if (binding instanceof UnresolvedReferenceBinding)
+ binding = ((UnresolvedReferenceBinding) binding).resolve(environment);
+ if (binding.isNestedType())
+ return new ProblemReferenceBinding(name, InternalNameProvided);
+ return binding;
+ }
+
+ /* Answer the type named name if it exists in the cache.
+ * Answer theNotFoundType if it could not be resolved the first time
+ * it was looked up, otherwise answer null.
+ *
+ * NOTE: Senders must convert theNotFoundType into a real problem
+ * reference type if its to returned.
+ */
+
+ ReferenceBinding getType0(char[] name) {
+ if (knownTypes == null)
+ return null;
+ return knownTypes.get(name);
+ }
+
+ /* Answer the package or type named name; ask the oracle if it is not in the cache.
+ * Answer null if it could not be resolved.
+ *
+ * When collisions exist between a type name & a package name, answer the package.
+ * Treat the type as if it does not exist... a problem was already reported when the type was defined.
+ *
+ * NOTE: no visibility checks are performed.
+ * THIS SHOULD ONLY BE USED BY SOURCE TYPES/SCOPES.
+ */
+
+ public Binding getTypeOrPackage(char[] name) {
+ PackageBinding packageBinding = getPackage0(name);
+ if (packageBinding != null && packageBinding != environment.theNotFoundPackage)
+ return packageBinding;
+
+ ReferenceBinding typeBinding = getType0(name);
+ if (typeBinding != null && typeBinding != environment.theNotFoundType) {
+ if (typeBinding instanceof UnresolvedReferenceBinding)
+ typeBinding = ((UnresolvedReferenceBinding) typeBinding).resolve(environment);
+ if (typeBinding.isNestedType())
+ return new ProblemReferenceBinding(name, InternalNameProvided);
+ return typeBinding;
+ }
+
+ if (typeBinding == null && packageBinding == null) {
+ // find the package
+ if ((packageBinding = findPackage(name)) != null)
+ return packageBinding;
+
+ // if no package was found, find the type named name relative to the receiver
+ if ((typeBinding = environment.askForType(this, name)) != null) {
+ if (typeBinding.isNestedType())
+ return new ProblemReferenceBinding(name, InternalNameProvided);
+ return typeBinding;
+ }
+
+ // Since name could not be found, add problem bindings
+ // to the collections so it will be reported as an error next time.
+ addNotFoundPackage(name);
+ addNotFoundType(name);
+ } else {
+ if (packageBinding == environment.theNotFoundPackage)
+ packageBinding = null;
+ if (typeBinding == environment.theNotFoundType)
+ typeBinding = null;
+ }
+
+ if (packageBinding != null)
+ return packageBinding;
+ else
+ return typeBinding;
+ }
+
+ public char[] readableName() /*java.lang*/ {
+ return CharOperation.concatWith(compoundName, '.');
+ }
+
+ public String toString() {
+ if (compoundName == NoCharChar)
+ return "The Default Package";
+ else
+ return "package "
+ + ((compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED");
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemBinding.java
new file mode 100644
index 0000000000..b9835c8b81
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemBinding.java
@@ -0,0 +1,59 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class ProblemBinding extends Binding {
+ public char[] name;
+ public ReferenceBinding searchType;
+ private int problemId;
+ // NOTE: must only answer the subset of the name related to the problem
+
+ public ProblemBinding(char[][] compoundName, int problemId) {
+ this(CharOperation.concatWith(compoundName, '.'), problemId);
+ }
+
+ // NOTE: must only answer the subset of the name related to the problem
+
+ public ProblemBinding(
+ char[][] compoundName,
+ ReferenceBinding searchType,
+ int problemId) {
+ this(CharOperation.concatWith(compoundName, '.'), searchType, problemId);
+ }
+
+ ProblemBinding(char[] name, int problemId) {
+ this.name = name;
+ this.problemId = problemId;
+ }
+
+ ProblemBinding(char[] name, ReferenceBinding searchType, int problemId) {
+ this(name, problemId);
+ this.searchType = searchType;
+ }
+
+ /* API
+ * Answer the receiver's binding type from Binding.BindingID.
+ */
+
+ public final int bindingType() {
+ return VARIABLE | TYPE;
+ }
+
+ /* API
+ * Answer the problem id associated with the receiver.
+ * NoError if the receiver is a valid binding.
+ */
+
+ public final int problemId() {
+ return problemId;
+ }
+
+ public char[] readableName() {
+ return name;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemFieldBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemFieldBinding.java
new file mode 100644
index 0000000000..796d7240a8
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemFieldBinding.java
@@ -0,0 +1,31 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class ProblemFieldBinding extends FieldBinding {
+ private int problemId;
+ // NOTE: must only answer the subset of the name related to the problem
+
+ public ProblemFieldBinding(char[][] compoundName, int problemId) {
+ this(CharOperation.concatWith(compoundName, '.'), problemId);
+ }
+
+ public ProblemFieldBinding(char[] name, int problemId) {
+ this.name = name;
+ this.problemId = problemId;
+ }
+
+ /* API
+ * Answer the problem id associated with the receiver.
+ * NoError if the receiver is a valid binding.
+ */
+
+ public final int problemId() {
+ return problemId;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemMethodBinding.java
new file mode 100644
index 0000000000..ccea7f8add
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemMethodBinding.java
@@ -0,0 +1,44 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+public class ProblemMethodBinding extends MethodBinding {
+ private int problemId;
+ public MethodBinding closestMatch;
+ public ProblemMethodBinding(
+ char[] selector,
+ TypeBinding[] args,
+ int problemId) {
+ this.selector = selector;
+ this.parameters = (args == null || args.length == 0) ? NoParameters : args;
+ this.problemId = problemId;
+ }
+
+ public ProblemMethodBinding(
+ char[] selector,
+ TypeBinding[] args,
+ ReferenceBinding declaringClass,
+ int problemId) {
+ this.selector = selector;
+ this.parameters = (args == null || args.length == 0) ? NoParameters : args;
+ this.declaringClass = declaringClass;
+ this.problemId = problemId;
+ }
+
+ public ProblemMethodBinding(
+ MethodBinding closestMatch,
+ char[] selector,
+ TypeBinding[] args,
+ int problemId) {
+ this(selector, args, problemId);
+ this.closestMatch = closestMatch;
+ }
+
+ /* API
+ * Answer the problem id associated with the receiver.
+ * NoError if the receiver is a valid binding.
+ */
+
+ public final int problemId() {
+ return problemId;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemPackageBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemPackageBinding.java
new file mode 100644
index 0000000000..d7f8e52d7d
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemPackageBinding.java
@@ -0,0 +1,25 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+public class ProblemPackageBinding extends PackageBinding {
+ private int problemId;
+ // NOTE: must only answer the subset of the name related to the problem
+
+ ProblemPackageBinding(char[][] compoundName, int problemId) {
+ this.compoundName = compoundName;
+ this.problemId = problemId;
+ }
+
+ ProblemPackageBinding(char[] name, int problemId) {
+ this(new char[][] { name }, problemId);
+ }
+
+ /* API
+ * Answer the problem id associated with the receiver.
+ * NoError if the receiver is a valid binding.
+ */
+
+ public final int problemId() {
+ return problemId;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReasons.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReasons.java
new file mode 100644
index 0000000000..84c0b8b09b
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReasons.java
@@ -0,0 +1,13 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+public interface ProblemReasons {
+ final int NoError = 0;
+ final int NotFound = 1;
+ final int NotVisible = 2;
+ final int Ambiguous = 3;
+ final int InternalNameProvided = 4;
+ // used if an internal name is used in source
+ final int InheritedNameHidesEnclosingName = 5;
+ final int NonStaticReferenceInConstructorInvocation = 6;
+ final int NonStaticReferenceInStaticContext = 7;
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java
new file mode 100644
index 0000000000..ed5bff017b
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java
@@ -0,0 +1,25 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+public class ProblemReferenceBinding extends ReferenceBinding {
+ private int problemId;
+ // NOTE: must only answer the subset of the name related to the problem
+
+ public ProblemReferenceBinding(char[][] compoundName, int problemId) {
+ this.compoundName = compoundName;
+ this.problemId = problemId;
+ }
+
+ public ProblemReferenceBinding(char[] name, int problemId) {
+ this(new char[][] { name }, problemId);
+ }
+
+ /* API
+ * Answer the problem id associated with the receiver.
+ * NoError if the receiver is a valid binding.
+ */
+
+ public final int problemId() {
+ return problemId;
+ }
+
+}
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
new file mode 100644
index 0000000000..2a9087f916
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
@@ -0,0 +1,648 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+/*
+Not all fields defined by this type (& its subclasses) are initialized when it is created.
+Some are initialized only when needed.
+
+Accessors have been provided for some public fields so all TypeBindings have the same API...
+but access public fields directly whenever possible.
+Non-public fields have accessors which should be used everywhere you expect the field to be initialized.
+
+null is NOT a valid value for a non-public field... it just means the field is not initialized.
+*/
+
+abstract public class ReferenceBinding
+ extends TypeBinding
+ implements IDependent {
+ public char[][] compoundName;
+ public char[] sourceName;
+ public int modifiers;
+ public PackageBinding fPackage;
+
+ char[] fileName;
+ char[] constantPoolName;
+ char[] signature;
+ /* Answer true if the receiver can be instantiated
+ */
+
+ public boolean canBeInstantiated() {
+ return !(isAbstract() || isInterface());
+ }
+
+ /* Answer true if the receiver is visible to the invocationPackage.
+ */
+
+ public final boolean canBeSeenBy(PackageBinding invocationPackage) {
+ if (isPublic())
+ return true;
+ if (isPrivate())
+ return false;
+
+ // isProtected() or isDefault()
+ return invocationPackage == fPackage;
+ }
+
+ /* Answer true if the receiver is visible to the receiverType and the invocationType.
+ */
+
+ public final boolean canBeSeenBy(
+ ReferenceBinding receiverType,
+ SourceTypeBinding invocationType) {
+ if (isPublic())
+ return true;
+
+ if (invocationType == this && invocationType == receiverType)
+ return true;
+
+ if (isProtected()) {
+ // answer true if the invocationType is the receiver (or its enclosingType) or they are in the same package
+ // OR the invocationType is a subclass of the enclosingType
+ // AND the receiverType is the invocationType or its subclass
+ if (invocationType == this)
+ return true;
+ if (invocationType.fPackage == fPackage)
+ return true;
+ ReferenceBinding declaringClass = enclosingType();
+ if (declaringClass != null) {
+ // could be null if incorrect top-level protected type
+ if (invocationType == declaringClass)
+ return true;
+ if (declaringClass.isSuperclassOf(invocationType))
+ return invocationType == receiverType
+ || invocationType.isSuperclassOf(receiverType);
+ }
+ return false;
+ }
+
+ if (isPrivate()) {
+ // answer true if the receiverType is the receiver or its enclosingType
+ // AND the invocationType and the receiver have a common enclosingType
+ if (!(receiverType == this || receiverType == enclosingType()))
+ return false;
+
+ if (invocationType != this) {
+ ReferenceBinding outerInvocationType = invocationType;
+ ReferenceBinding temp = outerInvocationType.enclosingType();
+ while (temp != null) {
+ outerInvocationType = temp;
+ temp = temp.enclosingType();
+ }
+
+ ReferenceBinding outerDeclaringClass = this;
+ temp = outerDeclaringClass.enclosingType();
+ while (temp != null) {
+ outerDeclaringClass = temp;
+ temp = temp.enclosingType();
+ }
+ if (outerInvocationType != outerDeclaringClass)
+ return false;
+ }
+ return true;
+ }
+
+ // isDefault()
+ if (invocationType.fPackage != fPackage)
+ return false;
+
+ ReferenceBinding type = receiverType;
+ ReferenceBinding declaringClass =
+ enclosingType() == null ? this : enclosingType();
+ do {
+ if (declaringClass == type)
+ return true;
+ if (fPackage != type.fPackage)
+ return false;
+ } while ((type = type.superclass()) != null);
+ return false;
+ }
+
+ /* Answer true if the receiver is visible to the type provided by the scope.
+ *
+ * NOTE: Cannot invoke this method with a compilation unit scope.
+ */
+
+ public final boolean canBeSeenBy(Scope scope) {
+ if (isPublic())
+ return true;
+
+ SourceTypeBinding invocationType = scope.enclosingSourceType();
+ if (invocationType == this)
+ return true;
+
+ if (isProtected()) {
+ // answer true if the receiver (or its enclosing type) is the superclass
+ // of the invocationType or in the same package
+ return invocationType.fPackage == fPackage
+ || isSuperclassOf(invocationType)
+ || enclosingType().isSuperclassOf(invocationType);
+ // protected types always have an enclosing one
+ }
+
+ if (isPrivate()) {
+ // answer true if the receiver and the invocationType have a common enclosingType
+ // already know they are not the identical type
+ ReferenceBinding outerInvocationType = invocationType;
+ ReferenceBinding temp = outerInvocationType.enclosingType();
+ while (temp != null) {
+ outerInvocationType = temp;
+ temp = temp.enclosingType();
+ }
+
+ ReferenceBinding outerDeclaringClass = this;
+ temp = outerDeclaringClass.enclosingType();
+ while (temp != null) {
+ outerDeclaringClass = temp;
+ temp = temp.enclosingType();
+ }
+ return outerInvocationType == outerDeclaringClass;
+ }
+
+ // isDefault()
+ return invocationType.fPackage == fPackage;
+ }
+
+ public void computeId() {
+ if (compoundName.length != 3) {
+ if (compoundName.length == 4
+ && CharOperation.equals(JAVA_LANG_REFLECT_CONSTRUCTOR, compoundName)) {
+ id = T_JavaLangReflectConstructor;
+ return;
+ }
+ return; // all other types are in java.*.*
+ }
+
+ if (!CharOperation.equals(JAVA, compoundName[0]))
+ return; // assumes we only look up types in java
+
+ if (!CharOperation.equals(LANG, compoundName[1])) {
+ if (CharOperation.equals(JAVA_IO_PRINTSTREAM, compoundName)) {
+ id = T_JavaIoPrintStream;
+ return;
+ }
+ return; // all other types are in java.lang
+ }
+
+ if (CharOperation.equals(JAVA_LANG_OBJECT, compoundName)) {
+ id = T_JavaLangObject;
+ return;
+ }
+ if (CharOperation.equals(JAVA_LANG_STRING, compoundName)) {
+ id = T_JavaLangString;
+ return;
+ }
+
+ // well-known exception types
+ if (CharOperation.equals(JAVA_LANG_THROWABLE, compoundName)) {
+ id = T_JavaLangThrowable;
+ return;
+ }
+ if (CharOperation.equals(JAVA_LANG_ERROR, compoundName)) {
+ id = T_JavaLangError;
+ return;
+ }
+ if (CharOperation.equals(JAVA_LANG_EXCEPTION, compoundName)) {
+ id = T_JavaLangException;
+ return;
+ }
+ if (CharOperation.equals(JAVA_LANG_CLASSNOTFOUNDEXCEPTION, compoundName)) {
+ id = T_JavaLangClassNotFoundException;
+ return;
+ }
+ if (CharOperation.equals(JAVA_LANG_NOCLASSDEFERROR, compoundName)) {
+ id = T_JavaLangNoClassDefError;
+ return;
+ }
+
+ // other well-known types
+ if (CharOperation.equals(JAVA_LANG_CLASS, compoundName)) {
+ id = T_JavaLangClass;
+ return;
+ }
+ if (CharOperation.equals(JAVA_LANG_STRINGBUFFER, compoundName)) {
+ id = T_JavaLangStringBuffer;
+ return;
+ }
+ if (CharOperation.equals(JAVA_LANG_SYSTEM, compoundName)) {
+ id = T_JavaLangSystem;
+ return;
+ }
+
+ if (CharOperation.equals(JAVA_LANG_INTEGER, compoundName)) {
+ id = T_JavaLangInteger;
+ return;
+ }
+
+ if (CharOperation.equals(JAVA_LANG_BYTE, compoundName)) {
+ id = T_JavaLangByte;
+ return;
+ }
+
+ if (CharOperation.equals(JAVA_LANG_CHARACTER, compoundName)) {
+ id = T_JavaLangCharacter;
+ return;
+ }
+
+ if (CharOperation.equals(JAVA_LANG_FLOAT, compoundName)) {
+ id = T_JavaLangFloat;
+ return;
+ }
+
+ if (CharOperation.equals(JAVA_LANG_DOUBLE, compoundName)) {
+ id = T_JavaLangDouble;
+ return;
+ }
+
+ if (CharOperation.equals(JAVA_LANG_BOOLEAN, compoundName)) {
+ id = T_JavaLangBoolean;
+ return;
+ }
+
+ if (CharOperation.equals(JAVA_LANG_SHORT, compoundName)) {
+ id = T_JavaLangShort;
+ return;
+ }
+
+ if (CharOperation.equals(JAVA_LANG_LONG, compoundName)) {
+ id = T_JavaLangLong;
+ return;
+ }
+
+ if (CharOperation.equals(JAVA_LANG_VOID, compoundName)) {
+ id = T_JavaLangVoid;
+ return;
+ }
+ }
+
+ /* Answer the receiver's constant pool name.
+ *
+ * NOTE: This method should only be used during/after code gen.
+ */
+
+ public char[] constantPoolName() /* java/lang/Object */ {
+ if (constantPoolName != null)
+ return constantPoolName;
+
+ return constantPoolName = CharOperation.concatWith(compoundName, '/');
+ }
+
+ String debugName() {
+ return (compoundName != null) ? new String(readableName()) : "UNNAMED TYPE";
+ }
+
+ public final int depth() {
+ int depth = 0;
+ ReferenceBinding current = this;
+ while ((current = current.enclosingType()) != null)
+ depth++;
+ return depth;
+ }
+
+ /* Answer the receiver's enclosing type... null if the receiver is a top level type.
+ */
+
+ public ReferenceBinding enclosingType() {
+ return null;
+ }
+
+ public final ReferenceBinding enclosingTypeAt(int relativeDepth) {
+ ReferenceBinding current = this;
+ while (relativeDepth-- > 0 && current != null)
+ current = current.enclosingType();
+ return current;
+ }
+
+ public int fieldCount() {
+ return fields().length;
+ }
+
+ public FieldBinding[] fields() {
+ return NoFields;
+ }
+
+ public final int getAccessFlags() {
+ return modifiers & AccJustFlag;
+ }
+
+ public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) {
+ return null;
+ }
+
+ public MethodBinding getExactMethod(
+ char[] selector,
+ TypeBinding[] argumentTypes) {
+ return null;
+ }
+
+ public FieldBinding getField(char[] fieldName) {
+ return null;
+ }
+
+ /**
+ * Answer the file name which defines the type.
+ *
+ * The path part (optional) must be separated from the actual
+ * file proper name by a java.io.File.separator.
+ *
+ * The proper file name includes the suffix extension (e.g. ".java")
+ *
+ * e.g. "c:/com/ibm/compiler/java/api/Compiler.java"
+ */
+
+ public char[] getFileName() {
+ return fileName;
+ }
+
+ public ReferenceBinding getMemberType(char[] typeName) {
+ ReferenceBinding[] memberTypes = memberTypes();
+ for (int i = memberTypes.length; --i >= 0;)
+ if (CharOperation.equals(memberTypes[i].sourceName, typeName))
+ return memberTypes[i];
+ return null;
+ }
+
+ public MethodBinding[] getMethods(char[] selector) {
+ return NoMethods;
+ }
+
+ public PackageBinding getPackage() {
+ return fPackage;
+ }
+
+ /* Answer true if the receiver implements anInterface or is identical to anInterface.
+ * If searchHierarchy is true, then also search the receiver's superclasses.
+ *
+ * NOTE: Assume that anInterface is an interface.
+ */
+
+ public boolean implementsInterface(
+ ReferenceBinding anInterface,
+ boolean searchHierarchy) {
+ if (this == anInterface)
+ return true;
+
+ ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][];
+ int lastPosition = -1;
+ ReferenceBinding currentType = this;
+ do {
+ ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(
+ interfacesToVisit,
+ 0,
+ interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
+ 0,
+ lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+ } while (searchHierarchy && (currentType = currentType.superclass()) != null);
+
+ for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++) {
+ if ((currentType = interfaces[j]) == anInterface)
+ return true;
+
+ ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(
+ interfacesToVisit,
+ 0,
+ interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
+ 0,
+ lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+ }
+ }
+ return false;
+ }
+
+ // Internal method... assume its only sent to classes NOT interfaces
+
+ boolean implementsMethod(MethodBinding method) {
+ ReferenceBinding type = this;
+ while (type != null) {
+ MethodBinding[] methods = type.getMethods(method.selector);
+ for (int i = methods.length; --i >= 0;)
+ if (methods[i].areParametersEqual(method))
+ return true;
+ type = type.superclass();
+ }
+ return false;
+ }
+
+ /* Answer true if the receiver is an abstract type
+ */
+
+ public final boolean isAbstract() {
+ return (modifiers & AccAbstract) != 0;
+ }
+
+ public final boolean isAnonymousType() {
+ return (tagBits & IsAnonymousType) != 0;
+ }
+
+ public final boolean isBinaryBinding() {
+ return (tagBits & IsBinaryBinding) != 0;
+ }
+
+ public final boolean isClass() {
+ return (modifiers & AccInterface) == 0;
+ }
+
+ /* Answer true if the receiver type can be assigned to the argument type (right)
+ */
+
+ boolean isCompatibleWith(TypeBinding right) {
+ if (right == this)
+ return true;
+ if (right.id == T_Object)
+ return true;
+ if (!(right instanceof ReferenceBinding))
+ return false;
+
+ ReferenceBinding referenceBinding = (ReferenceBinding) right;
+ if (referenceBinding.isInterface())
+ return implementsInterface(referenceBinding, true);
+ if (isInterface())
+ // Explicit conversion from an interface to a class is not allowed
+ return false;
+ return referenceBinding.isSuperclassOf(this);
+ }
+
+ /* Answer true if the receiver has default visibility
+ */
+
+ public final boolean isDefault() {
+ return !isPublic() && !isProtected() && !isPrivate();
+ }
+
+ /* Answer true if the receiver is a deprecated type
+ */
+
+ public final boolean isDeprecated() {
+ return (modifiers & AccDeprecated) != 0;
+ }
+
+ /* Answer true if the receiver is final and cannot be subclassed
+ */
+
+ public final boolean isFinal() {
+ return (modifiers & AccFinal) != 0;
+ }
+
+ public final boolean isInterface() {
+ return (modifiers & AccInterface) != 0;
+ }
+
+ public final boolean isLocalType() {
+ return (tagBits & IsLocalType) != 0;
+ }
+
+ public final boolean isMemberType() {
+ return (tagBits & IsMemberType) != 0;
+ }
+
+ public final boolean isNestedType() {
+ return (tagBits & IsNestedType) != 0;
+ }
+
+ /* Answer true if the receiver has private visibility
+ */
+
+ public final boolean isPrivate() {
+ return (modifiers & AccPrivate) != 0;
+ }
+
+ /* Answer true if the receiver has protected visibility
+ */
+
+ public final boolean isProtected() {
+ return (modifiers & AccProtected) != 0;
+ }
+
+ /* Answer true if the receiver has public visibility
+ */
+
+ public final boolean isPublic() {
+ return (modifiers & AccPublic) != 0;
+ }
+
+ /* Answer true if the receiver is a static member type
+ */
+
+ public final boolean isStatic() {
+ return (modifiers & AccStatic) != 0 || (tagBits & IsNestedType) == 0;
+ }
+
+ /* Answer true if all float operations must adher to IEEE 754 float/double rules
+ */
+
+ public final boolean isStrictfp() {
+ return (modifiers & AccStrictfp) != 0;
+ }
+
+ /* Answer true if the receiver is in the superclass hierarchy of aType
+ *
+ * NOTE: Object.isSuperclassOf(Object) -> false
+ */
+
+ public boolean isSuperclassOf(ReferenceBinding type) {
+ do {
+ if (this == (type = type.superclass()))
+ return true;
+ } while (type != null);
+
+ return false;
+ }
+
+ /* Answer true if the receiver is deprecated (or any of its enclosing types)
+ */
+
+ public final boolean isViewedAsDeprecated() {
+ return (modifiers & AccDeprecated) != 0
+ || (modifiers & AccDeprecatedImplicitly) != 0;
+ }
+
+ public ReferenceBinding[] memberTypes() {
+ return NoMemberTypes;
+ }
+
+ public MethodBinding[] methods() {
+ return NoMethods;
+ }
+
+ /**
+ * Answer the source name for the type.
+ * In the case of member types, as the qualified name from its top level type.
+ * For example, for a member type N defined inside M & A: "A.M.N".
+ */
+
+ public char[] qualifiedSourceName() {
+ if (isMemberType()) {
+ return CharOperation.concat(
+ enclosingType().qualifiedSourceName(),
+ sourceName(),
+ '.');
+ } else {
+ return sourceName();
+ }
+ }
+
+ public char[] readableName() /*java.lang.Object*/ {
+ if (isMemberType())
+ return CharOperation.concat(enclosingType().readableName(), sourceName, '.');
+ else
+ return CharOperation.concatWith(compoundName, '.');
+ }
+
+ /* Answer the receiver's signature.
+ *
+ * NOTE: This method should only be used during/after code gen.
+ */
+
+ public char[] signature() /* Ljava/lang/Object; */ {
+ if (signature != null)
+ return signature;
+
+ return signature = CharOperation.concat('L', constantPoolName(), ';');
+ }
+
+ public char[] sourceName() {
+ return sourceName;
+ }
+
+ public ReferenceBinding superclass() {
+ return null;
+ }
+
+ public ReferenceBinding[] superInterfaces() {
+ return NoSuperInterfaces;
+ }
+
+ public ReferenceBinding[] syntheticEnclosingInstanceTypes() {
+ if (isStatic())
+ return null;
+
+ ReferenceBinding enclosingType = enclosingType();
+ if (enclosingType == null)
+ return null;
+ else
+ return new ReferenceBinding[] { enclosingType };
+ }
+
+ public SyntheticArgumentBinding[] syntheticOuterLocalVariables() {
+ return null; // is null if no enclosing instances are required
+ }
+
+}
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
new file mode 100644
index 0000000000..aba6c98c2b
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
@@ -0,0 +1,1064 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public abstract class Scope implements BaseTypes, BindingIds, CompilerModifiers, ProblemReasons, TagBits, TypeConstants, TypeIds {
+ public Scope parent;
+ public int kind;
+
+ public final static int BLOCK_SCOPE = 1;
+ public final static int METHOD_SCOPE = 2;
+ public final static int CLASS_SCOPE = 3;
+ public final static int COMPILATION_UNIT_SCOPE = 4;
+protected Scope(int kind, Scope parent) {
+ this.kind = kind;
+ this.parent = parent;
+}
+// Internal use only
+
+protected final boolean areParametersAssignable(TypeBinding[] parameters, TypeBinding[] arguments) {
+ if (parameters == arguments)
+ return true;
+
+ int length = parameters.length;
+ if (length != arguments.length)
+ return false;
+
+ for (int i = 0; i < length; i++)
+ if (parameters[i] != arguments[i])
+ if (!arguments[i].isCompatibleWith(parameters[i]))
+ return false;
+ return true;
+}
+/* Answer true if the left type can be assigned to right
+*/
+
+public boolean areTypesCompatible(TypeBinding left, TypeBinding right) {
+ return left.isCompatibleWith(right);
+}
+/* Answer an int describing the relationship between the given types.
+*
+* NotRelated
+* EqualOrMoreSpecific : left is compatible with right
+* MoreGeneric : right is compatible with left
+*/
+
+public int compareTypes(TypeBinding left, TypeBinding right) {
+ if (areTypesCompatible(left, right))
+ return EqualOrMoreSpecific;
+ if (areTypesCompatible(right, left))
+ return MoreGeneric;
+ return NotRelated;
+}
+/* Answer an int describing the relationship between the given type and unchecked exceptions.
+*
+* NotRelated
+* EqualOrMoreSpecific : type is known for sure to be an unchecked exception type
+* MoreGeneric : type is a supertype of an actual unchecked exception type
+*/
+
+public int compareUncheckedException(ReferenceBinding type) {
+ int comparison = compareTypes(type, getJavaLangRuntimeException());
+ if (comparison != 0)
+ return comparison;
+ else
+ return compareTypes(type, getJavaLangError());
+}
+public final CompilationUnitScope compilationUnitScope() {
+ Scope lastScope = null;
+ Scope scope = this;
+ do {
+ lastScope = scope;
+ scope = scope.parent;
+ } while (scope != null);
+ return (CompilationUnitScope) lastScope;
+}
+public ArrayBinding createArray(TypeBinding type, int dimension) {
+ if (type.isValidBinding())
+ return environment().createArrayType(type, dimension);
+ else
+ return new ArrayBinding(type, dimension);
+}
+/* Answer the receiver's enclosing source type.
+*/
+
+public final SourceTypeBinding enclosingSourceType() {
+ Scope scope = this;
+ do {
+ if (scope instanceof ClassScope)
+ return ((ClassScope) scope).referenceContext.binding;
+ scope = scope.parent;
+ } while (scope != null);
+ return null;
+}
+public final LookupEnvironment environment() {
+ Scope scope, unitScope = this;
+ while ((scope = unitScope.parent) != null)
+ unitScope = scope;
+ return ((CompilationUnitScope) unitScope).environment;
+}
+// Internal use only
+
+public ReferenceBinding findDirectMemberType(char[] typeName, ReferenceBinding enclosingType) {
+ if ((enclosingType.tagBits & HasNoMemberTypes) != 0)
+ return null; // know it has no member types (nor inherited member types)
+
+ SourceTypeBinding enclosingSourceType = enclosingSourceType();
+ compilationUnitScope().addTypeReference(enclosingType);
+ ReferenceBinding memberType = enclosingType.getMemberType(typeName);
+ if (memberType != null) {
+ compilationUnitScope().addTypeReference(memberType);
+ if (enclosingSourceType == null
+ ? memberType.canBeSeenBy(getCurrentPackage())
+ : memberType.canBeSeenBy(enclosingType, enclosingSourceType))
+ return memberType;
+ else
+ return new ProblemReferenceBinding(typeName, NotVisible);
+ }
+ return null;
+}
+// Internal use only
+
+public MethodBinding findExactMethod(ReferenceBinding receiverType, char[] selector, TypeBinding[] argumentTypes, InvocationSite invocationSite) {
+ compilationUnitScope().addTypeReference(receiverType);
+ compilationUnitScope().addTypeReferences(argumentTypes);
+ MethodBinding exactMethod = receiverType.getExactMethod(selector, argumentTypes);
+ if (exactMethod != null){
+ compilationUnitScope().addTypeReferences(exactMethod.thrownExceptions);
+ if (receiverType.isInterface() || exactMethod.canBeSeenBy(receiverType, invocationSite, this))
+ return exactMethod;
+ }
+ return null;
+}
+// Internal use only
+
+/* Answer the field binding that corresponds to fieldName.
+ Start the lookup at the receiverType.
+ InvocationSite implements
+ isSuperAccess(); this is used to determine if the discovered field is visible.
+ Only fields defined by the receiverType or its supertypes are answered;
+ a field of an enclosing type will not be found using this API.
+
+ If no visible field is discovered, null is answered.
+*/
+
+public FieldBinding findField(TypeBinding receiverType, char[] fieldName, InvocationSite invocationSite) {
+ if (receiverType.isBaseType())
+ return null;
+ if (receiverType.isArrayType()) {
+ if (CharOperation.equals(fieldName, LENGTH))
+ return ArrayBinding.LengthField;
+ return null;
+ }
+
+ ReferenceBinding currentType = (ReferenceBinding) receiverType;
+ if (!currentType.canBeSeenBy(this))
+ return new ProblemFieldBinding(fieldName, NotVisible); // *** Need a new problem id - TypeNotVisible?
+
+ compilationUnitScope().addTypeReference(currentType);
+ FieldBinding field = currentType.getField(fieldName);
+ if (field != null) {
+ if (field.canBeSeenBy(currentType, invocationSite, this))
+ return field;
+ else
+ return new ProblemFieldBinding(fieldName, NotVisible);
+ }
+
+ // collect all superinterfaces of receiverType until the field is found in a supertype
+ ReferenceBinding[][] interfacesToVisit = null;
+ int lastPosition = -1;
+ FieldBinding visibleField = null;
+ boolean keepLooking = true;
+ boolean notVisible = false; // we could hold onto the not visible field for extra error reporting
+ while (keepLooking) {
+ ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (interfacesToVisit == null)
+ interfacesToVisit = new ReferenceBinding[5][];
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+ if ((currentType = currentType.superclass()) == null)
+ break;
+
+ if ((field = currentType.getField(fieldName)) != null) {
+ keepLooking = false;
+ if (field.canBeSeenBy(receiverType, invocationSite, this)) {
+ if (visibleField == null)
+ visibleField = field;
+ else
+ return new ProblemFieldBinding(fieldName, Ambiguous);
+ } else {
+ notVisible = true;
+ }
+ }
+ }
+
+ // walk all visible interfaces to find ambiguous references
+ if (interfacesToVisit != null) {
+ ProblemFieldBinding ambiguous = null;
+ done : for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++) {
+ ReferenceBinding anInterface = interfaces[j];
+ if ((anInterface.tagBits & InterfaceVisited) == 0) { // if interface as not already been visited
+ anInterface.tagBits |= InterfaceVisited;
+ if ((field = anInterface.getField(fieldName)) != null) {
+ if (visibleField == null) {
+ visibleField = field;
+ } else {
+ ambiguous = new ProblemFieldBinding(fieldName, Ambiguous);
+ break done;
+ }
+ } else {
+ ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+ }
+ }
+ }
+ }
+
+ // bit reinitialization
+ for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++)
+ interfaces[j].tagBits &= ~InterfaceVisited;
+ }
+ if (ambiguous != null) return ambiguous;
+ }
+
+ if (visibleField != null)
+ return visibleField;
+ if (notVisible)
+ return new ProblemFieldBinding(fieldName, NotVisible);
+ return null;
+}
+// Internal use only
+
+public ReferenceBinding findMemberType(char[] typeName, ReferenceBinding enclosingType) {
+ if ((enclosingType.tagBits & HasNoMemberTypes) != 0)
+ return null; // know it has no member types (nor inherited member types)
+
+ SourceTypeBinding enclosingSourceType = enclosingSourceType();
+ PackageBinding currentPackage = getCurrentPackage();
+ compilationUnitScope().addTypeReference(enclosingType);
+ ReferenceBinding memberType = enclosingType.getMemberType(typeName);
+ if (memberType != null) {
+ compilationUnitScope().addTypeReference(memberType);
+ if (enclosingSourceType == null
+ ? memberType.canBeSeenBy(currentPackage)
+ : memberType.canBeSeenBy(enclosingType, enclosingSourceType))
+ return memberType;
+ else
+ return new ProblemReferenceBinding(typeName, NotVisible);
+ }
+
+ // collect all superinterfaces of receiverType until the memberType is found in a supertype
+ ReferenceBinding currentType = enclosingType;
+ ReferenceBinding[][] interfacesToVisit = null;
+ int lastPosition = -1;
+ ReferenceBinding visibleMemberType = null;
+ boolean keepLooking = true;
+ boolean notVisible = false; // we could hold onto the not visible field for extra error reporting
+ while (keepLooking) {
+ ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (interfacesToVisit == null)
+ interfacesToVisit = new ReferenceBinding[5][];
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+ if ((currentType = currentType.superclass()) == null)
+ break;
+
+ compilationUnitScope().addTypeReference(currentType);
+ if ((memberType = currentType.getMemberType(typeName)) != null) {
+ compilationUnitScope().addTypeReference(memberType);
+ keepLooking = false;
+ if (enclosingSourceType == null
+ ? memberType.canBeSeenBy(currentPackage)
+ : memberType.canBeSeenBy(enclosingType, enclosingSourceType)) {
+ if (visibleMemberType == null)
+ visibleMemberType = memberType;
+ else
+ return new ProblemReferenceBinding(typeName, Ambiguous);
+ } else {
+ notVisible = true;
+ }
+ }
+ }
+
+ // walk all visible interfaces to find ambiguous references
+ if (interfacesToVisit != null) {
+ ProblemReferenceBinding ambiguous = null;
+ done : for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++) {
+ ReferenceBinding anInterface = interfaces[j];
+ if ((anInterface.tagBits & InterfaceVisited) == 0) { // if interface as not already been visited
+ anInterface.tagBits |= InterfaceVisited;
+ compilationUnitScope().addTypeReference(anInterface);
+ if ((memberType = anInterface.getMemberType(typeName)) != null) {
+ compilationUnitScope().addTypeReference(memberType);
+ if (visibleMemberType == null) {
+ visibleMemberType = memberType;
+ } else {
+ ambiguous = new ProblemReferenceBinding(typeName, Ambiguous);
+ break done;
+ }
+ } else {
+ ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+ }
+ }
+ }
+ }
+
+ // bit reinitialization
+ for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++)
+ interfaces[j].tagBits &= ~InterfaceVisited;
+ }
+ if (ambiguous != null) return ambiguous;
+ }
+
+ if (visibleMemberType != null)
+ return visibleMemberType;
+ if (notVisible)
+ return new ProblemReferenceBinding(typeName, NotVisible);
+ return null;
+}
+// Internal use only
+
+public MethodBinding findMethod(ReferenceBinding receiverType, char[] selector, TypeBinding[] argumentTypes, InvocationSite invocationSite) {
+ ReferenceBinding currentType = receiverType;
+ MethodBinding matchingMethod = null;
+ ObjectVector found = null;
+
+ compilationUnitScope().addTypeReference(currentType);
+ compilationUnitScope().addTypeReferences(argumentTypes);
+ if (currentType.isInterface()) {
+ MethodBinding[] currentMethods = currentType.getMethods(selector);
+ int currentLength = currentMethods.length;
+ if (currentLength == 1) {
+ matchingMethod = currentMethods[0];
+ } else if (currentLength > 1) {
+ found = new ObjectVector();
+ for (int f = 0; f < currentLength; f++)
+ found.add(currentMethods[f]);
+ }
+
+ ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][];
+ int lastPosition = -1;
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+
+ for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++) {
+ currentType = interfaces[j];
+ if ((currentType.tagBits & InterfaceVisited) == 0) { // if interface as not already been visited
+ currentType.tagBits |= InterfaceVisited;
+
+ currentMethods = currentType.getMethods(selector);
+ if ((currentLength = currentMethods.length) == 1 && matchingMethod == null && found == null) {
+ matchingMethod = currentMethods[0];
+ } else if (currentLength > 0) {
+ if (found == null) {
+ found = new ObjectVector();
+ if (matchingMethod != null)
+ found.add(matchingMethod);
+ }
+ for (int f = 0; f < currentLength; f++)
+ found.add(currentMethods[f]);
+ }
+
+ itsInterfaces = currentType.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+ }
+ }
+ }
+
+ // bit reinitialization
+ for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++)
+ interfaces[j].tagBits &= ~InterfaceVisited;
+ }
+ }
+ currentType = (matchingMethod == null && found == null) ? getJavaLangObject() : null;
+ }
+
+ while (currentType != null) {
+ MethodBinding[] currentMethods = currentType.getMethods(selector);
+ int currentLength = currentMethods.length;
+ if (currentLength == 1 && matchingMethod == null && found == null) {
+ matchingMethod = currentMethods[0];
+ } else if (currentLength > 0) {
+ if (found == null) {
+ found = new ObjectVector();
+ if (matchingMethod != null)
+ found.add(matchingMethod);
+ }
+ for (int f = 0; f < currentLength; f++)
+ found.add(currentMethods[f]);
+ }
+ currentType = currentType.superclass();
+ }
+
+ if (found == null)
+ return matchingMethod; // may be null - have not checked arg types or visibility
+
+ int foundSize = found.size;
+ MethodBinding[] compatible = new MethodBinding[foundSize];
+ int compatibleIndex = 0;
+ for (int i = 0; i < foundSize; i++) {
+ MethodBinding methodBinding = (MethodBinding) found.elementAt(i);
+ if (areParametersAssignable(methodBinding.parameters, argumentTypes))
+ compatible[compatibleIndex++] = methodBinding;
+ }
+ if (compatibleIndex == 1)
+ return compatible[0]; // have not checked visibility
+ if (compatibleIndex == 0)
+ return (MethodBinding) found.elementAt(0); // no good match so just use the first one found
+
+ MethodBinding[] visible = new MethodBinding[compatibleIndex];
+ int visibleIndex = 0;
+ for (int i = 0; i < compatibleIndex; i++) {
+ MethodBinding methodBinding = compatible[i];
+ if (methodBinding.canBeSeenBy(receiverType, invocationSite, this))
+ visible[visibleIndex++] = methodBinding;
+ }
+ if (visibleIndex == 1){
+ compilationUnitScope().addTypeReferences(visible[0].thrownExceptions);
+ return visible[0];
+ }
+ if (visibleIndex == 0)
+ return new ProblemMethodBinding(compatible[0].selector, argumentTypes, compatible[0].declaringClass, NotVisible);
+ if (visible[0].declaringClass.isClass())
+ return mostSpecificClassMethodBinding(visible, visibleIndex);
+ else
+ return mostSpecificInterfaceMethodBinding(visible, visibleIndex);
+}
+// Internal use only
+
+public MethodBinding findMethodForArray(ArrayBinding receiverType, char[] selector, TypeBinding[] argumentTypes, InvocationSite invocationSite) {
+ ReferenceBinding object = getJavaLangObject();
+ MethodBinding methodBinding = object.getExactMethod(selector, argumentTypes);
+ if (methodBinding != null) {
+ // handle the method clone() specially... cannot be protected or throw exceptions
+ if (argumentTypes == NoParameters && CharOperation.equals(selector, CLONE))
+ return new MethodBinding((methodBinding.modifiers ^ AccProtected) | AccPublic, CLONE, methodBinding.returnType, argumentTypes, null, object);
+ if (methodBinding.canBeSeenBy(receiverType, invocationSite, this))
+ return methodBinding;
+ }
+
+ // answers closest approximation, may not check argumentTypes or visibility
+ methodBinding = findMethod(object, selector, argumentTypes, invocationSite);
+ if (methodBinding == null)
+ return new ProblemMethodBinding(selector, argumentTypes, NotFound);
+ if (methodBinding.isValidBinding()) {
+ if (!areParametersAssignable(methodBinding.parameters, argumentTypes))
+ return new ProblemMethodBinding(methodBinding, selector, argumentTypes, NotFound);
+ if (!methodBinding.canBeSeenBy(receiverType, invocationSite, this))
+ return new ProblemMethodBinding(selector, argumentTypes, methodBinding.declaringClass, NotVisible);
+ }
+ return methodBinding;
+}
+// Internal use only
+
+public ReferenceBinding findType(char[] typeName, PackageBinding declarationPackage, PackageBinding invocationPackage) {
+ compilationUnitScope().addNamespaceReference(declarationPackage);
+ ReferenceBinding typeBinding = declarationPackage.getType(typeName);
+ if (typeBinding == null) return null;
+
+ if (typeBinding.isValidBinding()) {
+ compilationUnitScope().addTypeReference(typeBinding);
+ if (declarationPackage != invocationPackage && !typeBinding.canBeSeenBy(invocationPackage))
+ return new ProblemReferenceBinding(typeName, NotVisible);
+ }
+ return typeBinding;
+}
+public TypeBinding getBaseType(char[] name) {
+ // list should be optimized (with most often used first)
+ int length = name.length;
+ if (length > 2 && length < 8) {
+ switch (name[0]) {
+ case 'i':
+ if (length == 3 &&
+ name[1] == 'n' &&
+ name[2] == 't')
+ return IntBinding;
+ break;
+ case 'v':
+ if (length == 4 &&
+ name[1] == 'o' &&
+ name[2] == 'i' &&
+ name[3] == 'd')
+ return VoidBinding;
+ break;
+
+ case 'b':
+ if (length == 7 &&
+ name[1] == 'o' &&
+ name[2] == 'o' &&
+ name[3] == 'l' &&
+ name[4] == 'e' &&
+ name[5] == 'a' &&
+ name[6] == 'n')
+ return BooleanBinding;
+ if (length == 4 &&
+ name[1] == 'y' &&
+ name[2] == 't' &&
+ name[3] == 'e')
+ return ByteBinding;
+ break;
+ case 'c':
+ if (length == 4 &&
+ name[1] == 'h' &&
+ name[2] == 'a' &&
+ name[3] == 'r')
+ return CharBinding;
+ break;
+ case 'd':
+ if (length == 6 &&
+ name[1] == 'o' &&
+ name[2] == 'u' &&
+ name[3] == 'b' &&
+ name[4] == 'l' &&
+ name[5] == 'e')
+ return DoubleBinding;
+ break;
+ case 'f':
+ if (length == 5 &&
+ name[1] == 'l' &&
+ name[2] == 'o' &&
+ name[3] == 'a' &&
+ name[4] == 't')
+ return FloatBinding;
+ break;
+ case 'l':
+ if (length == 4 &&
+ name[1] == 'o' &&
+ name[2] == 'n' &&
+ name[3] == 'g')
+ return LongBinding;
+ break;
+ case 's':
+ if (length == 5 &&
+ name[1] == 'h' &&
+ name[2] == 'o' &&
+ name[3] == 'r' &&
+ name[4] == 't')
+ return ShortBinding;
+ }
+ }
+ return null;
+}
+public final PackageBinding getCurrentPackage() {
+ Scope scope, unitScope = this;
+ while ((scope = unitScope.parent) != null)
+ unitScope = scope;
+ return ((CompilationUnitScope) unitScope).fPackage;
+}
+public final ReferenceBinding getJavaIoSerializable() {
+ ReferenceBinding type = environment().getType(JAVA_IO_SERIALIZABLE);
+ if (type != null)
+ return type;
+
+ compilationUnitScope().addNamespaceReference(new ProblemPackageBinding(JAVA_IO, NotFound)); // record extra reference to pkg
+ problemReporter().isClassPathCorrect(JAVA_IO_SERIALIZABLE, referenceCompilationUnit());
+ return null; // will not get here since the above error aborts the compilation
+}
+public final ReferenceBinding getJavaLangClass() {
+ ReferenceBinding type = environment().getType(JAVA_LANG_CLASS);
+ if (type != null)
+ return type;
+
+ compilationUnitScope().addNamespaceReference(new ProblemPackageBinding(JAVA_LANG, NotFound)); // record extra reference to pkg
+ problemReporter().isClassPathCorrect(JAVA_LANG_CLASS, referenceCompilationUnit());
+ return null; // will not get here since the above error aborts the compilation
+}
+public final ReferenceBinding getJavaLangCloneable() {
+ ReferenceBinding type = environment().getType(JAVA_LANG_CLONEABLE);
+ if (type != null)
+ return type;
+
+ compilationUnitScope().addNamespaceReference(new ProblemPackageBinding(JAVA_LANG, NotFound)); // record extra reference to pkg
+ problemReporter().isClassPathCorrect(JAVA_LANG_CLONEABLE, referenceCompilationUnit());
+ return null; // will not get here since the above error aborts the compilation
+}
+public final ReferenceBinding getJavaLangError() {
+ ReferenceBinding type = environment().getType(JAVA_LANG_ERROR);
+ if (type != null)
+ return type;
+
+ compilationUnitScope().addNamespaceReference(new ProblemPackageBinding(JAVA_LANG, NotFound)); // record extra reference to pkg
+ problemReporter().isClassPathCorrect(JAVA_LANG_ERROR, referenceCompilationUnit());
+ return null; // will not get here since the above error aborts the compilation
+}
+public final ReferenceBinding getJavaLangObject() {
+ ReferenceBinding type = environment().getType(JAVA_LANG_OBJECT);
+ if (type != null)
+ return type;
+
+ compilationUnitScope().addNamespaceReference(new ProblemPackageBinding(JAVA_LANG, NotFound)); // record extra reference to pkg
+ problemReporter().isClassPathCorrect(JAVA_LANG_OBJECT, referenceCompilationUnit());
+ return null; // will not get here since the above error aborts the compilation
+}
+public final ReferenceBinding getJavaLangRuntimeException() {
+ ReferenceBinding type = environment().getType(JAVA_LANG_RUNTIMEEXCEPTION);
+ if (type != null)
+ return type;
+
+ compilationUnitScope().addNamespaceReference(new ProblemPackageBinding(JAVA_LANG, NotFound)); // record extra reference to pkg
+ problemReporter().isClassPathCorrect(JAVA_LANG_RUNTIMEEXCEPTION, referenceCompilationUnit());
+ return null; // will not get here since the above error aborts the compilation
+}
+public final ReferenceBinding getJavaLangString() {
+ ReferenceBinding type = environment().getType(JAVA_LANG_STRING);
+ if (type != null)
+ return type;
+
+ problemReporter().isClassPathCorrect(JAVA_LANG_STRING, referenceCompilationUnit());
+ return null; // will not get here since the above error aborts the compilation
+}
+public final ReferenceBinding getJavaLangThrowable() {
+ ReferenceBinding type = environment().getType(JAVA_LANG_THROWABLE);
+ if (type != null)
+ return type;
+
+ problemReporter().isClassPathCorrect(JAVA_LANG_THROWABLE, referenceCompilationUnit());
+ return null; // will not get here since the above error aborts the compilation
+}
+/* Answer the type binding corresponding to the typeName argument, relative to the enclosingType.
+*/
+
+public final ReferenceBinding getMemberType(char[] typeName, ReferenceBinding enclosingType) {
+ ReferenceBinding memberType = findMemberType(typeName, enclosingType);
+ if (memberType == null)
+ return new ProblemReferenceBinding(typeName, NotFound);
+ else
+ return memberType;
+}
+/* Answer the type binding corresponding to the compoundName.
+*
+* NOTE: If a problem binding is returned, senders should extract the compound name
+* from the binding & not assume the problem applies to the entire compoundName.
+*/
+
+public final TypeBinding getType(char[][] compoundName) {
+ int typeNameLength = compoundName.length;
+ if (typeNameLength == 1) {
+ // Would like to remove this test and require senders to specially handle base types
+ TypeBinding binding = getBaseType(compoundName[0]);
+ if (binding != null)
+ return binding;
+ }
+
+ Binding binding = getTypeOrPackage(compoundName[0], typeNameLength == 1 ? TYPE : TYPE | PACKAGE);
+ if (binding == null)
+ return new ProblemReferenceBinding(compoundName[0], NotFound);
+ if (!binding.isValidBinding()){
+ compilationUnitScope().addNamespaceReference(new ProblemPackageBinding(compoundName[0], NotFound)); // record extra reference to pkg
+ return (ReferenceBinding) binding;
+ }
+ int currentIndex = 1;
+ boolean checkVisibility = false;
+ if (binding instanceof PackageBinding) {
+ PackageBinding packageBinding = (PackageBinding) binding;
+ compilationUnitScope().addNamespaceReference(packageBinding);
+
+ while (currentIndex < typeNameLength) {
+ binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++]); // does not check visibility
+ if (binding == null)
+ return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex), NotFound);
+ if (!binding.isValidBinding())
+ return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex), binding.problemId());
+ if (!(binding instanceof PackageBinding))
+ break;
+ packageBinding = (PackageBinding) binding;
+ compilationUnitScope().addNamespaceReference(packageBinding);
+ }
+
+ if (binding instanceof PackageBinding)
+ return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex), NotFound);
+ checkVisibility = true;
+ }
+
+ // binding is now a ReferenceBinding
+ ReferenceBinding typeBinding = (ReferenceBinding) binding;
+ compilationUnitScope().addTypeReference(typeBinding);
+ if (checkVisibility) // handles the fall through case
+ if (!typeBinding.canBeSeenBy(this))
+ return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex), NotVisible);
+
+ while (currentIndex < typeNameLength) {
+ typeBinding = getMemberType(compoundName[currentIndex++], typeBinding);
+ if (!typeBinding.isValidBinding())
+ return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex), typeBinding.problemId());
+ }
+ return typeBinding;
+}
+/* Answer the type binding that corresponds the given name, starting the lookup in the receiver.
+* The name provided is a simple source name (e.g., "Object" , "Point", ...)
+*/
+
+// The return type of this method could be ReferenceBinding if we did not answer base types.
+
+// NOTE: We could support looking for Base Types last in the search, however any code using
+// this feature would be extraordinarily slow. Therefore we don't do this
+
+public final TypeBinding getType(char[] name) {
+ // Would like to remove this test and require senders to specially handle base types
+ TypeBinding binding = getBaseType(name);
+ if (binding != null)
+ return binding;
+
+ return (ReferenceBinding) getTypeOrPackage(name, TYPE);
+}
+// Added for code assist... NOT Public API
+
+public final Binding getTypeOrPackage(char[][] compoundName) {
+ int nameLength = compoundName.length;
+ if (nameLength == 1) {
+ TypeBinding binding = getBaseType(compoundName[0]);
+ if (binding != null)
+ return binding;
+ }
+
+ Binding binding = getTypeOrPackage(compoundName[0], TYPE | PACKAGE);
+ if (!binding.isValidBinding())
+ return binding;
+
+ int currentIndex = 1;
+ boolean checkVisibility = false;
+ if (binding instanceof PackageBinding) {
+ PackageBinding packageBinding = (PackageBinding) binding;
+
+ while (currentIndex < nameLength) {
+ binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++]);
+ if (binding == null)
+ return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex), NotFound);
+ if (!binding.isValidBinding())
+ return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex), binding.problemId());
+ if (!(binding instanceof PackageBinding))
+ break;
+ packageBinding = (PackageBinding) binding;
+ }
+
+ if (binding instanceof PackageBinding)
+ return binding;
+ checkVisibility = true;
+ }
+
+ // binding is now a ReferenceBinding
+ ReferenceBinding typeBinding = (ReferenceBinding) binding;
+ if (checkVisibility) // handles the fall through case
+ if (!typeBinding.canBeSeenBy(this))
+ return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex), NotVisible);
+
+ while (currentIndex < nameLength) {
+ typeBinding = getMemberType(compoundName[currentIndex++], typeBinding); // checks visibility
+ if (!typeBinding.isValidBinding())
+ return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex), typeBinding.problemId());
+ }
+ return typeBinding;
+}
+/* Internal use only
+*/
+
+final Binding getTypeOrPackage(char[] name, int mask) {
+ Scope scope = this;
+ if ((mask & TYPE) == 0) {
+ Scope next = scope;
+ while ((next = scope.parent) != null)
+ scope = next;
+ } else {
+ ReferenceBinding foundType = null;
+ done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found
+ switch(scope.kind) {
+ case METHOD_SCOPE :
+ case BLOCK_SCOPE :
+ ReferenceBinding localType = ((BlockScope) scope).findLocalType(name); // looks in this scope only
+ if (localType != null) {
+ if (foundType != null && foundType != localType)
+ return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName);
+ return localType;
+ }
+ break;
+ case CLASS_SCOPE :
+ SourceTypeBinding sourceType = ((ClassScope) scope).referenceContext.binding;
+ if (CharOperation.equals(sourceType.sourceName, name)) {
+ if (foundType != null && foundType != sourceType)
+ return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName);
+ return sourceType;
+ }
+
+ ReferenceBinding memberType = findMemberType(name, sourceType);
+ if (memberType != null) { // skip it if we did not find anything
+ if (memberType.problemId() == Ambiguous) {
+ if (foundType == null || foundType.problemId() == NotVisible)
+ // supercedes any potential InheritedNameHidesEnclosingName problem
+ return memberType;
+ else
+ // make the user qualify the type, likely wants the first inherited type
+ return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName);
+ }
+
+ if (memberType.isValidBinding()) {
+ if (sourceType == memberType.enclosingType()) { // found a valid type in the 'immediate' scope (ie. not inherited)
+ if (foundType == null)
+ return memberType;
+ if (foundType.isValidBinding()) // if a valid type was found, complain when another is found in an 'immediate' enclosing type (ie. not inherited)
+ if (foundType != memberType)
+ return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName);
+ }
+ }
+
+ if (foundType == null || (foundType.problemId() == NotVisible && memberType.problemId() != NotVisible))
+ // only remember the memberType if its the first one found or the previous one was not visible & memberType is...
+ foundType = memberType;
+ }
+ break;
+ case COMPILATION_UNIT_SCOPE :
+ break done;
+ }
+ scope = scope.parent;
+ }
+ if (foundType != null)
+ return foundType;
+ }
+
+ // at this point the scope is a compilation unit scope
+ CompilationUnitScope unitScope = (CompilationUnitScope) scope;
+ // ask for the imports + name
+ if ((mask & TYPE) != 0) {
+ // check single type imports.
+ ImportBinding[] imports = unitScope.imports; // copy the list, since single type imports are removed if they cannot be resolved
+ for (int i = 0, length = imports.length; i < length; i++) {
+ ImportBinding typeImport = imports[i];
+ if (!typeImport.onDemand)
+ if (CharOperation.equals(typeImport.compoundName[typeImport.compoundName.length - 1], name))
+ if (unitScope.resolveSingleTypeImport(typeImport) != null)
+ return typeImport.resolvedImport; // already know its visible
+ }
+
+ // check if the name is in the current package (answer the problem binding unless its not found in which case continue to look)
+ ReferenceBinding type = findType(name, unitScope.fPackage, unitScope.fPackage); // is always visible
+ if (type != null)
+ return type;
+
+ // check on demand imports
+ boolean foundInImport = false;
+ for (int i = 0, length = unitScope.imports.length; i < length; i++) {
+ if (unitScope.imports[i].onDemand) {
+ Binding resolvedImport = unitScope.imports[i].resolvedImport;
+ ReferenceBinding temp =
+ (resolvedImport instanceof PackageBinding)
+ ? findType(name, (PackageBinding) resolvedImport, unitScope.fPackage)
+ : findDirectMemberType(name, (ReferenceBinding) resolvedImport);
+ if (temp != null && temp.isValidBinding()) {
+ if (foundInImport)
+ // Answer error binding -- import on demand conflict; name found in two import on demand packages.
+ return new ProblemReferenceBinding(name, Ambiguous);
+ type = temp;
+ foundInImport = true;
+ }
+ }
+ }
+
+ if (type != null)
+ return type;
+ }
+
+ // see if the name is a package
+ if ((mask & PACKAGE) != 0) {
+ PackageBinding packageBinding = unitScope.environment.getTopLevelPackage(name);
+ if (packageBinding != null)
+ return packageBinding;
+ }
+
+ // Answer error binding -- could not find name
+ compilationUnitScope().addNamespaceReference(new ProblemPackageBinding(name, NotFound));
+ return new ProblemReferenceBinding(name, NotFound);
+}
+/* Answer whether the type is defined in the same compilation unit as the receiver
+*/
+
+public final boolean isDefinedInSameUnit(ReferenceBinding type) {
+ // find the outer most enclosing type
+ ReferenceBinding enclosingType = type;
+ while ((type = enclosingType.enclosingType()) != null)
+ enclosingType = type;
+
+ // find the compilation unit scope
+ Scope scope, unitScope = this;
+ while ((scope = unitScope.parent) != null)
+ unitScope = scope;
+
+ // test that the enclosingType is not part of the compilation unit
+ SourceTypeBinding[] topLevelTypes = ((CompilationUnitScope) unitScope).topLevelTypes;
+ for (int i = topLevelTypes.length; --i >= 0;)
+ if (topLevelTypes[i] == enclosingType)
+ return true;
+ return false;
+}
+public final boolean isJavaIoSerializable(TypeBinding tb){
+ //a first -none optimized version-...:-)....
+ //please modify as needed
+
+ return tb == getJavaIoSerializable();
+}
+public final boolean isJavaLangCloneable(TypeBinding tb){
+ //a first -none optimized version-...:-)....
+ //please modify as needed
+
+ return tb == getJavaLangCloneable();
+}
+public final boolean isJavaLangObject(TypeBinding type) {
+ return type.id == T_JavaLangObject;
+}
+public final MethodScope methodScope() {
+ Scope scope = this;
+ do {
+ if (scope instanceof MethodScope)
+ return (MethodScope) scope;
+ scope = scope.parent;
+ } while (scope != null);
+ return null;
+}
+// Internal use only
+
+/* All methods in visible are acceptable matches for the method in question...
+* The methods defined by the receiver type appear before those defined by its
+* superclass and so on. We want to find the one which matches best.
+*
+* Since the receiver type is a class, we know each method's declaring class is
+* either the receiver type or one of its superclasses. It is an error if the best match
+* is defined by a superclass, when a lesser match is defined by the receiver type
+* or a closer superclass.
+*/
+
+protected final MethodBinding mostSpecificClassMethodBinding(MethodBinding[] visible, int visibleSize) {
+ MethodBinding method = null;
+ MethodBinding previous = null;
+ nextVisible: for (int i = 0; i < visibleSize; i++) {
+ method = visible[i];
+ if (previous != null && method.declaringClass != previous.declaringClass)
+ break; // cannot answer a method farther up the hierarchy than the first method found
+ previous = method;
+ for (int j = 0; j < visibleSize; j++) {
+ if (i == j) continue;
+ MethodBinding next = visible[j];
+ if (!areParametersAssignable(next.parameters, method.parameters))
+ continue nextVisible;
+ }
+ compilationUnitScope().addTypeReferences(method.thrownExceptions);
+ return method;
+ }
+ return new ProblemMethodBinding(visible[0].selector, visible[0].parameters, Ambiguous);
+}
+// Internal use only
+
+/* All methods in visible are acceptable matches for the method in question...
+* Since the receiver type is an interface, we ignore the possibility that 2 inherited
+* but unrelated superinterfaces may define the same method in acceptable but
+* not identical ways... we just take the best match that we find since any class which
+* implements the receiver interface MUST implement all signatures for the method...
+* in which case the best match is correct.
+*
+* NOTE: This is different than javac... in the following example, the message send of
+* bar(X) in class Y is supposed to be ambiguous. But any class which implements the
+* interface I MUST implement both signatures for bar. If this class was the receiver of
+* the message send instead of the interface I, then no problem would be reported.
+*
+interface I1 {
+ void bar(J j);
+}
+interface I2 {
+// void bar(J j);
+ void bar(Object o);
+}
+interface I extends I1, I2 {}
+interface J {}
+
+class X implements J {}
+
+class Y extends X {
+ public void foo(I i, X x) { i.bar(x); }
+}
+*/
+
+protected final MethodBinding mostSpecificInterfaceMethodBinding(MethodBinding[] visible, int visibleSize) {
+ MethodBinding method = null;
+ nextVisible: for (int i = 0; i < visibleSize; i++) {
+ method = visible[i];
+ for (int j = 0; j < visibleSize; j++) {
+ if (i == j) continue;
+ MethodBinding next = visible[j];
+ if (!areParametersAssignable(next.parameters, method.parameters))
+ continue nextVisible;
+ }
+ compilationUnitScope().addTypeReferences(method.thrownExceptions);
+ return method;
+ }
+ return new ProblemMethodBinding(visible[0].selector, visible[0].parameters, Ambiguous);
+}
+public final ClassScope outerMostClassScope() {
+ ClassScope lastClassScope = null;
+ Scope scope = this;
+ do {
+ if (scope instanceof ClassScope)
+ lastClassScope = (ClassScope) scope;
+ scope = scope.parent;
+ } while (scope != null);
+ return lastClassScope; // may answer null if no class around
+}
+public final MethodScope outerMostMethodScope() {
+ MethodScope lastMethodScope = null;
+ Scope scope = this;
+ do {
+ if (scope instanceof MethodScope)
+ lastMethodScope = (MethodScope) scope;
+ scope = scope.parent;
+ } while (scope != null);
+ return lastMethodScope; // may answer null if no method around
+}
+public abstract ProblemReporter problemReporter();
+public final CompilationUnitDeclaration referenceCompilationUnit() {
+ Scope scope, unitScope = this;
+ while ((scope = unitScope.parent) != null)
+ unitScope = scope;
+ return ((CompilationUnitScope) unitScope).referenceContext;
+}
+// start position in this scope - for ordering scopes vs. variables
+int startIndex() {
+ return 0;
+}
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
new file mode 100644
index 0000000000..4812ebe1b8
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
@@ -0,0 +1,1000 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.*;
+
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class SourceTypeBinding extends ReferenceBinding {
+ public ReferenceBinding superclass;
+ public ReferenceBinding[] superInterfaces;
+ public FieldBinding[] fields;
+ public MethodBinding[] methods;
+ public ReferenceBinding[] memberTypes;
+
+ public ClassScope scope;
+
+ // Synthetics are separated into 3 categories: methods, fields and class literals
+ public final static int METHOD = 0;
+ public final static int FIELD = 1;
+ public final static int CLASS_LITERAL = 2;
+ Hashtable[] synthetics;
+ protected SourceTypeBinding() {
+ }
+
+ public SourceTypeBinding(
+ char[][] compoundName,
+ PackageBinding fPackage,
+ ClassScope scope) {
+ this.compoundName = compoundName;
+ this.fPackage = fPackage;
+ this.fileName = scope.referenceCompilationUnit().getFileName();
+ this.modifiers = scope.referenceContext.modifiers;
+ this.sourceName = scope.referenceContext.name;
+ this.scope = scope;
+
+ computeId();
+ }
+
+ private void addDefaultAbstractMethod(MethodBinding abstractMethod) {
+ MethodBinding defaultAbstract =
+ new MethodBinding(
+ abstractMethod.modifiers | AccDefaultAbstract,
+ abstractMethod.selector,
+ abstractMethod.returnType,
+ abstractMethod.parameters,
+ abstractMethod.thrownExceptions,
+ this);
+
+ MethodBinding[] temp = new MethodBinding[methods.length + 1];
+ System.arraycopy(methods, 0, temp, 0, methods.length);
+ temp[methods.length] = defaultAbstract;
+ methods = temp;
+ }
+
+ public void addDefaultAbstractMethods() {
+ if ((tagBits & KnowsDefaultAbstractMethods) != 0)
+ return;
+
+ tagBits |= KnowsDefaultAbstractMethods;
+
+ if (isClass() && isAbstract()) {
+ ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][];
+ int lastPosition = 0;
+ interfacesToVisit[lastPosition] = superInterfaces();
+
+ for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++) {
+ ReferenceBinding superType = interfaces[j];
+ if (superType.isValidBinding()) {
+ MethodBinding[] methods = superType.methods();
+ for (int m = methods.length; --m >= 0;) {
+ MethodBinding method = methods[m];
+ if (!implementsMethod(method))
+ addDefaultAbstractMethod(method);
+ }
+
+ ReferenceBinding[] itsInterfaces = superType.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(
+ interfacesToVisit,
+ 0,
+ interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
+ 0,
+ lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Add a new synthetic field for <actualOuterLocalVariable>.
+ * Answer the new field or the existing field if one already existed.
+ */
+
+ public FieldBinding addSyntheticField(LocalVariableBinding actualOuterLocalVariable) {
+ if (synthetics == null) {
+ synthetics =
+ new Hashtable[] { new Hashtable(5), new Hashtable(5), new Hashtable(5)};
+ }
+
+ FieldBinding synthField =
+ (FieldBinding) synthetics[FIELD].get(actualOuterLocalVariable);
+ if (synthField == null) {
+ synthField =
+ new SyntheticFieldBinding(
+ CharOperation.concat(
+ SyntheticArgumentBinding.OuterLocalPrefix,
+ actualOuterLocalVariable.name),
+ actualOuterLocalVariable.type,
+ AccPrivate | AccFinal | AccSynthetic,
+ this,
+ Constant.NotAConstant,
+ synthetics[FIELD].size());
+ synthetics[FIELD].put(actualOuterLocalVariable, synthField);
+ }
+
+ // ensure there is not already such a field defined by the user
+ boolean needRecheck;
+ int index = 1;
+ do {
+ needRecheck = false;
+ FieldBinding existingField;
+ if ((existingField = this.getField(synthField.name)) != null) {
+ TypeDeclaration typeDecl = scope.referenceContext;
+ for (int i = 0, max = typeDecl.fields.length; i < max; i++) {
+ FieldDeclaration fieldDecl = typeDecl.fields[i];
+ if (fieldDecl.binding == existingField) {
+ synthField.name =
+ CharOperation.concat(
+ SyntheticArgumentBinding.OuterLocalPrefix,
+ actualOuterLocalVariable.name,
+ ("$" + String.valueOf(index++)).toCharArray());
+ needRecheck = true;
+ break;
+ }
+ }
+ }
+ } while (needRecheck);
+ return synthField;
+ }
+
+ /* Add a new synthetic field for <enclosingType>.
+ * Answer the new field or the existing field if one already existed.
+ */
+
+ public FieldBinding addSyntheticField(ReferenceBinding enclosingType) {
+ if (synthetics == null) {
+ synthetics =
+ new Hashtable[] { new Hashtable(5), new Hashtable(5), new Hashtable(5)};
+ }
+
+ FieldBinding synthField = (FieldBinding) synthetics[FIELD].get(enclosingType);
+ if (synthField == null) {
+ synthField =
+ new SyntheticFieldBinding(
+ CharOperation.concat(
+ SyntheticArgumentBinding.EnclosingInstancePrefix,
+ String.valueOf(enclosingType.depth()).toCharArray()),
+ enclosingType,
+ AccPrivate | AccFinal | AccSynthetic,
+ this,
+ Constant.NotAConstant,
+ synthetics[FIELD].size());
+ synthetics[FIELD].put(enclosingType, synthField);
+ }
+ // ensure there is not already such a field defined by the user
+ FieldBinding existingField;
+ if ((existingField = this.getField(synthField.name)) != null) {
+ TypeDeclaration typeDecl = scope.referenceContext;
+ for (int i = 0, max = typeDecl.fields.length; i < max; i++) {
+ FieldDeclaration fieldDecl = typeDecl.fields[i];
+ if (fieldDecl.binding == existingField) {
+ scope.problemReporter().duplicateFieldInType(this, fieldDecl);
+ break;
+ }
+ }
+ }
+ return synthField;
+ }
+
+ /* Add a new synthetic field for a class literal access.
+ * Answer the new field or the existing field if one already existed.
+ */
+
+ public FieldBinding addSyntheticField(
+ TypeBinding targetType,
+ BlockScope blockScope) {
+ if (synthetics == null) {
+ synthetics =
+ new Hashtable[] { new Hashtable(5), new Hashtable(5), new Hashtable(5)};
+ }
+
+ // use a different table than FIELDS, given there might be a collision between emulation of X.this$0 and X.class.
+ FieldBinding synthField =
+ (FieldBinding) synthetics[CLASS_LITERAL].get(targetType);
+ if (synthField == null) {
+ synthField =
+ new SyntheticFieldBinding(
+ ("class$" + synthetics[CLASS_LITERAL].size()).toCharArray(),
+ blockScope.getJavaLangClass(),
+ AccDefault | AccStatic | AccSynthetic,
+ this,
+ Constant.NotAConstant,
+ synthetics[CLASS_LITERAL].size());
+ synthetics[CLASS_LITERAL].put(targetType, synthField);
+ }
+ // ensure there is not already such a field defined by the user
+ FieldBinding existingField;
+ if ((existingField = this.getField(synthField.name)) != null) {
+ TypeDeclaration typeDecl = blockScope.referenceType();
+ for (int i = 0, max = typeDecl.fields.length; i < max; i++) {
+ FieldDeclaration fieldDecl = typeDecl.fields[i];
+ if (fieldDecl.binding == existingField) {
+ blockScope.problemReporter().duplicateFieldInType(this, fieldDecl);
+ break;
+ }
+ }
+ }
+ return synthField;
+ }
+
+ /* Add a new synthetic access method for read/write access to <targetField>.
+ Answer the new method or the existing method if one already existed.
+ */
+
+ public SyntheticAccessMethodBinding addSyntheticMethod(
+ FieldBinding targetField,
+ boolean isReadAccess) {
+ if (synthetics == null) {
+ synthetics =
+ new Hashtable[] { new Hashtable(5), new Hashtable(5), new Hashtable(5)};
+ }
+
+ SyntheticAccessMethodBinding accessMethod = null;
+ SyntheticAccessMethodBinding[] accessors =
+ (SyntheticAccessMethodBinding[]) synthetics[METHOD].get(targetField);
+ if (accessors == null) {
+ accessMethod =
+ new SyntheticAccessMethodBinding(targetField, isReadAccess, this);
+ synthetics[METHOD].put(
+ targetField,
+ accessors = new SyntheticAccessMethodBinding[2]);
+ accessors[isReadAccess ? 0 : 1] = accessMethod;
+ } else {
+ if ((accessMethod = accessors[isReadAccess ? 0 : 1]) == null) {
+ accessMethod =
+ new SyntheticAccessMethodBinding(targetField, isReadAccess, this);
+ accessors[isReadAccess ? 0 : 1] = accessMethod;
+ }
+ }
+ return accessMethod;
+ }
+
+ /* Add a new synthetic access method for access to <targetMethod>.
+ Answer the new method or the existing method if one already existed.
+ */
+
+ public SyntheticAccessMethodBinding addSyntheticMethod(MethodBinding targetMethod) {
+ if (synthetics == null) {
+ synthetics =
+ new Hashtable[] { new Hashtable(5), new Hashtable(5), new Hashtable(5)};
+ }
+
+ SyntheticAccessMethodBinding accessMethod =
+ (SyntheticAccessMethodBinding) synthetics[METHOD].get(targetMethod);
+ if (accessMethod == null) {
+ accessMethod = new SyntheticAccessMethodBinding(targetMethod, this);
+ synthetics[METHOD].put(targetMethod, accessMethod);
+ }
+ return accessMethod;
+ }
+
+ void faultInTypesForFieldsAndMethods() {
+ fields();
+ methods();
+
+ for (int i = 0, length = memberTypes.length; i < length; i++)
+ ((SourceTypeBinding) memberTypes[i]).faultInTypesForFieldsAndMethods();
+ }
+
+ // NOTE: the type of each field of a source type is resolved when needed
+
+ public FieldBinding[] fields() {
+ int failed = 0;
+ for (int f = fields.length; --f >= 0;) {
+ if (resolveTypeFor(fields[f]) == null) {
+ fields[f] = null;
+ failed++;
+ }
+ }
+ if (failed > 0) {
+ int newSize = fields.length - failed;
+ if (newSize == 0)
+ return fields = NoFields;
+
+ FieldBinding[] newFields = new FieldBinding[newSize];
+ for (int i = 0, n = 0, max = fields.length; i < max; i++)
+ if (fields[i] != null)
+ newFields[n++] = fields[i];
+ fields = newFields;
+ }
+ return fields;
+ }
+
+ public MethodBinding[] getDefaultAbstractMethods() {
+ int count = 0;
+ for (int i = methods.length; --i >= 0;)
+ if (methods[i].isDefaultAbstract())
+ count++;
+ if (count == 0)
+ return NoMethods;
+
+ MethodBinding[] result = new MethodBinding[count];
+ count = 0;
+ for (int i = methods.length; --i >= 0;)
+ if (methods[i].isDefaultAbstract())
+ result[count++] = methods[i];
+ return result;
+ }
+
+ // NOTE: the return type, arg & exception types of each method of a source type are resolved when needed
+
+ public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) {
+ int argCount = argumentTypes.length;
+
+ if ((modifiers & AccUnresolved) == 0) {
+ // have resolved all arg types & return type of the methods
+ nextMethod : for (int m = methods.length; --m >= 0;) {
+ MethodBinding method = methods[m];
+ if (method.selector == ConstructorDeclaration.ConstantPoolName
+ && method.parameters.length == argCount) {
+ TypeBinding[] toMatch = method.parameters;
+ for (int p = 0; p < argCount; p++)
+ if (toMatch[p] != argumentTypes[p])
+ continue nextMethod;
+ return method;
+ }
+ }
+ } else {
+ MethodBinding[] methods = getMethods(ConstructorDeclaration.ConstantPoolName);
+ // takes care of duplicates & default abstract methods
+ nextMethod : for (int m = methods.length; --m >= 0;) {
+ MethodBinding method = methods[m];
+ TypeBinding[] toMatch = method.parameters;
+ if (toMatch.length == argCount) {
+ for (int p = 0; p < argCount; p++)
+ if (toMatch[p] != argumentTypes[p])
+ continue nextMethod;
+ return method;
+ }
+ }
+ }
+ return null;
+ }
+
+ // NOTE: the return type, arg & exception types of each method of a source type are resolved when needed
+ // searches up the hierarchy as long as no potential (but not exact) match was found.
+
+ public MethodBinding getExactMethod(
+ char[] selector,
+ TypeBinding[] argumentTypes) {
+ int argCount = argumentTypes.length;
+ int selectorLength = selector.length;
+ boolean foundNothing = true;
+
+ if ((modifiers & AccUnresolved) == 0) {
+ // have resolved all arg types & return type of the methods
+ nextMethod : for (int m = methods.length; --m >= 0;) {
+ MethodBinding method = methods[m];
+ if (method.selector.length == selectorLength
+ && CharOperation.prefixEquals(method.selector, selector)) {
+ foundNothing = false;
+ // inner type lookups must know that a method with this name exists
+ if (method.parameters.length == argCount) {
+ TypeBinding[] toMatch = method.parameters;
+ for (int p = 0; p < argCount; p++)
+ if (toMatch[p] != argumentTypes[p])
+ continue nextMethod;
+ return method;
+ }
+ }
+ }
+ } else {
+ MethodBinding[] methods = getMethods(selector);
+ // takes care of duplicates & default abstract methods
+ foundNothing = methods == NoMethods;
+ nextMethod : for (int m = methods.length; --m >= 0;) {
+ MethodBinding method = methods[m];
+ TypeBinding[] toMatch = method.parameters;
+ if (toMatch.length == argCount) {
+ for (int p = 0; p < argCount; p++)
+ if (toMatch[p] != argumentTypes[p])
+ continue nextMethod;
+ return method;
+ }
+ }
+ }
+
+ if (foundNothing) {
+ if (isInterface()) {
+ if (superInterfaces.length == 1)
+ return superInterfaces[0].getExactMethod(selector, argumentTypes);
+ } else
+ if (superclass != null) {
+ return superclass.getExactMethod(selector, argumentTypes);
+ }
+ }
+ return null;
+ }
+
+ // NOTE: the type of a field of a source type is resolved when needed
+
+ public FieldBinding getField(char[] fieldName) {
+ int fieldLength = fieldName.length;
+ for (int f = fields.length; --f >= 0;) {
+ FieldBinding field = fields[f];
+ if (field.name.length == fieldLength
+ && CharOperation.prefixEquals(field.name, fieldName)) {
+ if (resolveTypeFor(field) != null)
+ return field;
+
+ int newSize = fields.length - 1;
+ if (newSize == 0) {
+ fields = NoFields;
+ } else {
+ FieldBinding[] newFields = new FieldBinding[newSize];
+ System.arraycopy(fields, 0, newFields, 0, f);
+ System.arraycopy(fields, f + 1, newFields, f, newSize - f);
+ fields = newFields;
+ }
+ return null;
+ }
+ }
+ return null;
+ }
+
+ // NOTE: the return type, arg & exception types of each method of a source type are resolved when needed
+
+ public MethodBinding[] getMethods(char[] selector) {
+ // handle forward references to potential default abstract methods
+ addDefaultAbstractMethods();
+
+ int count = 0;
+ int lastIndex = -1;
+ int selectorLength = selector.length;
+ if ((modifiers & AccUnresolved) == 0) {
+ // have resolved all arg types & return type of the methods
+ for (int m = 0, length = methods.length; m < length; m++) {
+ MethodBinding method = methods[m];
+ if (method.selector.length == selectorLength
+ && CharOperation.prefixEquals(method.selector, selector)) {
+ count++;
+ lastIndex = m;
+ }
+ }
+ } else {
+ boolean foundProblem = false;
+ int failed = 0;
+ for (int m = 0, length = methods.length; m < length; m++) {
+ MethodBinding method = methods[m];
+ if (method.selector.length == selectorLength
+ && CharOperation.prefixEquals(method.selector, selector)) {
+ if (resolveTypesFor(method) == null) {
+ foundProblem = true;
+ methods[m] = null; // unable to resolve parameters
+ failed++;
+ } else
+ if (method.returnType == null) {
+ foundProblem = true;
+ } else {
+ count++;
+ lastIndex = m;
+ }
+ }
+ }
+
+ if (foundProblem || count > 1) {
+ for (int m = methods.length; --m >= 0;) {
+ MethodBinding method = methods[m];
+ if (method != null
+ && method.selector.length == selectorLength
+ && CharOperation.prefixEquals(method.selector, selector)) {
+ AbstractMethodDeclaration methodDecl = null;
+ for (int i = 0; i < m; i++) {
+ MethodBinding method2 = methods[i];
+ if (method2 != null
+ && CharOperation.equals(method.selector, method2.selector)) {
+ if (method.areParametersEqual(method2)) {
+ if (methodDecl == null) {
+ methodDecl = method.sourceMethod();
+ // cannot be retrieved after binding is lost
+ scope.problemReporter().duplicateMethodInType(this, methodDecl);
+ methodDecl.binding = null;
+ methods[m] = null;
+ failed++;
+ }
+ scope.problemReporter().duplicateMethodInType(this, method2.sourceMethod());
+ method2.sourceMethod().binding = null;
+ methods[i] = null;
+ failed++;
+ }
+ }
+ }
+ if (method.returnType == null
+ && methodDecl == null) {
+ // forget method with invalid return type... was kept to detect possible collisions
+ method.sourceMethod().binding = null;
+ methods[m] = null;
+ failed++;
+ }
+ }
+ }
+
+ if (failed > 0) {
+ int newSize = methods.length - failed;
+ if (newSize == 0)
+ return methods = NoMethods;
+
+ MethodBinding[] newMethods = new MethodBinding[newSize];
+ for (int i = 0, n = 0, max = methods.length; i < max; i++)
+ if (methods[i] != null)
+ newMethods[n++] = methods[i];
+ methods = newMethods;
+ return getMethods(selector);
+ // try again now that the problem methods have been removed
+ }
+ }
+ }
+
+ if (count == 1)
+ return new MethodBinding[] { methods[lastIndex] };
+ if (count > 1) {
+ MethodBinding[] result = new MethodBinding[count];
+ count = 0;
+ for (int m = 0; m <= lastIndex; m++) {
+ MethodBinding method = methods[m];
+ if (method.selector.length == selectorLength
+ && CharOperation.prefixEquals(method.selector, selector))
+ result[count++] = method;
+ }
+ return result;
+ }
+ return NoMethods;
+ }
+
+ /* Answer the synthetic field for <actualOuterLocalVariable>
+ * or null if one does not exist.
+ */
+
+ public FieldBinding getSyntheticField(LocalVariableBinding actualOuterLocalVariable) {
+ if (synthetics == null)
+ return null;
+
+ return (FieldBinding) synthetics[FIELD].get(actualOuterLocalVariable);
+ }
+
+ /* Answer the synthetic field for <targetEnclosingType>
+ * or null if one does not exist.
+ */
+
+ public FieldBinding getSyntheticField(
+ ReferenceBinding targetEnclosingType,
+ BlockScope scope) {
+ if (synthetics == null)
+ return null;
+
+ FieldBinding field = (FieldBinding) synthetics[FIELD].get(targetEnclosingType);
+ if (field != null)
+ return field;
+
+ // type compatibility : to handle cases such as
+ // class T { class M{}}
+ // class S extends T { class N extends M {}} --> need to use S as a default enclosing instance for the super constructor call in N().
+ Enumeration enum = synthetics[FIELD].elements();
+ while (enum.hasMoreElements()) {
+ field = (FieldBinding) enum.nextElement();
+ if (CharOperation
+ .startsWith(field.name, SyntheticArgumentBinding.EnclosingInstancePrefix)
+ && targetEnclosingType.isSuperclassOf((ReferenceBinding) field.type))
+ return field;
+ }
+ return null;
+ }
+
+ public ReferenceBinding[] memberTypes() {
+ return memberTypes;
+ }
+
+ // NOTE: the return type, arg & exception types of each method of a source type are resolved when needed
+
+ public MethodBinding[] methods() {
+ if ((modifiers & AccUnresolved) == 0)
+ return methods;
+
+ int failed = 0;
+ for (int m = methods.length; --m >= 0;) {
+ if (resolveTypesFor(methods[m]) == null) {
+ methods[m] = null; // unable to resolve parameters
+ failed++;
+ }
+ }
+
+ for (int m = methods.length; --m >= 0;) {
+ MethodBinding method = methods[m];
+ if (method != null) {
+ AbstractMethodDeclaration methodDecl = null;
+ for (int i = 0; i < m; i++) {
+ MethodBinding method2 = methods[i];
+ if (method2 != null
+ && CharOperation.equals(method.selector, method2.selector)) {
+ if (method.areParametersEqual(method2)) {
+ if (methodDecl == null) {
+ methodDecl = method.sourceMethod();
+ // cannot be retrieved after binding is lost
+ scope.problemReporter().duplicateMethodInType(this, methodDecl);
+ methodDecl.binding = null;
+ methods[m] = null;
+ failed++;
+ }
+ scope.problemReporter().duplicateMethodInType(this, method2.sourceMethod());
+ method2.sourceMethod().binding = null;
+ methods[i] = null;
+ failed++;
+ }
+ }
+ }
+ if (method.returnType == null
+ && methodDecl == null) {
+ // forget method with invalid return type... was kept to detect possible collisions
+ method.sourceMethod().binding = null;
+ methods[m] = null;
+ failed++;
+ }
+ }
+ }
+
+ if (failed > 0) {
+ int newSize = methods.length - failed;
+ if (newSize == 0) {
+ methods = NoMethods;
+ } else {
+ MethodBinding[] newMethods = new MethodBinding[newSize];
+ for (int m = 0, n = 0, max = methods.length; m < max; m++)
+ if (methods[m] != null)
+ newMethods[n++] = methods[m];
+ methods = newMethods;
+ }
+ }
+
+ // handle forward references to potential default abstract methods
+ addDefaultAbstractMethods();
+ modifiers ^= AccUnresolved;
+ return methods;
+ }
+
+ private FieldBinding resolveTypeFor(FieldBinding field) {
+ if (field.type != null)
+ return field;
+
+ FieldDeclaration[] fieldDecls = scope.referenceContext.fields;
+ for (int f = 0, length = fieldDecls.length; f < length; f++) {
+ if (fieldDecls[f].binding != field)
+ continue;
+
+ field.type = fieldDecls[f].getTypeBinding(scope);
+ if (!field.type.isValidBinding()) {
+ scope.problemReporter().fieldTypeProblem(this, fieldDecls[f], field.type);
+ fieldDecls[f].binding = null;
+ return null;
+ }
+ if (field.type == VoidBinding) {
+ scope.problemReporter().variableTypeCannotBeVoid(fieldDecls[f]);
+ fieldDecls[f].binding = null;
+ return null;
+ }
+ if (field.type.isArrayType()
+ && ((ArrayBinding) field.type).leafComponentType == VoidBinding) {
+ scope.problemReporter().variableTypeCannotBeVoidArray(fieldDecls[f]);
+ fieldDecls[f].binding = null;
+ return null;
+ }
+ return field;
+ }
+ return null; // should never reach this point
+ }
+
+ private MethodBinding resolveTypesFor(MethodBinding method) {
+ if ((method.modifiers & AccUnresolved) == 0)
+ return method;
+
+ AbstractMethodDeclaration methodDecl = method.sourceMethod();
+ TypeReference[] exceptionTypes = methodDecl.thrownExceptions;
+ if (exceptionTypes != null) {
+ int size = exceptionTypes.length;
+ method.thrownExceptions = new ReferenceBinding[size];
+ ReferenceBinding throwable = scope.getJavaLangThrowable();
+ int count = 0;
+ ReferenceBinding resolvedExceptionType;
+ for (int i = 0; i < size; i++) {
+ resolvedExceptionType =
+ (ReferenceBinding) exceptionTypes[i].getTypeBinding(scope);
+ if (!resolvedExceptionType.isValidBinding()) {
+ methodDecl.scope.problemReporter().exceptionTypeProblem(
+ this,
+ methodDecl,
+ exceptionTypes[i],
+ resolvedExceptionType);
+ continue;
+ }
+ if (throwable != resolvedExceptionType
+ && !throwable.isSuperclassOf(resolvedExceptionType)) {
+ methodDecl.scope.problemReporter().cannotThrowType(
+ this,
+ methodDecl,
+ exceptionTypes[i],
+ resolvedExceptionType);
+ continue;
+ }
+ method.thrownExceptions[count++] = resolvedExceptionType;
+ }
+ if (count < size)
+ System.arraycopy(
+ method.thrownExceptions,
+ 0,
+ method.thrownExceptions = new ReferenceBinding[count],
+ 0,
+ count);
+ }
+
+ boolean foundArgProblem = false;
+ Argument[] arguments = methodDecl.arguments;
+ if (arguments != null) {
+ int size = arguments.length;
+ method.parameters = new TypeBinding[size];
+ for (int i = 0; i < size; i++) {
+ Argument arg = arguments[i];
+ method.parameters[i] = arg.type.getTypeBinding(scope);
+ if (!method.parameters[i].isValidBinding()) {
+ methodDecl.scope.problemReporter().argumentTypeProblem(
+ this,
+ methodDecl,
+ arg,
+ method.parameters[i]);
+ foundArgProblem = true;
+ } else
+ if (method.parameters[i] == VoidBinding) {
+ methodDecl.scope.problemReporter().argumentTypeCannotBeVoid(
+ this,
+ methodDecl,
+ arg);
+ foundArgProblem = true;
+ } else
+ if (method.parameters[i].isArrayType()
+ && ((ArrayBinding) method.parameters[i]).leafComponentType == VoidBinding) {
+ methodDecl.scope.problemReporter().argumentTypeCannotBeVoidArray(
+ this,
+ methodDecl,
+ arg);
+ foundArgProblem = true;
+ }
+ // check the modifiers for argument. Only final is authorized.
+ if ((arg.modifiers & ~AccFinal) != 0) {
+ methodDecl.scope.problemReporter().illegalModifierForArgument(
+ this,
+ methodDecl,
+ arg);
+ foundArgProblem = true;
+ }
+ }
+ }
+
+ boolean foundReturnTypeProblem = false;
+ if (!method.isConstructor()) {
+ method.returnType =
+ ((MethodDeclaration) methodDecl).returnType.getTypeBinding(scope);
+ if (!method.returnType.isValidBinding()) {
+ methodDecl.scope.problemReporter().returnTypeProblem(
+ this,
+ (MethodDeclaration) methodDecl,
+ method.returnType);
+ method.returnType = null;
+ foundReturnTypeProblem = true;
+ } else
+ if (method.returnType.isArrayType()
+ && ((ArrayBinding) method.returnType).leafComponentType == VoidBinding) {
+ methodDecl.scope.problemReporter().returnTypeCannotBeVoidArray(
+ this,
+ (MethodDeclaration) methodDecl);
+ method.returnType = null;
+ foundReturnTypeProblem = true;
+ }
+ }
+ if (foundArgProblem) {
+ methodDecl.binding = null;
+ return null;
+ }
+ if (foundReturnTypeProblem)
+ return method;
+ // but its still unresolved with a null return type & is still connected to its method declaration
+
+ method.modifiers ^= AccUnresolved;
+ return method;
+ }
+
+ public final int sourceEnd() {
+ return scope.referenceContext.sourceEnd;
+ }
+
+ public final int sourceStart() {
+ return scope.referenceContext.sourceStart;
+ }
+
+ public ReferenceBinding superclass() {
+ return superclass;
+ }
+
+ public ReferenceBinding[] superInterfaces() {
+ return superInterfaces;
+ }
+
+ public SyntheticAccessMethodBinding[] syntheticAccessMethods() {
+ if (synthetics == null || synthetics[METHOD].size() == 0)
+ return null;
+
+ // difficult to compute size up front because of the embedded arrays so assume there is only 1
+ int index = 0;
+ SyntheticAccessMethodBinding[] bindings = new SyntheticAccessMethodBinding[1];
+ Enumeration fieldsOrMethods = synthetics[METHOD].keys();
+ while (fieldsOrMethods.hasMoreElements()) {
+ Object fieldOrMethod = fieldsOrMethods.nextElement();
+ if (fieldOrMethod instanceof MethodBinding) {
+ if (index + 1 > bindings.length)
+ System.arraycopy(
+ bindings,
+ 0,
+ (bindings = new SyntheticAccessMethodBinding[index + 1]),
+ 0,
+ index);
+ bindings[index++] =
+ (SyntheticAccessMethodBinding) synthetics[METHOD].get(fieldOrMethod);
+ } else {
+ SyntheticAccessMethodBinding[] fieldAccessors =
+ (SyntheticAccessMethodBinding[]) synthetics[METHOD].get(fieldOrMethod);
+ int numberOfAccessors = 0;
+ if (fieldAccessors[0] != null)
+ numberOfAccessors++;
+ if (fieldAccessors[1] != null)
+ numberOfAccessors++;
+ if (index + numberOfAccessors > bindings.length)
+ System.arraycopy(
+ bindings,
+ 0,
+ (bindings = new SyntheticAccessMethodBinding[index + numberOfAccessors]),
+ 0,
+ index);
+ if (fieldAccessors[0] != null)
+ bindings[index++] = fieldAccessors[0];
+ if (fieldAccessors[1] != null)
+ bindings[index++] = fieldAccessors[1];
+ }
+ }
+
+ // sort them in according to their own indexes
+ int length;
+ SyntheticAccessMethodBinding[] sortedBindings =
+ new SyntheticAccessMethodBinding[length = bindings.length];
+ for (int i = 0; i < length; i++) {
+ SyntheticAccessMethodBinding binding = bindings[i];
+ sortedBindings[binding.index] = binding;
+ }
+ return sortedBindings;
+ }
+
+ /**
+ * Answer the collection of synthetic fields to append into the classfile
+ */
+ public FieldBinding[] syntheticFields() {
+ if (synthetics == null)
+ return null;
+
+ int fieldSize = synthetics[FIELD].size();
+ int literalSize = synthetics[CLASS_LITERAL].size();
+ FieldBinding[] bindings = new FieldBinding[fieldSize + literalSize];
+
+ // add innerclass synthetics
+ Enumeration elements = synthetics[FIELD].elements();
+ for (int i = 0; i < fieldSize; i++) {
+ SyntheticFieldBinding synthBinding =
+ (SyntheticFieldBinding) elements.nextElement();
+ bindings[synthBinding.index] = synthBinding;
+ }
+ // add class literal synthetics
+ elements = synthetics[CLASS_LITERAL].elements();
+ for (int i = 0; i < literalSize; i++) {
+ SyntheticFieldBinding synthBinding =
+ (SyntheticFieldBinding) elements.nextElement();
+ bindings[fieldSize + synthBinding.index] = synthBinding;
+ }
+ return bindings;
+ }
+
+ public String toString() {
+ String s = "(id=" + (id == NoId ? "NoId" : ("" + id)) + ")\n";
+
+ if (isDeprecated())
+ s += "deprecated ";
+ if (isPublic())
+ s += "public ";
+ if (isProtected())
+ s += "protected ";
+ if (isPrivate())
+ s += "private ";
+ if (isAbstract() && isClass())
+ s += "abstract ";
+ if (isStatic() && isNestedType())
+ s += "static ";
+ if (isFinal())
+ s += "final ";
+
+ s += isInterface() ? "interface " : "class ";
+ s += (compoundName != null)
+ ? CharOperation.toString(compoundName)
+ : "UNNAMED TYPE";
+
+ s += "\n\textends ";
+ s += (superclass != null) ? superclass.debugName() : "NULL TYPE";
+
+ if (superInterfaces != null) {
+ if (superInterfaces != NoSuperInterfaces) {
+ s += "\n\timplements : ";
+ for (int i = 0, length = superInterfaces.length; i < length; i++) {
+ if (i > 0)
+ s += ", ";
+ s += (superInterfaces[i] != null)
+ ? superInterfaces[i].debugName()
+ : "NULL TYPE";
+ }
+ }
+ } else {
+ s += "NULL SUPERINTERFACES";
+ }
+
+ if (enclosingType() != null) {
+ s += "\n\tenclosing type : ";
+ s += enclosingType().debugName();
+ }
+
+ if (fields != null) {
+ if (fields != NoFields) {
+ s += "\n/* fields */";
+ for (int i = 0, length = fields.length; i < length; i++)
+ s += (fields[i] != null) ? "\n" + fields[i].toString() : "\nNULL FIELD";
+ }
+ } else {
+ s += "NULL FIELDS";
+ }
+
+ if (methods != null) {
+ if (methods != NoMethods) {
+ s += "\n/* methods */";
+ for (int i = 0, length = methods.length; i < length; i++)
+ s += (methods[i] != null) ? "\n" + methods[i].toString() : "\nNULL METHOD";
+ }
+ } else {
+ s += "NULL METHODS";
+ }
+
+ if (memberTypes != null) {
+ if (memberTypes != NoMemberTypes) {
+ s += "\n/* members */";
+ for (int i = 0, length = memberTypes.length; i < length; i++)
+ s += (memberTypes[i] != null)
+ ? "\n" + memberTypes[i].toString()
+ : "\nNULL TYPE";
+ }
+ } else {
+ s += "NULL MEMBER TYPES";
+ }
+
+ s += "\n\n\n";
+ return s;
+ }
+
+ void verifyMethods(MethodVerifier verifier) {
+ verifier.verify(this);
+
+ for (int i = memberTypes.length; --i >= 0;)
+ ((SourceTypeBinding) memberTypes[i]).verifyMethods(verifier);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticAccessMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticAccessMethodBinding.java
new file mode 100644
index 0000000000..877f2f546b
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticAccessMethodBinding.java
@@ -0,0 +1,316 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class SyntheticAccessMethodBinding extends MethodBinding {
+
+ public FieldBinding targetReadField; // read access to a field
+ public FieldBinding targetWriteField; // write access to a field
+ public MethodBinding targetMethod; // method or constructor
+
+ public int accessType;
+
+ public final static int FieldReadAccess = 1;
+ public final static int FieldWriteAccess = 2;
+ public final static int MethodAccess = 3;
+ public final static int ConstructorAccess = 4;
+
+ final static char[] AccessMethodPrefix = { 'a', 'c', 'c', 'e', 's', 's', '$' };
+
+ public int sourceStart = 0; // start position of the matching declaration
+ public int index; // used for sorting access methods in the class file
+ public SyntheticAccessMethodBinding(
+ FieldBinding targetField,
+ boolean isReadAccess,
+ ReferenceBinding declaringClass) {
+ this.modifiers = AccDefault | AccStatic | AccSynthetic;
+ SourceTypeBinding declaringSourceType = (SourceTypeBinding) declaringClass;
+ SyntheticAccessMethodBinding[] knownAccessMethods =
+ declaringSourceType.syntheticAccessMethods();
+ int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length;
+ this.index = methodId;
+ this.selector =
+ CharOperation.concat(
+ AccessMethodPrefix,
+ String.valueOf(methodId).toCharArray());
+ if (isReadAccess) {
+ this.returnType = targetField.type;
+ if (targetField.isStatic()) {
+ this.parameters = NoParameters;
+ } else {
+ this.parameters = new TypeBinding[1];
+ this.parameters[0] = declaringSourceType;
+ }
+ this.targetReadField = targetField;
+ this.accessType = FieldReadAccess;
+ } else {
+ this.returnType = VoidBinding;
+ if (targetField.isStatic()) {
+ this.parameters = new TypeBinding[1];
+ this.parameters[0] = targetField.type;
+ } else {
+ this.parameters = new TypeBinding[2];
+ this.parameters[0] = declaringSourceType;
+ this.parameters[1] = targetField.type;
+ }
+ this.targetWriteField = targetField;
+ this.accessType = FieldWriteAccess;
+ }
+ this.thrownExceptions = NoExceptions;
+ this.declaringClass = declaringSourceType;
+
+ // check for method collision
+ boolean needRename;
+ do {
+ check : {
+ needRename = false;
+ // check for collision with known methods
+ MethodBinding[] methods = declaringSourceType.methods;
+ for (int i = 0, length = methods.length; i < length; i++) {
+ if (this.selector == methods[i].selector
+ && this.areParametersEqual(methods[i])) {
+ needRename = true;
+ break check;
+ }
+ }
+ // check for collision with synthetic accessors
+ if (knownAccessMethods != null) {
+ for (int i = 0, length = knownAccessMethods.length; i < length; i++) {
+ if (knownAccessMethods[i] == null)
+ continue;
+ if (this.selector == knownAccessMethods[i].selector
+ && this.areParametersEqual(methods[i])) {
+ needRename = true;
+ break check;
+ }
+ }
+ }
+ }
+ if (needRename) { // retry with a selector postfixed by a growing methodId
+ this.selector(
+ CharOperation.concat(
+ AccessMethodPrefix,
+ String.valueOf(++methodId).toCharArray()));
+ }
+ } while (needRename);
+
+ // retrieve sourceStart position for the target field for line number attributes
+ FieldDeclaration[] fieldDecls =
+ declaringSourceType.scope.referenceContext.fields;
+ if (fieldDecls != null) {
+ for (int i = 0, max = fieldDecls.length; i < max; i++) {
+ if (fieldDecls[i].binding == targetField) {
+ this.sourceStart = fieldDecls[i].sourceStart;
+ return;
+ }
+ }
+ }
+
+ /* did not find the target field declaration - it is a synthetic one
+ public class A {
+ public class B {
+ public class C {
+ void foo() {
+ System.out.println("A.this = " + A.this);
+ }
+ }
+ }
+ public static void main(String args[]) {
+ new A().new B().new C().foo();
+ }
+ }
+ */
+ // We now at this point - per construction - it is for sure an enclosing instance, we are going to
+ // show the target field type declaration location.
+ this.sourceStart = declaringSourceType.scope.referenceContext.sourceStart;
+ // use the target declaring class name position instead
+ }
+
+ public SyntheticAccessMethodBinding(
+ MethodBinding targetMethod,
+ ReferenceBinding receiverType) {
+
+ if (targetMethod.isConstructor()) {
+ this.initializeConstructorAccessor(targetMethod);
+ } else {
+ this.initializeMethodAccessor(targetMethod, receiverType);
+ }
+ }
+
+ /**
+ * An constructor accessor is a constructor with an extra argument (declaringClass), in case of
+ * collision with an existing constructor, then add again an extra argument (declaringClass again).
+ */
+ public void initializeConstructorAccessor(MethodBinding targetConstructor) {
+
+ this.targetMethod = targetConstructor;
+ this.modifiers = AccDefault | AccSynthetic;
+ SourceTypeBinding sourceType =
+ (SourceTypeBinding) targetConstructor.declaringClass;
+ SyntheticAccessMethodBinding[] knownAccessMethods =
+ sourceType.syntheticAccessMethods();
+ this.index = knownAccessMethods == null ? 0 : knownAccessMethods.length;
+
+ this.selector = targetConstructor.selector;
+ this.returnType = targetConstructor.returnType;
+ this.accessType = ConstructorAccess;
+ this.parameters = new TypeBinding[targetConstructor.parameters.length + 1];
+ System.arraycopy(
+ targetConstructor.parameters,
+ 0,
+ this.parameters,
+ 0,
+ targetConstructor.parameters.length);
+ parameters[targetConstructor.parameters.length] =
+ targetConstructor.declaringClass;
+ this.thrownExceptions = targetConstructor.thrownExceptions;
+ this.declaringClass = sourceType;
+
+ // check for method collision
+ boolean needRename;
+ do {
+ check : {
+ needRename = false;
+ // check for collision with known methods
+ MethodBinding[] methods = sourceType.methods;
+ for (int i = 0, length = methods.length; i < length; i++) {
+ if (this.selector == methods[i].selector
+ && this.areParametersEqual(methods[i])) {
+ needRename = true;
+ break check;
+ }
+ }
+ // check for collision with synthetic accessors
+ if (knownAccessMethods != null) {
+ for (int i = 0, length = knownAccessMethods.length; i < length; i++) {
+ if (knownAccessMethods[i] == null)
+ continue;
+ if (this.selector == knownAccessMethods[i].selector
+ && this.areParametersEqual(methods[i])) {
+ needRename = true;
+ break check;
+ }
+ }
+ }
+ }
+ if (needRename) { // retry with a new extra argument
+ int length = this.parameters.length;
+ System.arraycopy(
+ this.parameters,
+ 0,
+ this.parameters = new TypeBinding[length + 1],
+ 0,
+ length);
+ this.parameters[length] = this.declaringClass;
+ }
+ } while (needRename);
+
+ // retrieve sourceStart position for the target method for line number attributes
+ AbstractMethodDeclaration[] methodDecls =
+ sourceType.scope.referenceContext.methods;
+ if (methodDecls != null) {
+ for (int i = 0, length = methodDecls.length; i < length; i++) {
+ if (methodDecls[i].binding == targetConstructor) {
+ this.sourceStart = methodDecls[i].sourceStart;
+ return;
+ }
+ }
+ }
+ }
+
+ /**
+ * An method accessor is a method with an access$N selector, where N is incremented in case of collisions.
+ */
+
+ public void initializeMethodAccessor(
+ MethodBinding targetMethod,
+ ReferenceBinding declaringClass) {
+
+ this.targetMethod = targetMethod;
+ this.modifiers = AccDefault | AccStatic | AccSynthetic;
+ SourceTypeBinding declaringSourceType = (SourceTypeBinding) declaringClass;
+ SyntheticAccessMethodBinding[] knownAccessMethods =
+ declaringSourceType.syntheticAccessMethods();
+ int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length;
+ this.index = methodId;
+
+ this.selector =
+ CharOperation.concat(
+ AccessMethodPrefix,
+ String.valueOf(methodId).toCharArray());
+ this.returnType = targetMethod.returnType;
+ this.accessType = MethodAccess;
+
+ if (targetMethod.isStatic()) {
+ this.parameters = targetMethod.parameters;
+ } else {
+ this.parameters = new TypeBinding[targetMethod.parameters.length + 1];
+ this.parameters[0] = declaringSourceType;
+ System.arraycopy(
+ targetMethod.parameters,
+ 0,
+ this.parameters,
+ 1,
+ targetMethod.parameters.length);
+ }
+ this.thrownExceptions = targetMethod.thrownExceptions;
+ this.declaringClass = declaringSourceType;
+
+ // check for method collision
+ boolean needRename;
+ do {
+ check : {
+ needRename = false;
+ // check for collision with known methods
+ MethodBinding[] methods = declaringSourceType.methods;
+ for (int i = 0, length = methods.length; i < length; i++) {
+ if (this.selector == methods[i].selector
+ && this.areParametersEqual(methods[i])) {
+ needRename = true;
+ break check;
+ }
+ }
+ // check for collision with synthetic accessors
+ if (knownAccessMethods != null) {
+ for (int i = 0, length = knownAccessMethods.length; i < length; i++) {
+ if (knownAccessMethods[i] == null)
+ continue;
+ if (this.selector == knownAccessMethods[i].selector
+ && this.areParametersEqual(methods[i])) {
+ needRename = true;
+ break check;
+ }
+ }
+ }
+ }
+ if (needRename) { // retry with a selector & a growing methodId
+ this.selector(
+ CharOperation.concat(
+ AccessMethodPrefix,
+ String.valueOf(++methodId).toCharArray()));
+ }
+ } while (needRename);
+
+ // retrieve sourceStart position for the target method for line number attributes
+ AbstractMethodDeclaration[] methodDecls =
+ declaringSourceType.scope.referenceContext.methods;
+ if (methodDecls != null) {
+ for (int i = 0, length = methodDecls.length; i < length; i++) {
+ if (methodDecls[i].binding == targetMethod) {
+ this.sourceStart = methodDecls[i].sourceStart;
+ return;
+ }
+ }
+ }
+ }
+
+ protected boolean isConstructorRelated() {
+ return accessType == ConstructorAccess;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticArgumentBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticArgumentBinding.java
new file mode 100644
index 0000000000..c323bb89b5
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticArgumentBinding.java
@@ -0,0 +1,52 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/**
+ * Specific local variable location used to:
+ * - either provide emulation for outer local variables used from within innerclass constructs,
+ * - or provide emulation to enclosing instances.
+ * When it is mapping to an outer local variable, this actual outer local is accessible through
+ * the public field #actualOuterLocalVariable.
+ *
+ * Such a synthetic argument binding will be inserted in all constructors of local innertypes before
+ * the user arguments.
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class SyntheticArgumentBinding extends LocalVariableBinding {
+
+ {
+ this.isArgument = true;
+ this.used = true;
+ }
+
+ // if the argument is mapping to an outer local variable, this denotes the outer actual variable
+ public LocalVariableBinding actualOuterLocalVariable;
+ // if the argument has a matching synthetic field
+ public FieldBinding matchingField;
+
+ final static char[] OuterLocalPrefix = { 'v', 'a', 'l', '$' };
+ final static char[] EnclosingInstancePrefix = { 't', 'h', 'i', 's', '$' };
+ public SyntheticArgumentBinding(LocalVariableBinding actualOuterLocalVariable) {
+ super(
+ CharOperation.concat(OuterLocalPrefix, actualOuterLocalVariable.name),
+ actualOuterLocalVariable.type,
+ AccFinal);
+ this.actualOuterLocalVariable = actualOuterLocalVariable;
+ }
+
+ public SyntheticArgumentBinding(ReferenceBinding enclosingType) {
+ super(
+ CharOperation.concat(
+ SyntheticArgumentBinding.EnclosingInstancePrefix,
+ String.valueOf(enclosingType.depth()).toCharArray()),
+ enclosingType,
+ AccFinal);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticFieldBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticFieldBinding.java
new file mode 100644
index 0000000000..61df5dde69
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticFieldBinding.java
@@ -0,0 +1,22 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.impl.*;
+
+public class SyntheticFieldBinding extends FieldBinding {
+ public int index;
+ public SyntheticFieldBinding(
+ char[] name,
+ TypeBinding type,
+ int modifiers,
+ ReferenceBinding declaringClass,
+ Constant constant,
+ int index) {
+ super(name, type, modifiers, declaringClass, constant);
+ this.index = index;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java
new file mode 100644
index 0000000000..bf719ef98a
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java
@@ -0,0 +1,35 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+public interface TagBits {
+ // Tag bits in the tagBits int of every TypeBinding
+ final int IsArrayType = 0x0001;
+ final int IsBaseType = 0x0002;
+ final int IsNestedType = 0x0004;
+ final int IsMemberType = 0x0008;
+ final int MemberTypeMask = IsNestedType | IsMemberType;
+ final int IsLocalType = 0x0010;
+ final int LocalTypeMask = IsNestedType | IsLocalType;
+ final int IsAnonymousType = 0x0020;
+ final int AnonymousTypeMask = LocalTypeMask | IsAnonymousType;
+ final int IsBinaryBinding = 0x0040;
+
+ // for the type hierarchy check used by ClassScope
+ final int BeginHierarchyCheck = 0x0100;
+ final int EndHierarchyCheck = 0x0200;
+
+ // test bit to see if default abstract methods were computed
+ final int KnowsDefaultAbstractMethods = 0x0400;
+
+ // Reusable bit currently used by Scopes
+ final int InterfaceVisited = 0x0800;
+
+ // test bits to see if parts of binary types are faulted
+ final int AreFieldsComplete = 0x1000;
+ final int AreMethodsComplete = 0x2000;
+
+ // test bit to avoid asking a type for a member type (includes inherited member types)
+ final int HasNoMemberTypes = 0x4000;
+
+ // test bit to identify if the type's hierarchy is inconsistent
+ final int HierarchyHasProblems = 0x8000;
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
new file mode 100644
index 0000000000..aa56ddd65b
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
@@ -0,0 +1,112 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+abstract public class TypeBinding
+ extends Binding
+ implements BaseTypes, TagBits, TypeConstants, TypeIds {
+ public int id = NoId;
+ public int tagBits = 0; // See values in the interface TagBits below
+ /* API
+ * Answer the receiver's binding type from Binding.BindingID.
+ */
+
+ public final int bindingType() {
+ return TYPE;
+ }
+
+ /* Answer true if the receiver can be instantiated
+ */
+
+ public boolean canBeInstantiated() {
+ return !isBaseType();
+ }
+
+ /* Answer the receiver's constant pool name.
+ *
+ * NOTE: This method should only be used during/after code gen.
+ */
+
+ public abstract char[] constantPoolName(); /* java/lang/Object */
+ String debugName() {
+ return new String(readableName());
+ }
+
+ public abstract PackageBinding getPackage();
+ /* Answer true if the receiver is an array
+ */
+
+ public final boolean isArrayType() {
+ return (tagBits & IsArrayType) != 0;
+ }
+
+ /* Answer true if the receiver is a base type
+ */
+
+ public final boolean isBaseType() {
+ return (tagBits & IsBaseType) != 0;
+ }
+
+ public boolean isClass() {
+ return false;
+ }
+
+ /* Answer true if the receiver type can be assigned to the argument type (right)
+ */
+
+ abstract boolean isCompatibleWith(TypeBinding right);
+ /* Answer true if the receiver's hierarchy has problems (always false for arrays & base types)
+ */
+
+ public final boolean isHierarchyInconsistent() {
+ return (tagBits & HierarchyHasProblems) != 0;
+ }
+
+ public boolean isInterface() {
+ return false;
+ }
+
+ public final boolean isNumericType() {
+ switch (id) {
+ case T_int :
+ case T_float :
+ case T_double :
+ case T_short :
+ case T_byte :
+ case T_long :
+ case T_char :
+ return true;
+ default :
+ return false;
+ }
+ }
+
+ /**
+ * Answer the qualified name of the receiver's package separated by periods
+ * or an empty string if its the default package.
+ *
+ * For example, {java.util.Hashtable}.
+ */
+
+ public char[] qualifiedPackageName() {
+ return getPackage() == null ? NoChar : getPackage().readableName();
+ }
+
+ /**
+ * Answer the source name for the type.
+ * In the case of member types, as the qualified name from its top level type.
+ * For example, for a member type N defined inside M & A: "A.M.N".
+ */
+
+ public abstract char[] qualifiedSourceName();
+ /* Answer the receiver's signature.
+ *
+ * Arrays & base types do not distinguish between signature() & constantPoolName().
+ *
+ * NOTE: This method should only be used during/after code gen.
+ */
+
+ public char[] signature() {
+ return constantPoolName();
+ }
+
+ public abstract char[] sourceName();
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
new file mode 100644
index 0000000000..57d7165387
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
@@ -0,0 +1,187 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+public interface TypeConstants {
+ final char[] JAVA = new char[] { 'j', 'a', 'v', 'a' };
+ final char[] LANG = new char[] { 'l', 'a', 'n', 'g' };
+ final char[] IO = new char[] { 'i', 'o' };
+ final char[] REFLECT = new char[] { 'r', 'e', 'f', 'l', 'e', 'c', 't' };
+ final char[] CharArray_JAVA_LANG_OBJECT =
+ new char[] {
+ 'j',
+ 'a',
+ 'v',
+ 'a',
+ '.',
+ 'l',
+ 'a',
+ 'n',
+ 'g',
+ '.',
+ 'O',
+ 'b',
+ 'j',
+ 'e',
+ 'c',
+ 't' };
+ final char[] LENGTH = new char[] { 'l', 'e', 'n', 'g', 't', 'h' };
+ final char[] CLONE = new char[] { 'c', 'l', 'o', 'n', 'e' };
+
+ // Constant compound names
+ final char[][] JAVA_LANG = new char[][] { JAVA, LANG };
+ final char[][] JAVA_IO = new char[][] { JAVA, IO };
+ final char[][] JAVA_LANG_CLASS =
+ new char[][] { JAVA, LANG, { 'C', 'l', 'a', 's', 's' }
+ };
+
+ final char[][] JAVA_LANG_CLASSNOTFOUNDEXCEPTION =
+ new char[][] {
+ JAVA,
+ LANG,
+ {
+ 'C',
+ 'l',
+ 'a',
+ 's',
+ 's',
+ 'N',
+ 'o',
+ 't',
+ 'F',
+ 'o',
+ 'u',
+ 'n',
+ 'd',
+ 'E',
+ 'x',
+ 'c',
+ 'e',
+ 'p',
+ 't',
+ 'i',
+ 'o',
+ 'n' }
+ };
+
+ final char[][] JAVA_LANG_CLONEABLE =
+ new char[][] { JAVA, LANG, { 'C', 'l', 'o', 'n', 'e', 'a', 'b', 'l', 'e' }
+ };
+
+ final char[][] JAVA_LANG_EXCEPTION =
+ new char[][] { JAVA, LANG, { 'E', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n' }
+ };
+
+ final char[][] JAVA_LANG_ERROR =
+ new char[][] { JAVA, LANG, { 'E', 'r', 'r', 'o', 'r' }
+ };
+
+ final char[][] JAVA_LANG_NOCLASSDEFERROR =
+ new char[][] {
+ JAVA,
+ LANG,
+ { 'N', 'o', 'C', 'l', 'a', 's', 's', 'D', 'e', 'f', 'E', 'r', 'r', 'o', 'r' }
+ };
+
+ final char[][] JAVA_LANG_OBJECT =
+ new char[][] { JAVA, LANG, { 'O', 'b', 'j', 'e', 'c', 't' }
+ };
+
+ final char[][] JAVA_LANG_STRING =
+ new char[][] { JAVA, LANG, { 'S', 't', 'r', 'i', 'n', 'g' }
+ };
+
+ final char[][] JAVA_LANG_STRINGBUFFER =
+ new char[][] {
+ JAVA,
+ LANG,
+ { 'S', 't', 'r', 'i', 'n', 'g', 'B', 'u', 'f', 'f', 'e', 'r' }
+ };
+
+ final char[][] JAVA_LANG_SYSTEM =
+ new char[][] { JAVA, LANG, { 'S', 'y', 's', 't', 'e', 'm' }
+ };
+
+ final char[][] JAVA_LANG_RUNTIMEEXCEPTION =
+ new char[][] {
+ JAVA,
+ LANG,
+ {
+ 'R',
+ 'u',
+ 'n',
+ 't',
+ 'i',
+ 'm',
+ 'e',
+ 'E',
+ 'x',
+ 'c',
+ 'e',
+ 'p',
+ 't',
+ 'i',
+ 'o',
+ 'n' }
+ };
+
+ final char[][] JAVA_LANG_THROWABLE =
+ new char[][] { JAVA, LANG, { 'T', 'h', 'r', 'o', 'w', 'a', 'b', 'l', 'e' }
+ };
+
+ final char[][] JAVA_LANG_REFLECT_CONSTRUCTOR =
+ new char[][] {
+ JAVA,
+ LANG,
+ REFLECT,
+ { 'C', 'o', 'n', 's', 't', 'r', 'u', 'c', 't', 'o', 'r' }
+ };
+
+ final char[][] JAVA_IO_PRINTSTREAM =
+ new char[][] {
+ JAVA,
+ IO,
+ { 'P', 'r', 'i', 'n', 't', 'S', 't', 'r', 'e', 'a', 'm' }
+ };
+
+ final char[][] JAVA_IO_SERIALIZABLE =
+ new char[][] {
+ JAVA,
+ IO,
+ { 'S', 'e', 'r', 'i', 'a', 'l', 'i', 'z', 'a', 'b', 'l', 'e' }
+ };
+
+ final char[][] JAVA_LANG_BYTE =
+ new char[][] { JAVA, LANG, "Byte".toCharArray()};
+ final char[][] JAVA_LANG_SHORT =
+ new char[][] { JAVA, LANG, "Short".toCharArray()};
+ final char[][] JAVA_LANG_CHARACTER =
+ new char[][] { JAVA, LANG, "Character".toCharArray()};
+ final char[][] JAVA_LANG_INTEGER =
+ new char[][] { JAVA, LANG, "Integer".toCharArray()};
+ final char[][] JAVA_LANG_LONG =
+ new char[][] { JAVA, LANG, "Long".toCharArray()};
+ final char[][] JAVA_LANG_FLOAT =
+ new char[][] { JAVA, LANG, "Float".toCharArray()};
+ final char[][] JAVA_LANG_DOUBLE =
+ new char[][] { JAVA, LANG, "Double".toCharArray()};
+ final char[][] JAVA_LANG_BOOLEAN =
+ new char[][] { JAVA, LANG, "Boolean".toCharArray()};
+ final char[][] JAVA_LANG_VOID =
+ new char[][] { JAVA, LANG, "Void".toCharArray()};
+
+ // Constants used by the flow analysis
+ final int EqualOrMoreSpecific = -1;
+ final int NotRelated = 0;
+ final int MoreGeneric = 1;
+
+ // Empty Collection which can later assign to null if performance is an issue.
+ final char[] NoChar = new char[0];
+ final char[][] NoCharChar = new char[0][];
+ // Method collections
+ final TypeBinding[] NoParameters = new TypeBinding[0];
+ final ReferenceBinding[] NoExceptions = new ReferenceBinding[0];
+ // Type collections
+ final FieldBinding[] NoFields = new FieldBinding[0];
+ final MethodBinding[] NoMethods = new MethodBinding[0];
+ final ReferenceBinding[] NoSuperInterfaces = new ReferenceBinding[0];
+ final ReferenceBinding[] NoMemberTypes = new ReferenceBinding[0];
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java
new file mode 100644
index 0000000000..3b9bbf12ec
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java
@@ -0,0 +1,115 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+public interface TypeIds {
+ //base type void null undefined Object String
+ //should have an id that is 0<= id <= 15
+
+ final int T_undefined = 0; // should not be changed
+ final int T_Object = 1;
+ final int T_char = 2;
+ final int T_byte = 3;
+ final int T_short = 4;
+ final int T_boolean = 5;
+ final int T_void = 6;
+ final int T_long = 7;
+ final int T_double = 8;
+ final int T_float = 9;
+ final int T_int = 10;
+ final int T_String = 11;
+ final int T_null = 12;
+ //final int T_extendedDouble = 13;
+ //final int T_extendedLong = 14
+
+ //=========end of 4 bits constraint===========
+
+ final int T_JavaLangObject = T_Object; // for consistency
+ final int T_JavaLangString = T_String; // for consistency
+
+ // well-known exception types
+ final int T_JavaLangClass = 16;
+ final int T_JavaLangStringBuffer = 17;
+ final int T_JavaLangSystem = 18;
+ final int T_JavaLangError = 19;
+ final int T_JavaLangReflectConstructor = 20;
+ final int T_JavaLangThrowable = 21;
+ final int T_JavaLangNoClassDefError = 22;
+ final int T_JavaLangClassNotFoundException = 23;
+ final int T_JavaIoPrintStream = 24;
+ final int T_JavaLangException = 25;
+
+ // wrapper types
+ final int T_JavaLangByte = 26;
+ final int T_JavaLangShort = 27;
+ final int T_JavaLangCharacter = 28;
+ final int T_JavaLangInteger = 29;
+ final int T_JavaLangLong = 30;
+ final int T_JavaLangFloat = 31;
+ final int T_JavaLangDouble = 32;
+ final int T_JavaLangBoolean = 33;
+ final int T_JavaLangVoid = 34;
+ final int NoId = Integer.MAX_VALUE;
+
+ // implicit conversions: <compileType> to <runtimeType> (note: booleans are integers at runtime)
+ final int Boolean2Int = T_boolean + (T_int << 4);
+ final int Boolean2String = T_boolean + (T_String << 4);
+ final int Boolean2Boolean = T_boolean + (T_boolean << 4);
+ final int Byte2Byte = T_byte + (T_byte << 4);
+ final int Byte2Short = T_byte + (T_short << 4);
+ final int Byte2Char = T_byte + (T_char << 4);
+ final int Byte2Int = T_byte + (T_int << 4);
+ final int Byte2Long = T_byte + (T_long << 4);
+ final int Byte2Float = T_byte + (T_float << 4);
+ final int Byte2Double = T_byte + (T_double << 4);
+ final int Byte2String = T_byte + (T_String << 4);
+ final int Short2Byte = T_short + (T_byte << 4);
+ final int Short2Short = T_short + (T_short << 4);
+ final int Short2Char = T_short + (T_char << 4);
+ final int Short2Int = T_short + (T_int << 4);
+ final int Short2Long = T_short + (T_long << 4);
+ final int Short2Float = T_short + (T_float << 4);
+ final int Short2Double = T_short + (T_double << 4);
+ final int Short2String = T_short + (T_String << 4);
+ final int Char2Byte = T_char + (T_byte << 4);
+ final int Char2Short = T_char + (T_short << 4);
+ final int Char2Char = T_char + (T_char << 4);
+ final int Char2Int = T_char + (T_int << 4);
+ final int Char2Long = T_char + (T_long << 4);
+ final int Char2Float = T_char + (T_float << 4);
+ final int Char2Double = T_char + (T_double << 4);
+ final int Char2String = T_char + (T_String << 4);
+ final int Int2Byte = T_int + (T_byte << 4);
+ final int Int2Short = T_int + (T_short << 4);
+ final int Int2Char = T_int + (T_char << 4);
+ final int Int2Int = T_int + (T_int << 4);
+ final int Int2Long = T_int + (T_long << 4);
+ final int Int2Float = T_int + (T_float << 4);
+ final int Int2Double = T_int + (T_double << 4);
+ final int Int2String = T_int + (T_String << 4);
+ final int Long2Byte = T_long + (T_byte << 4);
+ final int Long2Short = T_long + (T_short << 4);
+ final int Long2Char = T_long + (T_char << 4);
+ final int Long2Int = T_long + (T_int << 4);
+ final int Long2Long = T_long + (T_long << 4);
+ final int Long2Float = T_long + (T_float << 4);
+ final int Long2Double = T_long + (T_double << 4);
+ final int Long2String = T_long + (T_String << 4);
+ final int Float2Byte = T_float + (T_byte << 4);
+ final int Float2Short = T_float + (T_short << 4);
+ final int Float2Char = T_float + (T_char << 4);
+ final int Float2Int = T_float + (T_int << 4);
+ final int Float2Long = T_float + (T_long << 4);
+ final int Float2Float = T_float + (T_float << 4);
+ final int Float2Double = T_float + (T_double << 4);
+ final int Float2String = T_float + (T_String << 4);
+ final int Double2Byte = T_double + (T_byte << 4);
+ final int Double2Short = T_double + (T_short << 4);
+ final int Double2Char = T_double + (T_char << 4);
+ final int Double2Int = T_double + (T_int << 4);
+ final int Double2Long = T_double + (T_long << 4);
+ final int Double2Float = T_double + (T_float << 4);
+ final int Double2Double = T_double + (T_double << 4);
+ final int Double2String = T_double + (T_String << 4);
+ final int String2String = T_String + (T_String << 4);
+ final int Object2String = T_Object + (T_String << 4);
+ final int Null2String = T_null + (T_String << 4);
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java
new file mode 100644
index 0000000000..d3fc86cbf1
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java
@@ -0,0 +1,46 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class UnresolvedReferenceBinding extends ReferenceBinding {
+ ReferenceBinding resolvedType;
+ UnresolvedReferenceBinding(
+ char[][] compoundName,
+ PackageBinding packageBinding) {
+ this.compoundName = compoundName;
+ this.fPackage = packageBinding;
+ }
+
+ String debugName() {
+ return toString();
+ }
+
+ ReferenceBinding resolve(LookupEnvironment environment) {
+ if (resolvedType != null)
+ return resolvedType;
+
+ ReferenceBinding environmentType;
+ if ((environmentType = environment.askForType(compoundName)) != null) {
+ if (environmentType != this) {
+ // could not resolve any better, error was already reported against it
+ resolvedType = environmentType;
+ environment.updateArrayCache(this, environmentType);
+ return environmentType;
+ // when found, it replaces the unresolved type in the cache
+ }
+ }
+
+ environment.problemReporter.isClassPathCorrect(compoundName, null);
+ return null; // will not get here since the above error aborts the compilation
+ }
+
+ public String toString() {
+ return "Unresolved type "
+ + ((compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED");
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VariableBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VariableBinding.java
new file mode 100644
index 0000000000..d6201f7932
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VariableBinding.java
@@ -0,0 +1,38 @@
+package org.eclipse.jdt.internal.compiler.lookup;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+
+public abstract class VariableBinding extends Binding {
+ public int modifiers;
+ public TypeBinding type;
+ public char[] name;
+ public Constant constant;
+ public int id; // for flow-analysis (position in flowInfo bit vector)
+ public boolean isConstantValue() {
+ return constant != Constant.NotAConstant;
+ }
+
+ /* Answer true if the receiver is final and cannot be changed
+ */
+
+ public final boolean isFinal() {
+ return (modifiers & AccFinal) != 0;
+ }
+
+ public char[] readableName() {
+ return name;
+ }
+
+ public String toString() {
+ String s = (type != null) ? type.debugName() : "UNDEFINED TYPE";
+ s += " ";
+ s += (name != null) ? new String(name) : "UNNAMED FIELD";
+ return s;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/InvalidInputException.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/InvalidInputException.java
new file mode 100644
index 0000000000..19e027d9ad
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/InvalidInputException.java
@@ -0,0 +1,24 @@
+package org.eclipse.jdt.internal.compiler.parser;
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+
+public class InvalidInputException extends Exception {
+ /**
+ * InvalidInputException constructor comment.
+ */
+ public InvalidInputException() {
+ super();
+ }
+
+ /**
+ * InvalidInputException constructor comment.
+ * @param s java.lang.String
+ */
+ public InvalidInputException(String s) {
+ super(s);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
new file mode 100644
index 0000000000..0bdcb0f069
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
@@ -0,0 +1,7837 @@
+package org.eclipse.jdt.internal.compiler.parser;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+import java.io.*;
+
+public class Parser
+ implements
+ BindingIds,
+ ParserBasicInformation,
+ TerminalSymbols,
+ CompilerModifiers,
+ OperatorIds,
+ TypeIds {
+ protected ProblemReporter problemReporter;
+ public int firstToken; // handle for multiple parsing goals
+ public int lastAct; //handle for multiple parsing goals
+ protected ReferenceContext referenceContext;
+ public int currentToken;
+
+ //error recovery management
+ protected final static boolean ENABLE_RECOVERY = true;
+ protected int lastCheckPoint;
+ protected RecoveredElement currentElement;
+ public static boolean VERBOSE_RECOVERY = false;
+ protected boolean restartRecovery;
+ protected int listLength;
+ // for recovering some incomplete list (interfaces, throws or parameters)
+ protected boolean hasReportedError;
+ protected int recoveredStaticInitializerStart;
+ protected int lastIgnoredToken, nextIgnoredToken;
+ protected int lastErrorEndPosition;
+
+ //internal data for the automat
+ protected final static int StackIncrement = 255;
+ protected int stateStackTop;
+ protected int[] stack = new int[StackIncrement];
+ //scanner token
+ public Scanner scanner;
+ //ast stack
+ final static int AstStackIncrement = 100;
+ protected int astPtr;
+ protected AstNode[] astStack = new AstNode[AstStackIncrement];
+ protected int astLengthPtr;
+ protected int[] astLengthStack;
+ public CompilationUnitDeclaration compilationUnit; /*the result from parse()*/
+ AstNode[] noAstNodes = new AstNode[AstStackIncrement];
+ //expression stack
+ final static int ExpressionStackIncrement = 100;
+ protected int expressionPtr;
+ protected Expression[] expressionStack =
+ new Expression[ExpressionStackIncrement];
+ protected int expressionLengthPtr;
+ protected int[] expressionLengthStack;
+ Expression[] noExpressions = new Expression[ExpressionStackIncrement];
+ //identifiers stacks
+ protected int identifierPtr;
+ protected char[][] identifierStack;
+ protected int identifierLengthPtr;
+ protected int[] identifierLengthStack;
+ protected long[] identifierPositionStack;
+ //positions , dimensions , .... (what ever is int) ..... stack
+ protected int intPtr;
+ protected int[] intStack;
+ protected int endPosition;
+ //accurate only when used ! (the start position is pushed into intStack while the end the current one)
+ protected int endStatementPosition;
+ protected int lParenPos, rParenPos; //accurate only when used !
+ //modifiers dimensions nestedType etc.......
+ protected boolean optimizeStringLiterals = true;
+ protected int modifiers;
+ protected int modifiersSourceStart;
+ protected int nestedType, dimensions;
+ protected int[] nestedMethod; //the ptr is nestedType
+ protected int[] realBlockStack;
+ protected int realBlockPtr;
+ protected boolean diet = false;
+ //tells the scanner to jump over some parts of the code/expressions like method bodies
+ protected int dietInt = 0;
+ // if > 0 force the none-diet-parsing mode (even if diet if requested) [field parsing with anonymous inner classes...]
+ protected int[] variablesCounter;
+ //===DATA===DATA===DATA===DATA===DATA===DATA===//
+
+ public final static byte rhs[] =
+ {
+ 0,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 2,
+ 2,
+ 1,
+ 1,
+ 1,
+ 1,
+ 3,
+ 4,
+ 0,
+ 1,
+ 2,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 5,
+ 1,
+ 2,
+ 1,
+ 2,
+ 2,
+ 2,
+ 1,
+ 1,
+ 2,
+ 2,
+ 2,
+ 4,
+ 1,
+ 1,
+ 1,
+ 1,
+ 2,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 2,
+ 3,
+ 3,
+ 2,
+ 2,
+ 1,
+ 3,
+ 1,
+ 3,
+ 1,
+ 2,
+ 1,
+ 1,
+ 1,
+ 3,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 4,
+ 1,
+ 3,
+ 3,
+ 7,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2,
+ 1,
+ 1,
+ 1,
+ 2,
+ 2,
+ 4,
+ 4,
+ 5,
+ 4,
+ 4,
+ 2,
+ 1,
+ 2,
+ 3,
+ 3,
+ 1,
+ 3,
+ 3,
+ 1,
+ 3,
+ 1,
+ 4,
+ 0,
+ 2,
+ 1,
+ 2,
+ 4,
+ 1,
+ 1,
+ 2,
+ 5,
+ 5,
+ 7,
+ 7,
+ 7,
+ 7,
+ 2,
+ 2,
+ 3,
+ 2,
+ 2,
+ 3,
+ 1,
+ 2,
+ 1,
+ 2,
+ 1,
+ 1,
+ 2,
+ 2,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 3,
+ 3,
+ 4,
+ 1,
+ 3,
+ 4,
+ 0,
+ 1,
+ 2,
+ 1,
+ 1,
+ 1,
+ 1,
+ 2,
+ 3,
+ 4,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 3,
+ 3,
+ 2,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 5,
+ 7,
+ 7,
+ 6,
+ 2,
+ 3,
+ 3,
+ 4,
+ 1,
+ 2,
+ 2,
+ 1,
+ 2,
+ 3,
+ 2,
+ 5,
+ 5,
+ 7,
+ 9,
+ 9,
+ 1,
+ 1,
+ 1,
+ 1,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 3,
+ 3,
+ 5,
+ 1,
+ 3,
+ 4,
+ 1,
+ 2,
+ 5,
+ 2,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 3,
+ 1,
+ 1,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 1,
+ 1,
+ 5,
+ 6,
+ 8,
+ 7,
+ 2,
+ 0,
+ 2,
+ 0,
+ 1,
+ 3,
+ 4,
+ 4,
+ 1,
+ 2,
+ 3,
+ 2,
+ 1,
+ 1,
+ 2,
+ 2,
+ 3,
+ 3,
+ 4,
+ 6,
+ 6,
+ 4,
+ 4,
+ 1,
+ 1,
+ 1,
+ 1,
+ 2,
+ 2,
+ 0,
+ 1,
+ 1,
+ 3,
+ 3,
+ 1,
+ 3,
+ 3,
+ 1,
+ 3,
+ 3,
+ 1,
+ 5,
+ 5,
+ 4,
+ 1,
+ 3,
+ 3,
+ 3,
+ 1,
+ 3,
+ 3,
+ 1,
+ 3,
+ 3,
+ 3,
+ 1,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 1,
+ 3,
+ 3,
+ 1,
+ 3,
+ 1,
+ 3,
+ 1,
+ 3,
+ 1,
+ 3,
+ 1,
+ 3,
+ 1,
+ 5,
+ 1,
+ 1,
+ 3,
+ 3,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 2,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 2,
+ 0,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1 };
+
+ public static char asb[] = null;
+ public static char asr[] = null;
+ public static char symbol_index[] = null;
+ private static final String UNEXPECTED_EOF = "Unexpected End Of File";
+
+ public final static String name[] =
+ {
+ null,
+ "++",
+ "--",
+ "==",
+ "<=",
+ ">=",
+ "!=",
+ "<<",
+ ">>",
+ ">>>",
+ "+=",
+ "-=",
+ "*=",
+ "/=",
+ "&=",
+ "|=",
+ "^=",
+ "%=",
+ "<<=",
+ ">>=",
+ ">>>=",
+ "||",
+ "&&",
+ "+",
+ "-",
+ "!",
+ "%",
+ "^",
+ "&",
+ "*",
+ "|",
+ "~",
+ "/",
+ ">",
+ "<",
+ "(",
+ ")",
+ "{",
+ "}",
+ "[",
+ "]",
+ ";",
+ "?",
+ ":",
+ ",",
+ ".",
+ "=",
+ "",
+ "$empty",
+ "Identifier",
+ "abstract",
+ "boolean",
+ "break",
+ "byte",
+ "case",
+ "catch",
+ "char",
+ "class",
+ "continue",
+ "default",
+ "do",
+ "double",
+ "else",
+ "extends",
+ "false",
+ "final",
+ "finally",
+ "float",
+ "for",
+ "if",
+ "implements",
+ "import",
+ "instanceof",
+ "int",
+ "interface",
+ "long",
+ "native",
+ "new",
+ "null",
+ "package",
+ "private",
+ "protected",
+ "public",
+ "return",
+ "short",
+ "static",
+ "strictfp",
+ "super",
+ "switch",
+ "synchronized",
+ "this",
+ "throw",
+ "throws",
+ "transient",
+ "true",
+ "try",
+ "void",
+ "volatile",
+ "while",
+ "IntegerLiteral",
+ "LongLiteral",
+ "FloatingPointLiteral",
+ "DoubleLiteral",
+ "CharacterLiteral",
+ "StringLiteral",
+ UNEXPECTED_EOF,
+ "Invalid Character",
+ "Goal",
+ "MethodBody",
+ "ConstructorBody",
+ "StaticInitializer",
+ "ClassBodyDeclaration",
+ "Headers",
+ "BlockStatements",
+ "MethodPushModifiersHeader",
+ "CatchHeader",
+ "FieldDeclaration",
+ "ImportDeclaration",
+ "PackageDeclaration",
+ "TypeDeclaration",
+ "GenericMethodDeclaration",
+ "Expression",
+ "Type",
+ "PrimitiveType",
+ "ReferenceType",
+ "ClassOrInterfaceType",
+ "ArrayType",
+ "Name",
+ "Dims",
+ "ClassType",
+ "SimpleName",
+ "Header",
+ "ClassHeader",
+ "InterfaceHeader",
+ "MethodHeader",
+ "ConstructorHeader",
+ "FormalParameter",
+ "ImportDeclarations",
+ "TypeDeclarations",
+ "PackageDeclarationName",
+ "SingleTypeImportDeclarationNam" + "e",
+ "TypeImportOnDemandDeclarationN" + "ame",
+ "Modifiers",
+ "Modifier",
+ "ClassBody",
+ "ClassHeaderName",
+ "InterfaceTypeList",
+ "InterfaceType",
+ "ClassBodyDeclarations",
+ "Block",
+ "VariableDeclarators",
+ "VariableDeclarator",
+ "VariableDeclaratorId",
+ "VariableInitializer",
+ "ArrayInitializer",
+ "MethodHeaderName",
+ "MethodHeaderParameters",
+ "MethodPushModifiersHeaderName",
+ "ClassTypeList",
+ "ConstructorHeaderName",
+ "FormalParameterList",
+ "ClassTypeElt",
+ "StaticOnly",
+ "ExplicitConstructorInvocation",
+ "Primary",
+ "InterfaceBody",
+ "InterfaceHeaderName",
+ "InterfaceMemberDeclarations",
+ "InterfaceMemberDeclaration",
+ "VariableInitializers",
+ "BlockStatement",
+ "Statement",
+ "LocalVariableDeclaration",
+ "StatementWithoutTrailingSubsta" + "tement",
+ "StatementNoShortIf",
+ "StatementExpression",
+ "PostIncrementExpression",
+ "PostDecrementExpression",
+ "MethodInvocation",
+ "ClassInstanceCreationExpressio" + "n",
+ "SwitchBlock",
+ "SwitchBlockStatements",
+ "SwitchLabels",
+ "SwitchBlockStatement",
+ "SwitchLabel",
+ "ConstantExpression",
+ "StatementExpressionList",
+ "OnlySynchronized",
+ "Catches",
+ "Finally",
+ "CatchClause",
+ "PushLPAREN",
+ "PushRPAREN",
+ "PrimaryNoNewArray",
+ "FieldAccess",
+ "ArrayAccess",
+ "ClassInstanceCreationExpressio" + "nName",
+ "ArgumentList",
+ "DimWithOrWithOutExprs",
+ "DimWithOrWithOutExpr",
+ "DimsLoop",
+ "OneDimLoop",
+ "PostfixExpression",
+ "UnaryExpression",
+ "UnaryExpressionNotPlusMinus",
+ "MultiplicativeExpression",
+ "AdditiveExpression",
+ "ShiftExpression",
+ "RelationalExpression",
+ "EqualityExpression",
+ "AndExpression",
+ "ExclusiveOrExpression",
+ "InclusiveOrExpression",
+ "ConditionalAndExpression",
+ "ConditionalOrExpression",
+ "ConditionalExpression",
+ "AssignmentExpression",
+ "LeftHandSide",
+ "AssignmentOperator" };
+
+ public static short check_table[] = null;
+ public static char lhs[] = null;
+ public static char action[] = lhs;
+ private final static String FILEPREFIX = "parser";
+
+ static {
+ try {
+ initTables();
+ } catch (java.io.IOException ex) {
+ throw new ExceptionInInitializerError(ex.getMessage());
+ }
+ }
+
+ public static final int RoundBracket = 0;
+ public static final int SquareBracket = 1;
+ public static final int CurlyBracket = 2;
+ public static final int BracketKinds = 3;
+ public Parser(ProblemReporter problemReporter) {
+ this(problemReporter, false);
+ }
+
+ public Parser(
+ ProblemReporter problemReporter,
+ boolean optimizeStringLiterals) {
+
+ this.problemReporter = problemReporter;
+ this.optimizeStringLiterals = optimizeStringLiterals;
+ this.initializeScanner();
+ astLengthStack = new int[50];
+ expressionLengthStack = new int[30];
+ intStack = new int[50];
+ identifierStack = new char[30][];
+ identifierLengthStack = new int[30];
+ nestedMethod = new int[30];
+ realBlockStack = new int[30];
+ identifierPositionStack = new long[30];
+ variablesCounter = new int[30];
+ }
+
+ /**
+ *
+ * INTERNAL USE-ONLY
+ */
+ protected void adjustInterfaceModifiers() {
+ intStack[intPtr - 1] |= AccInterface;
+ }
+
+ public final void arrayInitializer(int length) {
+ //length is the size of the array Initializer
+ //expressionPtr points on the last elt of the arrayInitializer
+ //i.e. it has not been decremented yet.
+
+ ArrayInitializer ai = new ArrayInitializer();
+ if (length != 0) {
+ expressionPtr -= length;
+ System.arraycopy(
+ expressionStack,
+ expressionPtr + 1,
+ ai.expressions = new Expression[length],
+ 0,
+ length);
+ }
+ pushOnExpressionStack(ai);
+ //positionning
+ ai.sourceEnd = endStatementPosition;
+ int searchPosition = length == 0 ? endPosition : ai.expressions[0].sourceStart;
+ try {
+ //does not work with comments(that contain '{') nor '{' describes as a unicode....
+ while (scanner.source[--searchPosition] != '{') {
+ }
+ } catch (IndexOutOfBoundsException ex) {
+ //should never occur (except for strange cases like whose describe above)
+ searchPosition =
+ (length == 0 ? endPosition : ai.expressions[0].sourceStart) - 1;
+ }
+ ai.sourceStart = searchPosition;
+ }
+
+ protected static int asi(int state) {
+
+ return asb[original_state(state)];
+ }
+
+ protected void blockReal() {
+ // See consumeLocalVariableDeclarationStatement in case of change: duplicated code
+ // increment the amount of declared variables for this block
+ realBlockStack[realBlockPtr]++;
+ }
+
+ private final static void buildFileFor(
+ String filename,
+ String tag,
+ String[] tokens,
+ boolean isShort)
+ throws java.io.IOException {
+
+ //transform the String tokens into chars before dumping then into file
+
+ int i = 0;
+ //read upto the tag
+ while (!tokens[i++].equals(tag)) {
+ }
+ //read upto the }
+ char[] chars = new char[tokens.length]; //can't be bigger
+ int ic = 0;
+ String token;
+ while (!(token = tokens[i++]).equals("}")) {
+ int c = Integer.parseInt(token);
+ if (isShort)
+ c += 32768;
+ chars[ic++] = (char) c;
+ }
+
+ //resize
+ System.arraycopy(chars, 0, chars = new char[ic], 0, ic);
+
+ buildFileForTable(filename, chars);
+ }
+
+ private final static void buildFileForTable(String filename, char[] chars)
+ throws java.io.IOException {
+
+ byte[] bytes = new byte[chars.length * 2];
+ for (int i = 0; i < chars.length; i++) {
+ bytes[2 * i] = (byte) (chars[i] >>> 8);
+ bytes[2 * i + 1] = (byte) (chars[i] & 0xFF);
+ }
+
+ java.io.FileOutputStream stream = new java.io.FileOutputStream(filename);
+ stream.write(bytes);
+ stream.close();
+
+ }
+
+ public final static void buildFilesFromLPG(String dataFilename)
+ throws java.io.IOException {
+
+ //RUN THIS METHOD TO GENERATE PARSER*.RSC FILES
+
+ //build from the lpg javadcl.java files that represents the parser tables
+ //lhs check_table asb asr symbol_index
+
+ //[org.eclipse.jdt.internal.compiler.parser.Parser.buildFilesFromLPG("d:/leapfrog/grammar/javadcl.java")]
+
+ File file = new File(dataFilename);
+ FileReader reader = null;
+ char[] contents = new char[] {
+ };
+ try {
+ reader = new FileReader(file);
+ contents = new char[(int) file.length()];
+ reader.read(contents, 0, contents.length);
+ reader.close();
+ } catch (IOException ex) {
+ System.out.println("The path for the javadcl.java file is incorrect");
+ return;
+ }
+ java.util.StringTokenizer st =
+ new java.util.StringTokenizer(new String(contents), " \t\n\r[]={,;");
+ String[] tokens = new String[st.countTokens()];
+ int i = 0;
+ while (st.hasMoreTokens()) {
+ tokens[i++] = st.nextToken();
+ }
+ final String prefix = FILEPREFIX;
+ i = 0;
+ buildFileFor(prefix + (++i) + ".rsc", "lhs", tokens, false);
+ buildFileFor(prefix + (++i) + ".rsc", "check_table", tokens, true);
+ buildFileFor(prefix + (++i) + ".rsc", "asb", tokens, false);
+ buildFileFor(prefix + (++i) + ".rsc", "asr", tokens, false);
+ buildFileFor(prefix + (++i) + ".rsc", "symbol_index", tokens, false);
+ System.out.println("MOVE FILES IN THE Runtime DIRECTORY OF Parser.class");
+ }
+
+ /*
+ * Build initial recovery state.
+ * Recovery state is inferred from the current state of the parser (reduced node stack).
+ */
+ public RecoveredElement buildInitialRecoveryState() {
+
+ if (!ENABLE_RECOVERY)
+ return null; // do not resume to recovery
+
+ /* initialize recovery by retrieving available reduced nodes
+ * also rebuild bracket balance
+ */
+ lastCheckPoint = 0;
+
+ RecoveredElement element = null;
+ if (referenceContext instanceof CompilationUnitDeclaration) {
+ element = new RecoveredUnit(compilationUnit, 0, this);
+
+ /* ignore current stack state, since restarting from the beginnning
+ since could not trust simple brace count */
+ if (true) { // experimenting restart recovery from scratch
+ compilationUnit.currentPackage = null;
+ compilationUnit.imports = null;
+ compilationUnit.types = null;
+ currentToken = 0;
+ listLength = 0;
+ return element;
+ }
+ if (compilationUnit.currentPackage != null) {
+ lastCheckPoint = compilationUnit.currentPackage.declarationSourceEnd + 1;
+ }
+ if (compilationUnit.imports != null) {
+ lastCheckPoint =
+ compilationUnit.imports[compilationUnit.imports.length
+ - 1].declarationSourceEnd
+ + 1;
+ }
+ } else {
+ if (referenceContext instanceof AbstractMethodDeclaration) {
+ element =
+ new RecoveredMethod(
+ (AbstractMethodDeclaration) referenceContext,
+ null,
+ 0,
+ this);
+ lastCheckPoint = ((AbstractMethodDeclaration) referenceContext).bodyStart;
+ } else {
+ /* Initializer bodies are parsed in the context of the type declaration, we must thus search it inside */
+ if (referenceContext instanceof TypeDeclaration) {
+ TypeDeclaration type = (TypeDeclaration) referenceContext;
+ for (int i = 0; i < type.fields.length; i++) {
+ FieldDeclaration field = type.fields[i];
+ if (field.declarationSourceStart <= scanner.initialPosition
+ && scanner.initialPosition <= field.declarationSourceEnd
+ && scanner.eofPosition <= field.declarationSourceEnd + 1) {
+ element = new RecoveredInitializer((Initializer) field, null, 1, this);
+ lastCheckPoint = field.declarationSourceStart;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (element == null)
+ return element;
+
+ for (int i = 0; i <= astPtr; i++) {
+ AstNode node = astStack[i];
+ if (node instanceof AbstractMethodDeclaration) {
+ AbstractMethodDeclaration method = (AbstractMethodDeclaration) node;
+ if (method.declarationSourceEnd == 0) {
+ element = element.add(method, 0);
+ lastCheckPoint = method.bodyStart;
+ } else {
+ element = element.add(method, 0);
+ lastCheckPoint = method.declarationSourceEnd + 1;
+ }
+ continue;
+ }
+ if (node instanceof Initializer) {
+ Initializer initializer = (Initializer) node;
+ if (initializer.declarationSourceEnd == 0) {
+ element = element.add(initializer, 1);
+ lastCheckPoint = initializer.bodyStart;
+ } else {
+ element = element.add(initializer, 0);
+ lastCheckPoint = initializer.declarationSourceEnd + 1;
+ }
+ continue;
+ }
+ if (node instanceof FieldDeclaration) {
+ FieldDeclaration field = (FieldDeclaration) node;
+ if (field.declarationSourceEnd == 0) {
+ element = element.add(field, 0);
+ if (field.initialization == null) {
+ lastCheckPoint = field.sourceEnd + 1;
+ } else {
+ lastCheckPoint = field.initialization.sourceEnd + 1;
+ }
+ } else {
+ element = element.add(field, 0);
+ lastCheckPoint = field.declarationSourceEnd + 1;
+ }
+ continue;
+ }
+ if (node instanceof TypeDeclaration) {
+ TypeDeclaration type = (TypeDeclaration) node;
+ if (type.declarationSourceEnd == 0) {
+ element = element.add(type, 0);
+ lastCheckPoint = type.bodyStart;
+ } else {
+ element = element.add(type, 0);
+ lastCheckPoint = type.declarationSourceEnd + 1;
+ }
+ continue;
+ }
+ if (node instanceof ImportReference) {
+ ImportReference importRef = (ImportReference) node;
+ element = element.add(importRef, 0);
+ lastCheckPoint = importRef.declarationSourceEnd + 1;
+ }
+ }
+ return element;
+ }
+
+ protected static short check(int i) {
+ return check_table[i - (NUM_RULES + 1)];
+ }
+
+ /*
+ * Reconsider the entire source looking for inconsistencies in {} () []
+ */
+ public boolean checkAndReportBracketAnomalies(ProblemReporter problemReporter) {
+
+ boolean anomaliesDetected = false;
+ try {
+ char[] source = scanner.source;
+ int[] leftCount = { 0, 0, 0 };
+ int[] rightCount = { 0, 0, 0 };
+ int[] depths = { 0, 0, 0 };
+ int[][] leftPositions = new int[][] { new int[10], new int[10], new int[10] };
+ int[][] leftDepths = new int[][] { new int[10], new int[10], new int[10] };
+ int[][] rightPositions = new int[][] { new int[10], new int[10], new int[10] };
+ int[][] rightDepths = new int[][] { new int[10], new int[10], new int[10] };
+ scanner.currentPosition = scanner.initialPosition;
+ //starting point (first-zero-based char)
+ while (scanner.currentPosition < scanner.eofPosition) {
+ //loop for jumping over comments
+ try {
+ // ---------Consume white space and handles startPosition---------
+ boolean isWhiteSpace;
+ do {
+ scanner.startPosition = scanner.currentPosition;
+ if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\')
+ && (source[scanner.currentPosition] == 'u')) {
+ isWhiteSpace = scanner.jumpOverUnicodeWhiteSpace();
+ } else {
+ if (scanner.recordLineSeparator
+ && ((scanner.currentCharacter == '\r') || (scanner.currentCharacter == '\n'))) {
+ if (scanner.lineEnds[scanner.linePtr] < scanner.startPosition) {
+ // only record line positions we have not recorded yet
+ scanner.pushLineSeparator();
+ }
+ }
+ isWhiteSpace = Character.isWhitespace(scanner.currentCharacter);
+ }
+ } while (isWhiteSpace && (scanner.currentPosition < scanner.eofPosition));
+
+ // -------consume token until } is found---------
+
+ switch (scanner.currentCharacter) {
+ case '{' :
+ {
+ int index = leftCount[CurlyBracket]++;
+ if (index == leftPositions[CurlyBracket].length) {
+ System.arraycopy(
+ leftPositions[CurlyBracket],
+ 0,
+ (leftPositions[CurlyBracket] = new int[index * 2]),
+ 0,
+ index);
+ System.arraycopy(
+ leftDepths[CurlyBracket],
+ 0,
+ (leftDepths[CurlyBracket] = new int[index * 2]),
+ 0,
+ index);
+ }
+ leftPositions[CurlyBracket][index] = scanner.startPosition;
+ leftDepths[CurlyBracket][index] = depths[CurlyBracket]++;
+ }
+ break;
+ case '}' :
+ {
+ int index = rightCount[CurlyBracket]++;
+ if (index == rightPositions[CurlyBracket].length) {
+ System.arraycopy(
+ rightPositions[CurlyBracket],
+ 0,
+ (rightPositions[CurlyBracket] = new int[index * 2]),
+ 0,
+ index);
+ System.arraycopy(
+ rightDepths[CurlyBracket],
+ 0,
+ (rightDepths[CurlyBracket] = new int[index * 2]),
+ 0,
+ index);
+ }
+ rightPositions[CurlyBracket][index] = scanner.startPosition;
+ rightDepths[CurlyBracket][index] = --depths[CurlyBracket];
+ }
+ break;
+ case '(' :
+ {
+ int index = leftCount[RoundBracket]++;
+ if (index == leftPositions[RoundBracket].length) {
+ System.arraycopy(
+ leftPositions[RoundBracket],
+ 0,
+ (leftPositions[RoundBracket] = new int[index * 2]),
+ 0,
+ index);
+ System.arraycopy(
+ leftDepths[RoundBracket],
+ 0,
+ (leftDepths[RoundBracket] = new int[index * 2]),
+ 0,
+ index);
+ }
+ leftPositions[RoundBracket][index] = scanner.startPosition;
+ leftDepths[RoundBracket][index] = depths[RoundBracket]++;
+ }
+ break;
+ case ')' :
+ {
+ int index = rightCount[RoundBracket]++;
+ if (index == rightPositions[RoundBracket].length) {
+ System.arraycopy(
+ rightPositions[RoundBracket],
+ 0,
+ (rightPositions[RoundBracket] = new int[index * 2]),
+ 0,
+ index);
+ System.arraycopy(
+ rightDepths[RoundBracket],
+ 0,
+ (rightDepths[RoundBracket] = new int[index * 2]),
+ 0,
+ index);
+ }
+ rightPositions[RoundBracket][index] = scanner.startPosition;
+ rightDepths[RoundBracket][index] = --depths[RoundBracket];
+ }
+ break;
+ case '[' :
+ {
+ int index = leftCount[SquareBracket]++;
+ if (index == leftPositions[SquareBracket].length) {
+ System.arraycopy(
+ leftPositions[SquareBracket],
+ 0,
+ (leftPositions[SquareBracket] = new int[index * 2]),
+ 0,
+ index);
+ System.arraycopy(
+ leftDepths[SquareBracket],
+ 0,
+ (leftDepths[SquareBracket] = new int[index * 2]),
+ 0,
+ index);
+ }
+ leftPositions[SquareBracket][index] = scanner.startPosition;
+ leftDepths[SquareBracket][index] = depths[SquareBracket]++;
+ }
+ break;
+ case ']' :
+ {
+ int index = rightCount[SquareBracket]++;
+ if (index == rightPositions[SquareBracket].length) {
+ System.arraycopy(
+ rightPositions[SquareBracket],
+ 0,
+ (rightPositions[SquareBracket] = new int[index * 2]),
+ 0,
+ index);
+ System.arraycopy(
+ rightDepths[SquareBracket],
+ 0,
+ (rightDepths[SquareBracket] = new int[index * 2]),
+ 0,
+ index);
+ }
+ rightPositions[SquareBracket][index] = scanner.startPosition;
+ rightDepths[SquareBracket][index] = --depths[SquareBracket];
+ }
+ break;
+ case '\'' :
+ {
+ boolean test;
+ if (test = scanner.getNextChar('\\')) {
+ scanner.scanEscapeCharacter();
+ } else { // consume next character
+ scanner.unicodeAsBackSlash = false;
+ if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\')
+ && (source[scanner.currentPosition] == 'u')) {
+ scanner.getNextUnicodeChar();
+ } else {
+ if (scanner.withoutUnicodePtr != 0) {
+ scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] =
+ scanner.currentCharacter;
+ }
+ }
+ }
+ scanner.getNextChar('\'');
+ break;
+ }
+ case '"' : // consume next character
+ scanner.unicodeAsBackSlash = false;
+ if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\')
+ && (source[scanner.currentPosition] == 'u')) {
+ scanner.getNextUnicodeChar();
+ } else {
+ if (scanner.withoutUnicodePtr != 0) {
+ scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] =
+ scanner.currentCharacter;
+ }
+ }
+ while (scanner.currentCharacter != '"') {
+ if (scanner.currentCharacter == '\r') {
+ if (source[scanner.currentPosition] == '\n')
+ scanner.currentPosition++;
+ break; // the string cannot go further that the line
+ }
+ if (scanner.currentCharacter == '\n') {
+ break; // the string cannot go further that the line
+ }
+ if (scanner.currentCharacter == '\\') {
+ scanner.scanEscapeCharacter();
+ }
+ // consume next character
+ scanner.unicodeAsBackSlash = false;
+ if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\')
+ && (source[scanner.currentPosition] == 'u')) {
+ scanner.getNextUnicodeChar();
+ } else {
+ if (scanner.withoutUnicodePtr != 0) {
+ scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] =
+ scanner.currentCharacter;
+ }
+ }
+ }
+ break;
+ case '/' :
+ {
+ int test;
+ if ((test = scanner.getNextChar('/', '*')) == 0) { //line comment
+ //get the next char
+ if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\')
+ && (source[scanner.currentPosition] == 'u')) {
+ //-------------unicode traitement ------------
+ int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
+ scanner.currentPosition++;
+ while (source[scanner.currentPosition] == 'u') {
+ scanner.currentPosition++;
+ }
+ if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
+ || c1 < 0
+ || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
+ || c2 < 0
+ || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
+ || c3 < 0
+ || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
+ || c4 < 0) { //error don't care of the value
+ scanner.currentCharacter = 'A';
+ } //something different from \n and \r
+ else {
+ scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+ }
+ }
+ while (scanner.currentCharacter != '\r' && scanner.currentCharacter != '\n') {
+ //get the next char
+ scanner.startPosition = scanner.currentPosition;
+ if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\')
+ && (source[scanner.currentPosition] == 'u')) {
+ //-------------unicode traitement ------------
+ int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
+ scanner.currentPosition++;
+ while (source[scanner.currentPosition] == 'u') {
+ scanner.currentPosition++;
+ }
+ if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
+ || c1 < 0
+ || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
+ || c2 < 0
+ || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
+ || c3 < 0
+ || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
+ || c4 < 0) { //error don't care of the value
+ scanner.currentCharacter = 'A';
+ } //something different from \n and \r
+ else {
+ scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+ }
+ }
+ }
+ if (scanner.recordLineSeparator
+ && ((scanner.currentCharacter == '\r') || (scanner.currentCharacter == '\n'))) {
+ if (scanner.lineEnds[scanner.linePtr] < scanner.startPosition) {
+ // only record line positions we have not recorded yet
+ scanner.pushLineSeparator();
+ }
+ }
+ break;
+ }
+ if (test > 0) { //traditional and annotation comment
+ boolean star = false;
+ // consume next character
+ scanner.unicodeAsBackSlash = false;
+ if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\')
+ && (source[scanner.currentPosition] == 'u')) {
+ scanner.getNextUnicodeChar();
+ } else {
+ if (scanner.withoutUnicodePtr != 0) {
+ scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] =
+ scanner.currentCharacter;
+ }
+ }
+ if (scanner.currentCharacter == '*') {
+ star = true;
+ }
+ //get the next char
+ if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\')
+ && (source[scanner.currentPosition] == 'u')) {
+ //-------------unicode traitement ------------
+ int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
+ scanner.currentPosition++;
+ while (source[scanner.currentPosition] == 'u') {
+ scanner.currentPosition++;
+ }
+ if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
+ || c1 < 0
+ || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
+ || c2 < 0
+ || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
+ || c3 < 0
+ || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
+ || c4 < 0) { //error don't care of the value
+ scanner.currentCharacter = 'A';
+ } //something different from * and /
+ else {
+ scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+ }
+ }
+ //loop until end of comment */
+ while ((scanner.currentCharacter != '/') || (!star)) {
+ star = scanner.currentCharacter == '*';
+ //get next char
+ if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\')
+ && (source[scanner.currentPosition] == 'u')) {
+ //-------------unicode traitement ------------
+ int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
+ scanner.currentPosition++;
+ while (source[scanner.currentPosition] == 'u') {
+ scanner.currentPosition++;
+ }
+ if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
+ || c1 < 0
+ || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
+ || c2 < 0
+ || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
+ || c3 < 0
+ || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
+ || c4 < 0) { //error don't care of the value
+ scanner.currentCharacter = 'A';
+ } //something different from * and /
+ else {
+ scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+ }
+ }
+ }
+ break;
+ }
+ break;
+ }
+ default :
+ if (Character.isJavaIdentifierStart(scanner.currentCharacter)) {
+ scanner.scanIdentifierOrKeyword();
+ break;
+ }
+ if (Character.isDigit(scanner.currentCharacter)) {
+ scanner.scanNumber(false);
+ break;
+ }
+ }
+ //-----------------end switch while try--------------------
+ } catch (IndexOutOfBoundsException e) {
+ break; // read until EOF
+ } catch (InvalidInputException e) {
+ return false; // no clue
+ }
+ }
+ if (scanner.recordLineSeparator) {
+ compilationUnit.compilationResult.lineSeparatorPositions = scanner.lineEnds();
+ }
+
+ // check placement anomalies against other kinds of brackets
+ for (int kind = 0; kind < BracketKinds; kind++) {
+ for (int leftIndex = leftCount[kind] - 1; leftIndex >= 0; leftIndex--) {
+ int start = leftPositions[kind][leftIndex]; // deepest first
+ // find matching closing bracket
+ int depth = leftDepths[kind][leftIndex];
+ int end = -1;
+ for (int i = 0; i < rightCount[kind]; i++) {
+ int pos = rightPositions[kind][i];
+ // want matching bracket further in source with same depth
+ if ((pos > start) && (depth == rightDepths[kind][i])) {
+ end = pos;
+ break;
+ }
+ }
+ if (end < 0) { // did not find a good closing match
+ problemReporter.unmatchedBracket(
+ start,
+ referenceContext,
+ compilationUnit.compilationResult);
+ return true;
+ }
+ // check if even number of opening/closing other brackets in between this pair of brackets
+ int balance = 0;
+ for (int otherKind = 0;
+ (balance == 0) && (otherKind < BracketKinds);
+ otherKind++) {
+ for (int i = 0; i < leftCount[otherKind]; i++) {
+ int pos = leftPositions[otherKind][i];
+ if ((pos > start) && (pos < end))
+ balance++;
+ }
+ for (int i = 0; i < rightCount[otherKind]; i++) {
+ int pos = rightPositions[otherKind][i];
+ if ((pos > start) && (pos < end))
+ balance--;
+ }
+ if (balance != 0) {
+ problemReporter.unmatchedBracket(
+ start,
+ referenceContext,
+ compilationUnit.compilationResult);
+ //bracket anomaly
+ return true;
+ }
+ }
+ }
+ // too many opening brackets ?
+ for (int i = rightCount[kind]; i < leftCount[kind]; i++) {
+ anomaliesDetected = true;
+ problemReporter.unmatchedBracket(
+ leftPositions[kind][leftCount[kind] - i - 1],
+ referenceContext,
+ compilationUnit.compilationResult);
+ }
+ // too many closing brackets ?
+ for (int i = leftCount[kind]; i < rightCount[kind]; i++) {
+ anomaliesDetected = true;
+ problemReporter.unmatchedBracket(
+ rightPositions[kind][i],
+ referenceContext,
+ compilationUnit.compilationResult);
+ }
+ if (anomaliesDetected)
+ return true;
+ }
+
+ return anomaliesDetected;
+ } catch (ArrayStoreException e) { // jdk1.2.2 jit bug
+ return anomaliesDetected;
+ } catch (NullPointerException e) { // jdk1.2.2 jit bug
+ return anomaliesDetected;
+ }
+ }
+
+ public final void checkAndSetModifiers(int flag) {
+ /*modify the current modifiers buffer.
+ When the startPosition of the modifiers is 0
+ it means that the modifier being parsed is the first
+ of a list of several modifiers. The startPosition
+ is zeroed when a copy of modifiers-buffer is push
+ onto the astStack. */
+
+ if ((modifiers & flag) != 0) { // duplicate modifier
+ modifiers |= AccAlternateModifierProblem;
+ }
+ modifiers |= flag;
+
+ if (modifiersSourceStart < 0)
+ modifiersSourceStart = scanner.startPosition;
+ }
+
+ public void checkAnnotation() {
+
+ boolean deprecated = false;
+ int lastAnnotationIndex = -1;
+
+ //since jdk1.2 look only in the last java doc comment...
+ found : {
+ if ((lastAnnotationIndex = scanner.commentPtr) >= 0) { //look for @deprecated
+ scanner.commentPtr = -1;
+ // reset the comment stack, since not necessary after having checked
+ int commentSourceStart = scanner.commentStarts[lastAnnotationIndex];
+ // javadoc only (non javadoc comment have negative end positions.)
+ int commentSourceEnd = scanner.commentStops[lastAnnotationIndex] - 1;
+ //stop is one over
+ char[] comment = scanner.source;
+
+ for (int i = commentSourceStart + 3; i < commentSourceEnd - 10; i++) {
+ if ((comment[i] == '@')
+ && (comment[i + 1] == 'd')
+ && (comment[i + 2] == 'e')
+ && (comment[i + 3] == 'p')
+ && (comment[i + 4] == 'r')
+ && (comment[i + 5] == 'e')
+ && (comment[i + 6] == 'c')
+ && (comment[i + 7] == 'a')
+ && (comment[i + 8] == 't')
+ && (comment[i + 9] == 'e')
+ && (comment[i + 10] == 'd')) {
+ // ensure the tag is properly ended: either followed by a space, line end or asterisk.
+ int nextPos = i + 11;
+ deprecated =
+ (comment[nextPos] == ' ')
+ || (comment[nextPos] == '\n')
+ || (comment[nextPos] == '\r')
+ || (comment[nextPos] == '*');
+ break found;
+ }
+ }
+ }
+ }
+ if (deprecated) {
+ checkAndSetModifiers(AccDeprecated);
+ }
+ // modify the modifier source start to point at the first comment
+ if (lastAnnotationIndex >= 0) {
+ modifiersSourceStart = scanner.commentStarts[0];
+ }
+ }
+
+ protected void classInstanceCreation(boolean alwaysQualified) {
+ // ClassInstanceCreationExpression ::= 'new' ClassType '(' ArgumentListopt ')' ClassBodyopt
+
+ // ClassBodyopt produces a null item on the astStak if it produces NO class body
+ // An empty class body produces a 0 on the length stack.....
+
+ AllocationExpression alloc;
+ int length;
+ if (((length = astLengthStack[astLengthPtr--]) == 1)
+ && (astStack[astPtr] == null)) {
+ //NO ClassBody
+ astPtr--;
+ if (alwaysQualified) {
+ alloc = new QualifiedAllocationExpression();
+ } else {
+ alloc = new AllocationExpression();
+ }
+ alloc.sourceEnd = endPosition; //the position has been stored explicitly
+
+ if ((length = expressionLengthStack[expressionLengthPtr--]) != 0) {
+ expressionPtr -= length;
+ System.arraycopy(
+ expressionStack,
+ expressionPtr + 1,
+ alloc.arguments = new Expression[length],
+ 0,
+ length);
+ }
+ alloc.type = getTypeReference(0);
+ //the default constructor with the correct number of argument
+ //will be created and added by the TC (see createsInternalConstructorWithBinding)
+ alloc.sourceStart = intStack[intPtr--];
+ pushOnExpressionStack(alloc);
+ } else {
+ dispatchDeclarationInto(length);
+ AnonymousLocalTypeDeclaration anonymousTypeDeclaration =
+ (AnonymousLocalTypeDeclaration) astStack[astPtr];
+ anonymousTypeDeclaration.declarationSourceEnd = endStatementPosition;
+ astPtr--;
+ astLengthPtr--;
+ }
+ }
+
+ protected final void concatExpressionLists() {
+ expressionLengthStack[--expressionLengthPtr]++;
+ }
+
+ private final void concatNodeLists() {
+ /*
+ * This is a case where you have two sublists into the astStack that you want
+ * to merge in one list. There is no action required on the astStack. The only
+ * thing you need to do is merge the two lengths specified on the astStackLength.
+ * The top two length are for example:
+ * ... p n
+ * and you want to result in a list like:
+ * ... n+p
+ * This means that the p could be equals to 0 in case there is no astNode pushed
+ * on the astStack.
+ * Look at the InterfaceMemberDeclarations for an example.
+ */
+
+ astLengthStack[astLengthPtr - 1] += astLengthStack[astLengthPtr--];
+ }
+
+ protected void consumeAllocationHeader() {
+ // ClassInstanceCreationExpression ::= 'new' ClassType '(' ArgumentListopt ')' ClassBodyopt
+
+ // ClassBodyopt produces a null item on the astStak if it produces NO class body
+ // An empty class body produces a 0 on the length stack.....
+
+ if (currentElement == null) {
+ return; // should never occur, this consumeRule is only used in recovery mode
+ }
+ if (currentToken == TokenNameLBRACE) {
+ // beginning of an anonymous type
+ AnonymousLocalTypeDeclaration anonymousType =
+ new AnonymousLocalTypeDeclaration();
+ anonymousType.sourceStart = intStack[intPtr--];
+ anonymousType.sourceEnd = rParenPos; // closing parenthesis
+ lastCheckPoint = anonymousType.bodyStart = scanner.currentPosition;
+ currentElement = currentElement.add(anonymousType, 0);
+ lastIgnoredToken = -1;
+ currentToken = 0; // opening brace already taken into account
+ return;
+ }
+ lastCheckPoint = scanner.startPosition;
+ // force to restart at this exact position
+ restartRecovery = true; // request to restart from here on
+ }
+
+ protected void consumeArgumentList() {
+ // ArgumentList ::= ArgumentList ',' Expression
+ concatExpressionLists();
+ }
+
+ protected void consumeArrayAccess(boolean unspecifiedReference) {
+ // ArrayAccess ::= Name '[' Expression ']' ==> true
+ // ArrayAccess ::= PrimaryNoNewArray '[' Expression ']' ==> false
+
+ //optimize push/pop
+ Expression exp;
+ if (unspecifiedReference) {
+ exp =
+ expressionStack[expressionPtr] =
+ new ArrayReference(
+ getUnspecifiedReferenceOptimized(),
+ expressionStack[expressionPtr]);
+ } else {
+ expressionPtr--;
+ expressionLengthPtr--;
+ exp =
+ expressionStack[expressionPtr] =
+ new ArrayReference(
+ expressionStack[expressionPtr],
+ expressionStack[expressionPtr + 1]);
+ }
+ exp.sourceEnd = endPosition;
+ }
+
+ protected void consumeArrayCreationExpression() {
+ // ArrayCreationExpression ::= 'new' PrimitiveType DimWithOrWithOutExprs ArrayInitializeropt
+ // ArrayCreationExpression ::= 'new' ClassOrInterfaceType DimWithOrWithOutExprs ArrayInitializeropt
+
+ int length;
+ ArrayAllocationExpression aae = new ArrayAllocationExpression();
+ if (expressionLengthStack[expressionLengthPtr] != 0) {
+ expressionLengthPtr--;
+ aae.initializer = (ArrayInitializer) expressionStack[expressionPtr--];
+ } else {
+ expressionLengthPtr--;
+ }
+
+ aae.type = getTypeReference(0);
+ length = (expressionLengthStack[expressionLengthPtr--]);
+ expressionPtr -= length;
+ System.arraycopy(
+ expressionStack,
+ expressionPtr + 1,
+ aae.dimensions = new Expression[length],
+ 0,
+ length);
+ aae.sourceStart = intStack[intPtr--];
+ if (aae.initializer == null) {
+ aae.sourceEnd = endPosition;
+ } else {
+ aae.sourceEnd = aae.initializer.sourceEnd;
+ }
+ pushOnExpressionStack(aae);
+ }
+
+ protected void consumeArrayInitializer() {
+ // ArrayInitializer ::= '{' VariableInitializers '}'
+ // ArrayInitializer ::= '{' VariableInitializers , '}'
+
+ arrayInitializer(expressionLengthStack[expressionLengthPtr--]);
+ }
+
+ protected void consumeAssignment() {
+ // Assignment ::= LeftHandSide AssignmentOperator AssignmentExpression
+ //optimize the push/pop
+
+ int op = intStack[intPtr--]; //<--the encoded operator
+
+ expressionPtr--;
+ expressionLengthPtr--;
+ expressionStack[expressionPtr] =
+ (op != EQUAL)
+ ? new CompoundAssignment(
+ expressionStack[expressionPtr],
+ expressionStack[expressionPtr + 1],
+ op)
+ : new Assignment(
+ expressionStack[expressionPtr],
+ expressionStack[expressionPtr + 1]);
+ }
+
+ protected void consumeAssignmentOperator(int pos) {
+ // AssignmentOperator ::= '='
+ // AssignmentOperator ::= '*='
+ // AssignmentOperator ::= '/='
+ // AssignmentOperator ::= '%='
+ // AssignmentOperator ::= '+='
+ // AssignmentOperator ::= '-='
+ // AssignmentOperator ::= '<<='
+ // AssignmentOperator ::= '>>='
+ // AssignmentOperator ::= '>>>='
+ // AssignmentOperator ::= '&='
+ // AssignmentOperator ::= '^='
+ // AssignmentOperator ::= '|='
+
+ try {
+ intStack[++intPtr] = pos;
+ } catch (IndexOutOfBoundsException e) {
+ //intPtr is correct
+ int oldStackLength = intStack.length;
+ int oldStack[] = intStack;
+ intStack = new int[oldStackLength + StackIncrement];
+ System.arraycopy(oldStack, 0, intStack, 0, oldStackLength);
+ intStack[intPtr] = pos;
+ }
+ }
+
+ protected void consumeBinaryExpression(int op) {
+ // MultiplicativeExpression ::= MultiplicativeExpression '*' UnaryExpression
+ // MultiplicativeExpression ::= MultiplicativeExpression '/' UnaryExpression
+ // MultiplicativeExpression ::= MultiplicativeExpression '%' UnaryExpression
+ // AdditiveExpression ::= AdditiveExpression '+' MultiplicativeExpression
+ // AdditiveExpression ::= AdditiveExpression '-' MultiplicativeExpression
+ // ShiftExpression ::= ShiftExpression '<<' AdditiveExpression
+ // ShiftExpression ::= ShiftExpression '>>' AdditiveExpression
+ // ShiftExpression ::= ShiftExpression '>>>' AdditiveExpression
+ // RelationalExpression ::= RelationalExpression '<' ShiftExpression
+ // RelationalExpression ::= RelationalExpression '>' ShiftExpression
+ // RelationalExpression ::= RelationalExpression '<=' ShiftExpression
+ // RelationalExpression ::= RelationalExpression '>=' ShiftExpression
+ // AndExpression ::= AndExpression '&' EqualityExpression
+ // ExclusiveOrExpression ::= ExclusiveOrExpression '^' AndExpression
+ // InclusiveOrExpression ::= InclusiveOrExpression '|' ExclusiveOrExpression
+ // ConditionalAndExpression ::= ConditionalAndExpression '&&' InclusiveOrExpression
+ // ConditionalOrExpression ::= ConditionalOrExpression '||' ConditionalAndExpression
+
+ //optimize the push/pop
+
+ expressionPtr--;
+ expressionLengthPtr--;
+ if (op == OR_OR) {
+ expressionStack[expressionPtr] =
+ new OR_OR_Expression(
+ expressionStack[expressionPtr],
+ expressionStack[expressionPtr + 1],
+ op);
+ } else {
+ if (op == AND_AND) {
+ expressionStack[expressionPtr] =
+ new AND_AND_Expression(
+ expressionStack[expressionPtr],
+ expressionStack[expressionPtr + 1],
+ op);
+ } else {
+ // look for "string1" + "string2"
+ if ((op == PLUS) && optimizeStringLiterals) {
+ Expression expr1, expr2;
+ expr1 = expressionStack[expressionPtr];
+ expr2 = expressionStack[expressionPtr + 1];
+ if (expr1 instanceof StringLiteral) {
+ if (expr2 instanceof CharLiteral) { // string+char
+ expressionStack[expressionPtr] =
+ ((StringLiteral) expr1).extendWith((CharLiteral) expr2);
+ } else
+ if (expr2 instanceof StringLiteral) { //string+string
+ expressionStack[expressionPtr] =
+ ((StringLiteral) expr1).extendWith((StringLiteral) expr2);
+ } else {
+ expressionStack[expressionPtr] = new BinaryExpression(expr1, expr2, PLUS);
+ }
+ } else {
+ expressionStack[expressionPtr] = new BinaryExpression(expr1, expr2, PLUS);
+ }
+ } else {
+ expressionStack[expressionPtr] =
+ new BinaryExpression(
+ expressionStack[expressionPtr],
+ expressionStack[expressionPtr + 1],
+ op);
+ }
+ }
+ }
+ }
+
+ protected void consumeBlock() {
+ // Block ::= OpenBlock '{' BlockStatementsopt '}'
+ // simpler action for empty blocks
+
+ int length;
+ if ((length = astLengthStack[astLengthPtr--]) == 0) { // empty block
+ pushOnAstStack(Block.EmptyWith(intStack[intPtr--], endStatementPosition));
+ realBlockPtr--; // still need to pop the block variable counter
+ } else {
+ Block bk = new Block(realBlockStack[realBlockPtr--]);
+ astPtr -= length;
+ System.arraycopy(
+ astStack,
+ astPtr + 1,
+ bk.statements = new Statement[length],
+ 0,
+ length);
+ pushOnAstStack(bk);
+ bk.sourceStart = intStack[intPtr--];
+ bk.sourceEnd = endStatementPosition;
+ }
+ }
+
+ protected void consumeBlockStatements() {
+ // BlockStatements ::= BlockStatements BlockStatement
+ concatNodeLists();
+ }
+
+ protected void consumeCaseLabel() {
+ // SwitchLabel ::= 'case' ConstantExpression ':'
+ expressionLengthPtr--;
+ pushOnAstStack(new Case(expressionStack[expressionPtr--]));
+ }
+
+ protected void consumeCastExpression() {
+ // CastExpression ::= PushLPAREN PrimitiveType Dimsopt PushRPAREN UnaryExpression
+ // CastExpression ::= PushLPAREN Name Dims PushRPAREN UnaryExpressionNotPlusMinus
+
+ //intStack : posOfLeftParen dim posOfRightParen
+
+ //optimize the push/pop
+
+ Expression exp, cast, castType;
+ int end = intStack[intPtr--];
+ expressionStack[expressionPtr] =
+ cast =
+ new CastExpression(
+ exp = expressionStack[expressionPtr],
+ castType = getTypeReference(intStack[intPtr--]));
+ castType.sourceEnd = end - 1;
+ castType.sourceStart = (cast.sourceStart = intStack[intPtr--]) + 1;
+ cast.sourceEnd = exp.sourceEnd;
+ }
+
+ protected void consumeCastExpressionLL1() {
+ //CastExpression ::= '(' Expression ')' UnaryExpressionNotPlusMinus
+ // Expression is used in order to make the grammar LL1
+
+ //optimize push/pop
+
+ Expression castType, cast, exp;
+ expressionPtr--;
+ expressionStack[expressionPtr] =
+ cast =
+ new CastExpression(
+ exp = expressionStack[expressionPtr + 1],
+ castType = getTypeReference(expressionStack[expressionPtr]));
+ expressionLengthPtr--;
+ updateSourcePosition(castType);
+ cast.sourceStart = castType.sourceStart;
+ cast.sourceEnd = exp.sourceEnd;
+ castType.sourceStart++;
+ castType.sourceEnd--;
+ }
+
+ protected void consumeCatches() {
+ // Catches ::= Catches CatchClause
+ optimizedConcatNodeLists();
+ }
+
+ protected void consumeCatchHeader() {
+ // CatchDeclaration ::= 'catch' '(' FormalParameter ')' '{'
+
+ if (currentElement == null) {
+ return; // should never occur, this consumeRule is only used in recovery mode
+ }
+ // current element should be a block due to the presence of the opening brace
+ if (!(currentElement instanceof RecoveredBlock)) {
+ return;
+ }
+ // exception argument is already on astStack
+ ((RecoveredBlock) currentElement).attach(
+ new RecoveredLocalVariable((Argument) astStack[astPtr--], currentElement, 0));
+ // insert catch variable in catch block
+ lastCheckPoint = scanner.startPosition;
+ // force to restart at this exact position
+ restartRecovery = true; // request to restart from here on
+ lastIgnoredToken = -1;
+ }
+
+ protected void consumeClassBodyDeclaration() {
+ // ClassBodyDeclaration ::= Diet Block
+ //push an Initializer
+ //optimize the push/pop
+ nestedMethod[nestedType]--;
+ Initializer initializer = new Initializer((Block) astStack[astPtr], 0);
+ astStack[astPtr] = initializer;
+ initializer.sourceEnd = endStatementPosition;
+ initializer.declarationSourceEnd =
+ flushAnnotationsDefinedPriorTo(endStatementPosition);
+ }
+
+ protected void consumeClassBodyDeclarations() {
+ // ClassBodyDeclarations ::= ClassBodyDeclarations ClassBodyDeclaration
+ concatNodeLists();
+ }
+
+ protected void consumeClassBodyDeclarationsopt() {
+ // ClassBodyDeclarationsopt ::= NestedType ClassBodyDeclarations
+ nestedType--;
+ }
+
+ protected void consumeClassBodyopt() {
+ // ClassBodyopt ::= $empty
+ pushOnAstStack(null);
+ endPosition = scanner.startPosition - 1;
+ }
+
+ protected void consumeClassDeclaration() {
+ // ClassDeclaration ::= ClassHeader ClassBody
+
+ int length;
+ if ((length = astLengthStack[astLengthPtr--]) != 0) {
+ //there are length declarations
+ //dispatch according to the type of the declarations
+ dispatchDeclarationInto(length);
+ }
+
+ TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr];
+
+ //convert constructor that do not have the type's name into methods
+ boolean hasConstructor = typeDecl.checkConstructors(this);
+
+ //add the default constructor when needed (interface don't have it)
+ if (!hasConstructor) {
+ typeDecl.createsInternalConstructor(true, true);
+ }
+
+ //always add <clinit> (will be remove at code gen time if empty)
+ typeDecl.addClinit();
+ typeDecl.declarationSourceEnd =
+ flushAnnotationsDefinedPriorTo(endStatementPosition);
+ }
+
+ protected void consumeClassHeader() {
+ // ClassHeader ::= ClassHeaderName ClassHeaderExtendsopt ClassHeaderImplementsopt
+
+ TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr];
+ if (currentToken == TokenNameLBRACE) {
+ typeDecl.bodyStart = scanner.currentPosition;
+ }
+ if (currentElement != null) {
+ restartRecovery = true;
+ // used to avoid branching back into the regular automaton
+ }
+ // flush the comments related to the class header
+ scanner.commentPtr = -1;
+ }
+
+ protected void consumeClassHeaderExtends() {
+ // ClassHeaderExtends ::= 'extends' ClassType
+ // There is a class declaration on the top of stack
+ TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr];
+ //superclass
+ typeDecl.superclass = getTypeReference(0);
+ typeDecl.bodyStart = typeDecl.superclass.sourceEnd + 1;
+ // recovery
+ if (currentElement != null) {
+ lastCheckPoint = typeDecl.bodyStart;
+ }
+ }
+
+ protected void consumeClassHeaderImplements() {
+ // ClassHeaderImplements ::= 'implements' InterfaceTypeList
+ int length = astLengthStack[astLengthPtr--];
+ //super interfaces
+ astPtr -= length;
+ // There is a class declaration on the top of stack
+ TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr];
+ System.arraycopy(
+ astStack,
+ astPtr + 1,
+ typeDecl.superInterfaces = new TypeReference[length],
+ 0,
+ length);
+ typeDecl.bodyStart = typeDecl.superInterfaces[length - 1].sourceEnd + 1;
+ listLength = 0; // reset after having read super-interfaces
+ // recovery
+ if (currentElement != null) { // is recovering
+ lastCheckPoint = typeDecl.bodyStart;
+ }
+ }
+
+ protected void consumeClassHeaderName() {
+ // ClassHeaderName ::= Modifiersopt 'class' 'Identifier'
+ TypeDeclaration typeDecl;
+ int length;
+ if (nestedMethod[nestedType] == 0) {
+ if (nestedType != 0) {
+ typeDecl = new MemberTypeDeclaration();
+ } else {
+ typeDecl = new TypeDeclaration();
+ }
+ } else {
+ // Record that the block has a declaration for local types
+ typeDecl = new LocalTypeDeclaration();
+ blockReal();
+ }
+
+ //highlight the name of the type
+ long pos = identifierPositionStack[identifierPtr];
+ typeDecl.sourceEnd = (int) pos;
+ typeDecl.sourceStart = (int) (pos >>> 32);
+ typeDecl.name = identifierStack[identifierPtr--];
+ identifierLengthPtr--;
+
+ //compute the declaration source too
+ typeDecl.declarationSourceStart = intStack[intPtr--];
+ // 'class' and 'interface' push an int position
+ typeDecl.modifiersSourceStart = intStack[intPtr--];
+ typeDecl.modifiers = intStack[intPtr--];
+ if (typeDecl.modifiersSourceStart >= 0) {
+ typeDecl.declarationSourceStart = typeDecl.modifiersSourceStart;
+ }
+ typeDecl.bodyStart = typeDecl.sourceEnd + 1;
+ pushOnAstStack(typeDecl);
+
+ listLength = 0; // will be updated when reading super-interfaces
+ // recovery
+ if (currentElement != null) {
+ lastCheckPoint = typeDecl.bodyStart;
+ currentElement = currentElement.add(typeDecl, 0);
+ lastIgnoredToken = -1;
+ }
+ }
+
+ protected void consumeClassInstanceCreationExpression() {
+ // ClassInstanceCreationExpression ::= 'new' ClassType '(' ArgumentListopt ')' ClassBodyopt
+ classInstanceCreation(false);
+ }
+
+ protected void consumeClassInstanceCreationExpressionName() {
+ // ClassInstanceCreationExpressionName ::= Name '.'
+ pushOnExpressionStack(getUnspecifiedReferenceOptimized());
+ }
+
+ protected void consumeClassInstanceCreationExpressionQualified() {
+ // ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
+ // ClassInstanceCreationExpression ::= ClassInstanceCreationExpressionName 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
+
+ classInstanceCreation(true); // <-- push the Qualifed....
+
+ expressionLengthPtr--;
+ QualifiedAllocationExpression qae =
+ (QualifiedAllocationExpression) expressionStack[expressionPtr--];
+ qae.enclosingInstance = expressionStack[expressionPtr];
+ expressionStack[expressionPtr] = qae;
+ qae.sourceStart = qae.enclosingInstance.sourceStart;
+ }
+
+ protected void consumeClassTypeElt() {
+ // ClassTypeElt ::= ClassType
+ pushOnAstStack(getTypeReference(0));
+ /* if incomplete thrown exception list, listLength counter will not have been reset,
+ indicating that some items are available on the stack */
+ listLength++;
+ }
+
+ protected void consumeClassTypeList() {
+ // ClassTypeList ::= ClassTypeList ',' ClassTypeElt
+ optimizedConcatNodeLists();
+ }
+
+ protected void consumeCompilationUnit() {
+ // CompilationUnit ::= EnterCompilationUnit PackageDeclarationopt ImportDeclarationsopt
+ // do nothing by default
+ }
+
+ protected void consumeConditionalExpression(int op) {
+ // ConditionalExpression ::= ConditionalOrExpression '?' Expression ':' ConditionalExpression
+ //optimize the push/pop
+
+ expressionPtr -= 2;
+ expressionLengthPtr -= 2;
+ expressionStack[expressionPtr] =
+ new ConditionalExpression(
+ expressionStack[expressionPtr],
+ expressionStack[expressionPtr + 1],
+ expressionStack[expressionPtr + 2]);
+ }
+
+ protected void consumeConstructorBlockStatements() {
+ // ConstructorBody ::= NestedMethod '{' ExplicitConstructorInvocation BlockStatements '}'
+ concatNodeLists();
+ // explictly add the first statement into the list of statements
+ }
+
+ protected void consumeConstructorBody() {
+ // ConstructorBody ::= NestedMethod '{' BlockStatementsopt '}'
+ // ConstructorBody ::= NestedMethod '{' ExplicitConstructorInvocation '}'
+ nestedMethod[nestedType]--;
+ }
+
+ protected void consumeConstructorDeclaration() {
+ // ConstructorDeclaration ::= ConstructorHeader ConstructorBody
+
+ /*
+ astStack : MethodDeclaration statements
+ identifierStack : name
+ ==>
+ astStack : MethodDeclaration
+ identifierStack :
+ */
+
+ //must provide a default constructor call when needed
+
+ int length;
+
+ // pop the position of the { (body of the method) pushed in block decl
+ intPtr--;
+
+ //statements
+ int explicitDeclarations = realBlockStack[realBlockPtr--];
+ ExplicitConstructorCall constructorCall = null;
+ Statement[] statements = null;
+ if ((length = astLengthStack[astLengthPtr--]) != 0) {
+ astPtr -= length;
+ if (astStack[astPtr + 1] instanceof ExplicitConstructorCall) {
+ //avoid a isSomeThing that would only be used here BUT what is faster between two alternatives ?
+ System.arraycopy(
+ astStack,
+ astPtr + 2,
+ statements = new Statement[length - 1],
+ 0,
+ length - 1);
+ constructorCall = (ExplicitConstructorCall) astStack[astPtr + 1];
+ } else { //need to add explicitly the super();
+ System.arraycopy(
+ astStack,
+ astPtr + 1,
+ statements = new Statement[length],
+ 0,
+ length);
+ constructorCall = SuperReference.implicitSuperConstructorCall();
+ }
+ } else {
+ constructorCall = SuperReference.implicitSuperConstructorCall();
+ }
+
+ // now we know that the top of stack is a constructorDeclaration
+ ConstructorDeclaration cd = (ConstructorDeclaration) astStack[astPtr];
+ cd.constructorCall = constructorCall;
+ cd.statements = statements;
+
+ //highlight of the implicit call on the method name
+ if (cd.constructorCall.sourceEnd == 0) {
+ cd.constructorCall.sourceEnd = cd.sourceEnd;
+ cd.constructorCall.sourceStart = cd.sourceStart;
+ }
+
+ //watch for } that could be given as a unicode ! ( u007D is '}' )
+ // store the endPosition (position just before the '}') in case there is
+ // a trailing comment behind the end of the method
+ cd.bodyEnd = endPosition;
+ cd.declarationSourceEnd = flushAnnotationsDefinedPriorTo(endStatementPosition);
+ }
+
+ protected void consumeConstructorHeader() {
+ // ConstructorHeader ::= ConstructorHeaderName MethodHeaderParameters MethodHeaderThrowsClauseopt
+
+ AbstractMethodDeclaration method = (AbstractMethodDeclaration) astStack[astPtr];
+
+ if (currentToken == TokenNameLBRACE) {
+ method.bodyStart = scanner.currentPosition;
+ }
+ // recovery
+ if (currentElement != null) {
+ restartRecovery = true;
+ // used to avoid branching back into the regular automaton
+ }
+ }
+
+ protected void consumeConstructorHeaderName() {
+
+ /* recovering - might be an empty message send */
+ if (currentElement != null) {
+ if (lastIgnoredToken == TokenNamenew) { // was an allocation expression
+ lastCheckPoint = scanner.startPosition;
+ // force to restart at this exact position
+ restartRecovery = true;
+ return;
+ }
+ }
+
+ // ConstructorHeaderName ::= Modifiersopt 'Identifier' '('
+ ConstructorDeclaration cd = new ConstructorDeclaration();
+
+ //name -- this is not really revelant but we do .....
+ cd.selector = identifierStack[identifierPtr];
+ long selectorSource = identifierPositionStack[identifierPtr--];
+ identifierLengthPtr--;
+
+ //modifiers
+ cd.declarationSourceStart = intStack[intPtr--];
+ cd.modifiers = intStack[intPtr--];
+
+ //highlight starts at the selector starts
+ cd.sourceStart = (int) (selectorSource >>> 32);
+ pushOnAstStack(cd);
+ cd.sourceEnd = lParenPos;
+ cd.bodyStart = lParenPos + 1;
+ listLength = 0; // initialize listLength before reading parameters/throws
+
+ // recovery
+ if (currentElement != null) {
+ lastCheckPoint = cd.bodyStart;
+ if ((currentElement instanceof RecoveredType
+ && lastIgnoredToken != TokenNameDOT)
+ || cd.modifiers != 0) {
+ currentElement = currentElement.add(cd, 0);
+ lastIgnoredToken = -1;
+ }
+ }
+ }
+
+ protected void consumeDefaultLabel() {
+ // SwitchLabel ::= 'default' ':'
+ pushOnAstStack(new DefaultCase(endPosition));
+ }
+
+ protected void consumeDefaultModifiers() {
+ checkAnnotation(); // might update modifiers with AccDeprecated
+ pushOnIntStack(modifiers); // modifiers
+ pushOnIntStack(
+ modifiersSourceStart >= 0 ? modifiersSourceStart : scanner.startPosition);
+ resetModifiers();
+ }
+
+ protected void consumeDiet() {
+ // Diet ::= $empty
+ jumpOverMethodBody();
+ }
+
+ protected void consumeDims() {
+ // Dims ::= DimsLoop
+ pushOnIntStack(dimensions);
+ dimensions = 0;
+ }
+
+ protected void consumeDimWithOrWithOutExpr() {
+ // DimWithOrWithOutExpr ::= '[' ']'
+ pushOnExpressionStack(null);
+ }
+
+ protected void consumeDimWithOrWithOutExprs() {
+ // DimWithOrWithOutExprs ::= DimWithOrWithOutExprs DimWithOrWithOutExpr
+ concatExpressionLists();
+ }
+
+ protected void consumeEmptyArgumentListopt() {
+ // ArgumentListopt ::= $empty
+ pushOnExpressionStackLengthStack(0);
+ }
+
+ protected void consumeEmptyArrayInitializer() {
+ // ArrayInitializer ::= '{' ,opt '}'
+ arrayInitializer(0);
+ }
+
+ protected void consumeEmptyArrayInitializeropt() {
+ // ArrayInitializeropt ::= $empty
+ pushOnExpressionStackLengthStack(0);
+ }
+
+ protected void consumeEmptyBlockStatementsopt() {
+ // BlockStatementsopt ::= $empty
+ pushOnAstLengthStack(0);
+ }
+
+ protected void consumeEmptyCatchesopt() {
+ // Catchesopt ::= $empty
+ pushOnAstLengthStack(0);
+ }
+
+ protected void consumeEmptyClassBodyDeclarationsopt() {
+ // ClassBodyDeclarationsopt ::= $empty
+ pushOnAstLengthStack(0);
+ }
+
+ protected void consumeEmptyClassMemberDeclaration() {
+ // ClassMemberDeclaration ::= ';'
+ pushOnAstLengthStack(0);
+ }
+
+ protected void consumeEmptyDimsopt() {
+ // Dimsopt ::= $empty
+ pushOnIntStack(0);
+ }
+
+ protected void consumeEmptyExpression() {
+ // Expressionopt ::= $empty
+ pushOnExpressionStackLengthStack(0);
+ }
+
+ protected void consumeEmptyForInitopt() {
+ // ForInitopt ::= $empty
+ pushOnAstLengthStack(0);
+ }
+
+ protected void consumeEmptyForUpdateopt() {
+ // ForUpdateopt ::= $empty
+ pushOnExpressionStackLengthStack(0);
+ }
+
+ protected void consumeEmptyImportDeclarationsopt() {
+ // ImportDeclarationsopt ::= $empty
+ pushOnAstLengthStack(0);
+ }
+
+ protected void consumeEmptyInterfaceMemberDeclaration() {
+ // InterfaceMemberDeclaration ::= ';'
+ pushOnAstLengthStack(0);
+ }
+
+ protected void consumeEmptyInterfaceMemberDeclarationsopt() {
+ // InterfaceMemberDeclarationsopt ::= $empty
+ pushOnAstLengthStack(0);
+ }
+
+ protected void consumeEmptyStatement() {
+ // EmptyStatement ::= ';'
+ pushOnAstLengthStack(0);
+ }
+
+ protected void consumeEmptySwitchBlock() {
+ // SwitchBlock ::= '{' '}'
+ pushOnAstLengthStack(0);
+ }
+
+ protected void consumeEmptyTypeDeclaration() {
+ // TypeDeclaration ::= ';'
+ pushOnAstLengthStack(0);
+ }
+
+ protected void consumeEmptyTypeDeclarationsopt() {
+ // TypeDeclarationsopt ::= $empty
+ pushOnAstLengthStack(0);
+ }
+
+ protected void consumeEnterAnonymousClassBody() {
+ // EnterAnonymousClassBody ::= $empty
+ QualifiedAllocationExpression alloc;
+ AnonymousLocalTypeDeclaration anonymousType =
+ new AnonymousLocalTypeDeclaration();
+ alloc =
+ anonymousType.allocation = new QualifiedAllocationExpression(anonymousType);
+ pushOnAstStack(anonymousType);
+
+ alloc.sourceEnd = rParenPos; //the position has been stored explicitly
+ int argumentLength;
+ if ((argumentLength = expressionLengthStack[expressionLengthPtr--]) != 0) {
+ expressionPtr -= argumentLength;
+ System.arraycopy(
+ expressionStack,
+ expressionPtr + 1,
+ alloc.arguments = new Expression[argumentLength],
+ 0,
+ argumentLength);
+ }
+ alloc.type = getTypeReference(0);
+
+ anonymousType.sourceEnd = alloc.sourceEnd;
+ //position at the type while it impacts the anonymous declaration
+ anonymousType.sourceStart =
+ anonymousType.declarationSourceStart = alloc.type.sourceStart;
+ alloc.sourceStart = intStack[intPtr--];
+ pushOnExpressionStack(alloc);
+
+ anonymousType.bodyStart = scanner.currentPosition;
+ listLength = 0; // will be updated when reading super-interfaces
+ // recovery
+ if (currentElement != null) {
+ lastCheckPoint = anonymousType.bodyStart;
+ // the recoveryTokenCheck will deal with the open brace
+ currentElement = currentElement.add(anonymousType, 0);
+ currentToken = 0; // opening brace already taken into account
+ lastIgnoredToken = -1;
+ }
+ }
+
+ protected void consumeEnterCompilationUnit() {
+ // EnterCompilationUnit ::= $empty
+ // do nothing by default
+ }
+
+ protected void consumeEnterVariable() {
+ // EnterVariable ::= $empty
+ // do nothing by default
+
+ char[] name = identifierStack[identifierPtr];
+ long namePosition = identifierPositionStack[identifierPtr--];
+ int extendedDimension = intStack[intPtr--];
+
+ AbstractVariableDeclaration declaration;
+ // create the ast node
+ boolean isLocalDeclaration = nestedMethod[nestedType] != 0;
+ if (isLocalDeclaration) {
+ // create the local variable declarations
+ declaration =
+ new LocalDeclaration(
+ null,
+ name,
+ (int) (namePosition >>> 32),
+ (int) namePosition);
+ } else {
+ // create the field declaration
+ declaration =
+ this.createFieldDeclaration(
+ null,
+ name,
+ (int) (namePosition >>> 32),
+ (int) namePosition);
+ }
+ identifierLengthPtr--;
+ TypeReference type;
+ int variableIndex = variablesCounter[nestedType];
+ int typeDim = 0;
+ if (variableIndex == 0) {
+ // first variable of the declaration (FieldDeclaration or LocalDeclaration)
+ if (isLocalDeclaration) {
+ declaration.declarationSourceStart = intStack[intPtr--];
+ declaration.modifiers = intStack[intPtr--];
+ type = getTypeReference(typeDim = intStack[intPtr--]); // type dimension
+ if (declaration.declarationSourceStart == -1) {
+ // this is true if there is no modifiers for the local variable declaration
+ declaration.declarationSourceStart = type.sourceStart;
+ }
+ pushOnAstStack(type);
+ } else {
+ type = getTypeReference(typeDim = intStack[intPtr--]); // type dimension
+ pushOnAstStack(type);
+ declaration.declarationSourceStart = intStack[intPtr--];
+ declaration.modifiers = intStack[intPtr--];
+ }
+ } else {
+ type = (TypeReference) astStack[astPtr - variableIndex];
+ typeDim = type.dimensions();
+ AbstractVariableDeclaration previousVariable =
+ (AbstractVariableDeclaration) astStack[astPtr];
+ declaration.declarationSourceStart = previousVariable.declarationSourceStart;
+ declaration.modifiers = previousVariable.modifiers;
+ }
+
+ if (extendedDimension == 0) {
+ declaration.type = type;
+ } else {
+ int dimension = typeDim + extendedDimension;
+ //on the identifierLengthStack there is the information about the type....
+ int baseType;
+ if ((baseType = identifierLengthStack[identifierLengthPtr + 1]) < 0) {
+ //it was a baseType
+ int typeSourceStart = type.sourceStart();
+ type = TypeReference.baseTypeReference(-baseType, dimension);
+ type.sourceStart = typeSourceStart;
+ declaration.type = type;
+ } else {
+ declaration.type = type.copyDims(dimension);
+ }
+ }
+ variablesCounter[nestedType]++;
+ pushOnAstStack(declaration);
+ // recovery
+ if (currentElement != null) {
+ if (!(currentElement instanceof RecoveredType)
+ && (currentToken == TokenNameDOT //|| declaration.modifiers != 0
+ || (scanner.searchLineNumber(declaration.type.sourceStart)
+ != scanner.searchLineNumber((int) (namePosition >>> 32))))) {
+ lastCheckPoint = (int) (namePosition >>> 32);
+ restartRecovery = true;
+ return;
+ }
+ if (isLocalDeclaration) {
+ LocalDeclaration localDecl = (LocalDeclaration) astStack[astPtr];
+ lastCheckPoint = localDecl.sourceEnd + 1;
+ currentElement = currentElement.add(localDecl, 0);
+ } else {
+ FieldDeclaration fieldDecl = (FieldDeclaration) astStack[astPtr];
+ lastCheckPoint = fieldDecl.sourceEnd + 1;
+ currentElement = currentElement.add(fieldDecl, 0);
+ }
+ lastIgnoredToken = -1;
+ }
+ }
+
+ protected void consumeEqualityExpression(int op) {
+ // EqualityExpression ::= EqualityExpression '==' RelationalExpression
+ // EqualityExpression ::= EqualityExpression '!=' RelationalExpression
+
+ //optimize the push/pop
+
+ expressionPtr--;
+ expressionLengthPtr--;
+ expressionStack[expressionPtr] =
+ new EqualExpression(
+ expressionStack[expressionPtr],
+ expressionStack[expressionPtr + 1],
+ op);
+ }
+
+ protected void consumeExitVariableWithInitialization() {
+ // ExitVariableWithInitialization ::= $empty
+ // do nothing by default
+ expressionLengthPtr--;
+ AbstractVariableDeclaration variableDecl =
+ (AbstractVariableDeclaration) astStack[astPtr];
+ variableDecl.initialization = expressionStack[expressionPtr--];
+ // we need to update the declarationSourceEnd of the local variable declaration to the
+ // source end position of the initialization expression
+ variableDecl.declarationSourceEnd = variableDecl.initialization.sourceEnd;
+ }
+
+ protected void consumeExitVariableWithoutInitialization() {
+ // ExitVariableWithoutInitialization ::= $empty
+ // do nothing by default
+ }
+
+ protected void consumeExplicitConstructorInvocation(int flag, int recFlag) {
+
+ /* flag allows to distinguish 3 cases :
+ (0) :
+ ExplicitConstructorInvocation ::= 'this' '(' ArgumentListopt ')' ';'
+ ExplicitConstructorInvocation ::= 'super' '(' ArgumentListopt ')' ';'
+ (1) :
+ ExplicitConstructorInvocation ::= Primary '.' 'super' '(' ArgumentListopt ')' ';'
+ ExplicitConstructorInvocation ::= Primary '.' 'this' '(' ArgumentListopt ')' ';'
+ (2) :
+ ExplicitConstructorInvocation ::= Name '.' 'super' '(' ArgumentListopt ')' ';'
+ ExplicitConstructorInvocation ::= Name '.' 'this' '(' ArgumentListopt ')' ';'
+ */
+ int startPosition = intStack[intPtr--];
+ ExplicitConstructorCall ecc = new ExplicitConstructorCall(recFlag);
+ int length;
+ if ((length = expressionLengthStack[expressionLengthPtr--]) != 0) {
+ expressionPtr -= length;
+ System.arraycopy(
+ expressionStack,
+ expressionPtr + 1,
+ ecc.arguments = new Expression[length],
+ 0,
+ length);
+ }
+ switch (flag) {
+ case 0 :
+ ecc.sourceStart = startPosition;
+ break;
+ case 1 :
+ expressionLengthPtr--;
+ ecc.sourceStart =
+ (ecc.qualification = expressionStack[expressionPtr--]).sourceStart;
+ break;
+ case 2 :
+ ecc.sourceStart =
+ (ecc.qualification = getUnspecifiedReferenceOptimized()).sourceStart;
+ break;
+ };
+ pushOnAstStack(ecc);
+ ecc.sourceEnd = endPosition;
+ }
+
+ protected void consumeExpressionStatement() {
+ // ExpressionStatement ::= StatementExpression ';'
+ expressionLengthPtr--;
+ pushOnAstStack(expressionStack[expressionPtr--]);
+ }
+
+ protected void consumeFieldAccess(boolean isSuperAccess) {
+ // FieldAccess ::= Primary '.' 'Identifier'
+ // FieldAccess ::= 'super' '.' 'Identifier'
+
+ FieldReference fr =
+ new FieldReference(
+ identifierStack[identifierPtr],
+ identifierPositionStack[identifierPtr--]);
+ identifierLengthPtr--;
+ if (isSuperAccess) {
+ //considerates the fieldReference beginning at the 'super' ....
+ fr.sourceStart = intStack[intPtr--];
+ fr.receiver = new SuperReference(fr.sourceStart, endPosition);
+ pushOnExpressionStack(fr);
+ } else {
+ //optimize push/pop
+ if ((fr.receiver = expressionStack[expressionPtr]).isThis()) {
+ //fieldreference begins at the this
+ fr.sourceStart = fr.receiver.sourceStart;
+ }
+ expressionStack[expressionPtr] = fr;
+ }
+ }
+
+ protected void consumeFieldDeclaration() {
+ // See consumeLocalVariableDeclarationDefaultModifier() in case of change: duplicated code
+ // FieldDeclaration ::= Modifiersopt Type VariableDeclarators ';'
+
+ /*
+ astStack :
+ expressionStack: Expression Expression ...... Expression
+ identifierStack : type identifier identifier ...... identifier
+ intStack : typeDim dim dim dim
+ ==>
+ astStack : FieldDeclaration FieldDeclaration ...... FieldDeclaration
+ expressionStack :
+ identifierStack :
+ intStack :
+
+ */
+ int variableDeclaratorsCounter = astLengthStack[astLengthPtr];
+
+ for (int i = variableDeclaratorsCounter - 1; i >= 0; i--) {
+ FieldDeclaration fieldDeclaration = (FieldDeclaration) astStack[astPtr - i];
+ fieldDeclaration.declarationSourceEnd = endStatementPosition;
+ // semi-colon included
+ }
+ updateSourceDeclarationParts(variableDeclaratorsCounter);
+ int endPos = flushAnnotationsDefinedPriorTo(endStatementPosition);
+ if (endPos != endStatementPosition) {
+ for (int i = 0; i < variableDeclaratorsCounter; i++) {
+ FieldDeclaration fieldDeclaration = (FieldDeclaration) astStack[astPtr - i];
+ fieldDeclaration.declarationSourceEnd = endPos;
+ }
+ }
+ // update the astStack, astPtr and astLengthStack
+ int startIndex = astPtr - variablesCounter[nestedType] + 1;
+ System.arraycopy(
+ astStack,
+ startIndex,
+ astStack,
+ startIndex - 1,
+ variableDeclaratorsCounter);
+ astPtr--; // remove the type reference
+ astLengthStack[--astLengthPtr] = variableDeclaratorsCounter;
+
+ // recovery
+ if (currentElement != null) {
+ lastCheckPoint = endPos + 1;
+ if (currentElement.parent != null
+ && currentElement instanceof RecoveredField) {
+ currentElement = currentElement.parent;
+ }
+ restartRecovery = true;
+ }
+ variablesCounter[nestedType] = 0;
+ }
+
+ protected void consumeForceNoDiet() {
+ // ForceNoDiet ::= $empty
+ dietInt++;
+ }
+
+ protected void consumeForInit() {
+ // ForInit ::= StatementExpressionList
+ pushOnAstLengthStack(-1);
+ }
+
+ protected void consumeFormalParameter() {
+ // FormalParameter ::= Type VariableDeclaratorId ==> false
+ // FormalParameter ::= Modifiers Type VariableDeclaratorId ==> true
+ /*
+ astStack :
+ identifierStack : type identifier
+ intStack : dim dim
+ ==>
+ astStack : Argument
+ identifierStack :
+ intStack :
+ */
+
+ identifierLengthPtr--;
+ char[] name = identifierStack[identifierPtr];
+ long namePositions = identifierPositionStack[identifierPtr--];
+ TypeReference type = getTypeReference(intStack[intPtr--] + intStack[intPtr--]);
+ intPtr -= 2;
+ Argument arg =
+ new Argument(name, namePositions, type, intStack[intPtr + 1] & ~AccDeprecated);
+ // modifiers
+ pushOnAstStack(arg);
+
+ /* if incomplete method header, listLength counter will not have been reset,
+ indicating that some arguments are available on the stack */
+ listLength++;
+ }
+
+ protected void consumeFormalParameterList() {
+ // FormalParameterList ::= FormalParameterList ',' FormalParameter
+ optimizedConcatNodeLists();
+ listLength++;
+ // record one more parameter got reduced, in case needing to recover incomplete list
+ }
+
+ protected void consumeFormalParameterListopt() {
+ // FormalParameterListopt ::= $empty
+ pushOnAstLengthStack(0);
+ }
+
+ protected void consumeImportDeclarations() {
+ // ImportDeclarations ::= ImportDeclarations ImportDeclaration
+ optimizedConcatNodeLists();
+ }
+
+ protected void consumeImportDeclarationsopt() {
+ // ImportDeclarationsopt ::= ImportDeclarations
+ int length;
+ if ((length = astLengthStack[astLengthPtr--]) != 0) {
+ astPtr -= length;
+ System.arraycopy(
+ astStack,
+ astPtr + 1,
+ compilationUnit.imports = new ImportReference[length],
+ 0,
+ length);
+ }
+ }
+
+ protected void consumeInstanceOfExpression(int op) {
+ // RelationalExpression ::= RelationalExpression 'instanceof' ReferenceType
+ //optimize the push/pop
+
+ //by construction, no base type may be used in getTypeReference
+ Expression exp;
+ expressionStack[expressionPtr] =
+ exp =
+ new InstanceOfExpression(
+ expressionStack[expressionPtr],
+ getTypeReference(intStack[intPtr--]),
+ op);
+ if (exp.sourceEnd == 0) {
+ //array on base type....
+ exp.sourceEnd = scanner.startPosition - 1;
+ }
+ //the scanner is on the next token already....
+ }
+
+ protected void consumeInterfaceDeclaration() {
+ // see consumeClassDeclaration in case of changes: duplicated code
+ // InterfaceDeclaration ::= InterfaceHeader InterfaceBody
+ int length;
+ if ((length = astLengthStack[astLengthPtr--]) != 0) {
+ //there are length declarations
+ //dispatch.....according to the type of the declarations
+ dispatchDeclarationInto(length);
+ }
+
+ TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr];
+
+ //convert constructor that do not have the type's name into methods
+ typeDecl.checkConstructors(this);
+
+ //always add <clinit> (will be remove at code gen time if empty)
+ typeDecl.addClinit();
+ typeDecl.declarationSourceEnd =
+ flushAnnotationsDefinedPriorTo(endStatementPosition);
+ }
+
+ protected void consumeInterfaceHeader() {
+ // InterfaceHeader ::= InterfaceHeaderName InterfaceHeaderExtendsopt
+
+ TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr];
+ if (currentToken == TokenNameLBRACE) {
+ typeDecl.bodyStart = scanner.currentPosition;
+ }
+ if (currentElement != null) {
+ restartRecovery = true;
+ // used to avoid branching back into the regular automaton
+ }
+ // flush the comments related to the interface header
+ scanner.commentPtr = -1;
+ }
+
+ protected void consumeInterfaceHeaderExtends() {
+ // InterfaceHeaderExtends ::= 'extends' InterfaceTypeList
+ int length = astLengthStack[astLengthPtr--];
+ //super interfaces
+ astPtr -= length;
+ TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr];
+ System.arraycopy(
+ astStack,
+ astPtr + 1,
+ typeDecl.superInterfaces = new TypeReference[length],
+ 0,
+ length);
+ typeDecl.bodyStart = typeDecl.superInterfaces[length - 1].sourceEnd + 1;
+ listLength = 0; // reset after having read super-interfaces
+ // recovery
+ if (currentElement != null) {
+ lastCheckPoint = typeDecl.bodyStart;
+ }
+ }
+
+ protected void consumeInterfaceHeaderName() {
+ // InterfaceHeaderName ::= Modifiersopt 'interface' 'Identifier'
+ TypeDeclaration typeDecl;
+ int length;
+ if (nestedMethod[nestedType] == 0) {
+ if (nestedType != 0) {
+ typeDecl = new MemberTypeDeclaration();
+ } else {
+ typeDecl = new TypeDeclaration();
+ }
+ } else {
+ // Record that the block has a declaration for local types
+ typeDecl = new LocalTypeDeclaration();
+ blockReal();
+ }
+
+ //highlight the name of the type
+ long pos = identifierPositionStack[identifierPtr];
+ typeDecl.sourceEnd = (int) pos;
+ typeDecl.sourceStart = (int) (pos >>> 32);
+ typeDecl.name = identifierStack[identifierPtr--];
+ identifierLengthPtr--;
+
+ //compute the declaration source too
+ typeDecl.declarationSourceStart = intStack[intPtr--];
+ // 'class' and 'interface' push an int position
+ typeDecl.modifiersSourceStart = intStack[intPtr--];
+ typeDecl.modifiers = intStack[intPtr--];
+ if (typeDecl.modifiersSourceStart >= 0) {
+ typeDecl.declarationSourceStart = typeDecl.modifiersSourceStart;
+ }
+ typeDecl.bodyStart = typeDecl.sourceEnd + 1;
+ pushOnAstStack(typeDecl);
+ listLength = 0; // will be updated when reading super-interfaces
+ // recovery
+ if (currentElement != null) { // is recovering
+ lastCheckPoint = typeDecl.bodyStart;
+ currentElement = currentElement.add(typeDecl, 0);
+ lastIgnoredToken = -1;
+ }
+ }
+
+ protected void consumeInterfaceMemberDeclarations() {
+ // InterfaceMemberDeclarations ::= InterfaceMemberDeclarations InterfaceMemberDeclaration
+ concatNodeLists();
+ }
+
+ protected void consumeInterfaceMemberDeclarationsopt() {
+ // InterfaceMemberDeclarationsopt ::= NestedType InterfaceMemberDeclarations
+ nestedType--;
+ }
+
+ protected void consumeInterfaceType() {
+ // InterfaceType ::= ClassOrInterfaceType
+ pushOnAstStack(getTypeReference(0));
+ /* if incomplete type header, listLength counter will not have been reset,
+ indicating that some interfaces are available on the stack */
+ listLength++;
+ }
+
+ protected void consumeInterfaceTypeList() {
+ // InterfaceTypeList ::= InterfaceTypeList ',' InterfaceType
+ optimizedConcatNodeLists();
+ }
+
+ protected void consumeLeftHandSide() {
+ // LeftHandSide ::= Name
+
+ pushOnExpressionStack(getUnspecifiedReferenceOptimized());
+ }
+
+ protected void consumeLeftParen() {
+ // PushLPAREN ::= '('
+ pushOnIntStack(lParenPos);
+ }
+
+ protected void consumeLocalVariableDeclaration() {
+ // LocalVariableDeclaration ::= Modifiers Type VariableDeclarators ';'
+
+ /*
+ astStack :
+ expressionStack: Expression Expression ...... Expression
+ identifierStack : type identifier identifier ...... identifier
+ intStack : typeDim dim dim dim
+ ==>
+ astStack : FieldDeclaration FieldDeclaration ...... FieldDeclaration
+ expressionStack :
+ identifierStack :
+ intStack :
+
+ */
+ int variableDeclaratorsCounter = astLengthStack[astLengthPtr];
+ // retrieve modifiers
+ // The modifiers has been set and it is still at the right value
+ // declaration starts from the modifierSourceStart
+ for (int i = variableDeclaratorsCounter - 1; i >= 0; i--) {
+ LocalDeclaration localDeclaration = (LocalDeclaration) astStack[astPtr - i];
+ localDeclaration.declarationSourceEnd = endStatementPosition;
+ // semi-colon included
+ }
+ // update the astStack, astPtr and astLengthStack
+ int startIndex = astPtr - variablesCounter[nestedType] + 1;
+ System.arraycopy(
+ astStack,
+ startIndex,
+ astStack,
+ startIndex - 1,
+ variableDeclaratorsCounter);
+ astPtr--; // remove the type reference
+ astLengthStack[--astLengthPtr] = variableDeclaratorsCounter;
+ variablesCounter[nestedType] = 0;
+ }
+
+ protected void consumeLocalVariableDeclarationStatement() {
+ // LocalVariableDeclarationStatement ::= LocalVariableDeclaration ';'
+ // see blockReal in case of change: duplicated code
+ // increment the amount of declared variables for this block
+ realBlockStack[realBlockPtr]++;
+ }
+
+ protected void consumeMethodBody() {
+ // MethodBody ::= NestedMethod '{' BlockStatementsopt '}'
+ nestedMethod[nestedType]--;
+ }
+
+ protected void consumeMethodDeclaration(boolean isNotAbstract) {
+ // MethodDeclaration ::= MethodHeader MethodBody
+ // AbstractMethodDeclaration ::= MethodHeader ';'
+
+ /*
+ astStack : modifiers arguments throws statements
+ identifierStack : type name
+ intStack : dim dim dim
+ ==>
+ astStack : MethodDeclaration
+ identifierStack :
+ intStack :
+ */
+
+ int length;
+ if (isNotAbstract) {
+ // pop the position of the { (body of the method) pushed in block decl
+ intPtr--;
+ }
+
+ int explicitDeclarations = 0;
+ Statement[] statements = null;
+ if (isNotAbstract) {
+ //statements
+ explicitDeclarations = realBlockStack[realBlockPtr--];
+ if ((length = astLengthStack[astLengthPtr--]) != 0)
+ System.arraycopy(
+ astStack,
+ (astPtr -= length) + 1,
+ statements = new Statement[length],
+ 0,
+ length);
+ }
+
+ // now we know that we have a method declaration at the top of the ast stack
+ MethodDeclaration md = (MethodDeclaration) astStack[astPtr];
+ md.statements = statements;
+ md.explicitDeclarations = explicitDeclarations;
+
+ // cannot be done in consumeMethodHeader because we have no idea whether or not there
+ // is a body when we reduce the method header
+ if (!isNotAbstract) { //remember the fact that the method has a semicolon body
+ md.modifiers |= AccSemicolonBody;
+ }
+ // store the endPosition (position just before the '}') in case there is
+ // a trailing comment behind the end of the method
+ md.bodyEnd = endPosition;
+ md.declarationSourceEnd = flushAnnotationsDefinedPriorTo(endStatementPosition);
+ }
+
+ protected void consumeMethodHeader() {
+ // MethodHeader ::= MethodHeaderName MethodHeaderParameters MethodHeaderExtendedDims ThrowsClauseopt
+ // retrieve end position of method declarator
+ AbstractMethodDeclaration method = (AbstractMethodDeclaration) astStack[astPtr];
+
+ if (currentToken == TokenNameLBRACE) {
+ method.bodyStart = scanner.currentPosition;
+ }
+ // recovery
+ if (currentElement != null) {
+ if (currentToken == TokenNameSEMICOLON) {
+ method.declarationSourceEnd = scanner.currentPosition - 1;
+ if (currentElement.parent != null) {
+ currentElement = currentElement.parent;
+ }
+ }
+ restartRecovery = true;
+ // used to avoid branching back into the regular automaton
+ }
+ }
+
+ protected void consumeMethodHeaderExtendedDims() {
+ // MethodHeaderExtendedDims ::= Dimsopt
+ // now we update the returnType of the method
+ MethodDeclaration md = (MethodDeclaration) astStack[astPtr];
+ int extendedDims = intStack[intPtr--];
+ if (extendedDims != 0) {
+ TypeReference returnType = md.returnType;
+ md.sourceEnd = endPosition;
+ int dims = returnType.dimensions() + extendedDims;
+ int baseType;
+ if ((baseType = identifierLengthStack[identifierLengthPtr + 1]) < 0) {
+ //it was a baseType
+ int sourceStart = returnType.sourceStart();
+ int sourceEnd = returnType.sourceEnd();
+ returnType = TypeReference.baseTypeReference(-baseType, dims);
+ returnType.sourceStart = sourceStart;
+ returnType.sourceEnd = sourceEnd;
+ md.returnType = returnType;
+ } else {
+ md.returnType = md.returnType.copyDims(dims);
+ }
+ if (currentToken == TokenNameLBRACE) {
+ md.bodyStart = endPosition + 1;
+ }
+ // recovery
+ if (currentElement != null) {
+ lastCheckPoint = md.bodyStart;
+ }
+ }
+ }
+
+ protected void consumeMethodHeaderName() {
+ // MethodHeaderName ::= Modifiersopt Type 'Identifier' '('
+ int length;
+ MethodDeclaration md = new MethodDeclaration();
+
+ //name
+ md.selector = identifierStack[identifierPtr];
+ long selectorSource = identifierPositionStack[identifierPtr--];
+ identifierLengthPtr--;
+ //type
+ md.returnType = getTypeReference(intStack[intPtr--]);
+ //modifiers
+ md.declarationSourceStart = intStack[intPtr--];
+ md.modifiers = intStack[intPtr--];
+
+ //highlight starts at selector start
+ md.sourceStart = (int) (selectorSource >>> 32);
+ pushOnAstStack(md);
+ md.sourceEnd = lParenPos;
+ md.bodyStart = lParenPos + 1;
+ listLength = 0; // initialize listLength before reading parameters/throws
+
+ // recovery
+ if (currentElement != null) {
+ if (currentElement instanceof RecoveredType //|| md.modifiers != 0
+ || (scanner.searchLineNumber(md.returnType.sourceStart)
+ == scanner.searchLineNumber(md.sourceStart))) {
+ lastCheckPoint = md.bodyStart;
+ currentElement = currentElement.add(md, 0);
+ lastIgnoredToken = -1;
+ } else {
+ lastCheckPoint = md.sourceStart;
+ restartRecovery = true;
+ }
+ }
+ }
+
+ protected void consumeMethodHeaderParameters() {
+ // MethodHeaderParameters ::= FormalParameterListopt ')'
+ int length = astLengthStack[astLengthPtr--];
+ astPtr -= length;
+ AbstractMethodDeclaration md = (AbstractMethodDeclaration) astStack[astPtr];
+ md.sourceEnd = rParenPos;
+ //arguments
+ if (length != 0) {
+ System.arraycopy(
+ astStack,
+ astPtr + 1,
+ md.arguments = new Argument[length],
+ 0,
+ length);
+ }
+ md.bodyStart = rParenPos + 1;
+ listLength = 0; // reset listLength after having read all parameters
+ // recovery
+ if (currentElement != null) {
+ lastCheckPoint = md.bodyStart;
+ if (currentElement.parseTree() == md)
+ return;
+
+ // might not have been attached yet - in some constructor scenarii
+ if (md.isConstructor()) {
+ if ((length != 0)
+ || (currentToken == TokenNameLBRACE)
+ || (currentToken == TokenNamethrows)) {
+ currentElement = currentElement.add(md, 0);
+ lastIgnoredToken = -1;
+ }
+ }
+ }
+ }
+
+ protected void consumeMethodHeaderThrowsClause() {
+ // MethodHeaderThrowsClause ::= 'throws' ClassTypeList
+ int length = astLengthStack[astLengthPtr--];
+ astPtr -= length;
+ AbstractMethodDeclaration md = (AbstractMethodDeclaration) astStack[astPtr];
+ System.arraycopy(
+ astStack,
+ astPtr + 1,
+ md.thrownExceptions = new TypeReference[length],
+ 0,
+ length);
+ md.sourceEnd = md.thrownExceptions[length - 1].sourceEnd;
+ md.bodyStart = md.thrownExceptions[length - 1].sourceEnd + 1;
+ listLength = 0; // reset listLength after having read all thrown exceptions
+ // recovery
+ if (currentElement != null) {
+ lastCheckPoint = md.bodyStart;
+ }
+ }
+
+ protected void consumeMethodInvocationName() {
+ // MethodInvocation ::= Name '(' ArgumentListopt ')'
+
+ // when the name is only an identifier...we have a message send to "this" (implicit)
+
+ MessageSend m = newMessageSend();
+ m.sourceEnd = rParenPos;
+ m.sourceStart =
+ (int) ((m.nameSourcePosition = identifierPositionStack[identifierPtr]) >>> 32);
+ m.selector = identifierStack[identifierPtr--];
+ if (identifierLengthStack[identifierLengthPtr] == 1) {
+ m.receiver = ThisReference.ThisImplicit;
+ identifierLengthPtr--;
+ } else {
+ identifierLengthStack[identifierLengthPtr]--;
+ m.receiver = getUnspecifiedReference();
+ m.sourceStart = m.receiver.sourceStart;
+ }
+ pushOnExpressionStack(m);
+ }
+
+ protected void consumeMethodInvocationPrimary() {
+ //optimize the push/pop
+ //MethodInvocation ::= Primary '.' 'Identifier' '(' ArgumentListopt ')'
+
+ MessageSend m = newMessageSend();
+ m.sourceStart =
+ (int) ((m.nameSourcePosition = identifierPositionStack[identifierPtr]) >>> 32);
+ m.selector = identifierStack[identifierPtr--];
+ identifierLengthPtr--;
+ if ((m.receiver = expressionStack[expressionPtr]).isThis()) {
+ m.sourceStart = m.receiver.sourceStart;
+ }
+ m.sourceEnd = rParenPos;
+ expressionStack[expressionPtr] = m;
+ }
+
+ protected void consumeMethodInvocationSuper() {
+ // MethodInvocation ::= 'super' '.' 'Identifier' '(' ArgumentListopt ')'
+
+ MessageSend m = newMessageSend();
+ m.sourceStart = intStack[intPtr--];
+ m.sourceEnd = rParenPos;
+ m.nameSourcePosition = identifierPositionStack[identifierPtr];
+ m.selector = identifierStack[identifierPtr--];
+ identifierLengthPtr--;
+ m.receiver = new SuperReference(m.sourceStart, endPosition);
+ pushOnExpressionStack(m);
+ }
+
+ protected void consumeMethodPushModifiersHeaderName() {
+ // MethodPushModifiersHeaderName ::= Modifiers Type PushModifiers 'Identifier' '('
+ // MethodPushModifiersHeaderName ::= Type PushModifiers 'Identifier' '('
+ int length;
+ MethodDeclaration md = new MethodDeclaration();
+
+ //name
+ md.selector = identifierStack[identifierPtr];
+ long selectorSource = identifierPositionStack[identifierPtr--];
+ identifierLengthPtr--;
+
+ //modifiers
+ md.declarationSourceStart = intStack[intPtr--];
+ md.modifiers = intStack[intPtr--];
+
+ //type
+ md.returnType = getTypeReference(intStack[intPtr--]);
+
+ //highlight starts at selector start
+ md.sourceStart = (int) (selectorSource >>> 32);
+ pushOnAstStack(md);
+ md.sourceEnd = lParenPos;
+ md.bodyStart = lParenPos + 1;
+ listLength = 0; // initialize listLength before reading parameters/throws
+
+ // recovery
+ if (currentElement != null) {
+ lastCheckPoint = md.bodyStart;
+ currentElement = currentElement.add(md, 0);
+ lastIgnoredToken = -1;
+ }
+ }
+
+ protected void consumeModifiers() {
+ checkAnnotation(); // might update modifiers with AccDeprecated
+ pushOnIntStack(modifiers); // modifiers
+ pushOnIntStack(modifiersSourceStart);
+ resetModifiers();
+ }
+
+ protected void consumeNestedMethod() {
+ // NestedMethod ::= $empty
+ jumpOverMethodBody();
+ nestedMethod[nestedType]++;
+ consumeOpenBlock();
+ }
+
+ protected void consumeNestedType() {
+ // NestedType ::= $empty
+ nestedType++;
+ try {
+ nestedMethod[nestedType] = 0;
+ } catch (IndexOutOfBoundsException e) {
+ //except in test's cases, it should never raise
+ int oldL = nestedMethod.length;
+ System.arraycopy(nestedMethod, 0, (nestedMethod = new int[oldL + 30]), 0, oldL);
+ nestedMethod[nestedType] = 0;
+ // increase the size of the fieldsCounter as well. It has to be consistent with the size of the nestedMethod collection
+ System.arraycopy(
+ variablesCounter,
+ 0,
+ (variablesCounter = new int[oldL + 30]),
+ 0,
+ oldL);
+ }
+ variablesCounter[nestedType] = 0;
+ }
+
+ protected void consumeOneDimLoop() {
+ // OneDimLoop ::= '[' ']'
+ dimensions++;
+ }
+
+ protected void consumeOnlySynchronized() {
+ // OnlySynchronized ::= 'synchronized'
+ resetModifiers();
+ }
+
+ protected void consumeOpenBlock() {
+ // OpenBlock ::= $empty
+
+ pushOnIntStack(scanner.startPosition);
+ try {
+ realBlockStack[++realBlockPtr] = 0;
+ } catch (IndexOutOfBoundsException e) {
+ //realBlockPtr is correct
+ int oldStackLength = realBlockStack.length;
+ int oldStack[] = realBlockStack;
+ realBlockStack = new int[oldStackLength + StackIncrement];
+ System.arraycopy(oldStack, 0, realBlockStack, 0, oldStackLength);
+ realBlockStack[realBlockPtr] = 0;
+ }
+ }
+
+ protected void consumePackageDeclaration() {
+ // PackageDeclaration ::= 'package' Name ';'
+ /* build an ImportRef build from the last name
+ stored in the identifier stack. */
+
+ ImportReference impt = compilationUnit.currentPackage;
+ // flush annotations defined prior to import statements
+ impt.declarationSourceEnd =
+ this.flushAnnotationsDefinedPriorTo(impt.declarationSourceEnd);
+ }
+
+ protected void consumePackageDeclarationName() {
+ // PackageDeclarationName ::= 'package' Name
+ /* build an ImportRef build from the last name
+ stored in the identifier stack. */
+
+ ImportReference impt;
+ int length;
+ char[][] tokens =
+ new char[length = identifierLengthStack[identifierLengthPtr--]][];
+ identifierPtr -= length;
+ long[] positions = new long[length];
+ System.arraycopy(identifierStack, ++identifierPtr, tokens, 0, length);
+ System.arraycopy(
+ identifierPositionStack,
+ identifierPtr--,
+ positions,
+ 0,
+ length);
+ compilationUnit.currentPackage =
+ impt = new ImportReference(tokens, positions, true);
+
+ if (currentToken == TokenNameSEMICOLON) {
+ impt.declarationSourceEnd = scanner.currentPosition - 1;
+ } else {
+ impt.declarationSourceEnd = impt.sourceEnd;
+ }
+ //endPosition is just before the ;
+ impt.declarationSourceStart = intStack[intPtr--];
+
+ // recovery
+ if (currentElement != null) {
+ lastCheckPoint = impt.declarationSourceEnd + 1;
+ restartRecovery = true;
+ // used to avoid branching back into the regular automaton
+ }
+ }
+
+ protected void consumePostfixExpression() {
+ // PostfixExpression ::= Name
+ pushOnExpressionStack(getUnspecifiedReferenceOptimized());
+ }
+
+ protected void consumePrimaryNoNewArray() {
+ // PrimaryNoNewArray ::= PushLPAREN Expression PushRPAREN
+ updateSourcePosition(expressionStack[expressionPtr]);
+ }
+
+ protected void consumePrimaryNoNewArrayArrayType() {
+ // PrimaryNoNewArray ::= ArrayType '.' 'class'
+ pushOnExpressionStack(
+ new ClassLiteralAccess(
+ intStack[intPtr--],
+ getTypeReference(intStack[intPtr--])));
+ }
+
+ protected void consumePrimaryNoNewArrayName() {
+ // PrimaryNoNewArray ::= Name '.' 'class'
+ pushOnExpressionStack(
+ new ClassLiteralAccess(intStack[intPtr--], getTypeReference(0)));
+ }
+
+ protected void consumePrimaryNoNewArrayNameSuper() {
+ // PrimaryNoNewArray ::= Name '.' 'super'
+ pushOnExpressionStack(
+ new QualifiedSuperReference(
+ getTypeReference(0),
+ intStack[intPtr--],
+ endPosition));
+ }
+
+ protected void consumePrimaryNoNewArrayNameThis() {
+ // PrimaryNoNewArray ::= Name '.' 'this'
+ pushOnExpressionStack(
+ new QualifiedThisReference(
+ getTypeReference(0),
+ intStack[intPtr--],
+ endPosition));
+ }
+
+ protected void consumePrimaryNoNewArrayPrimitiveType() {
+ // PrimaryNoNewArray ::= PrimitiveType '.' 'class'
+ pushOnExpressionStack(
+ new ClassLiteralAccess(intStack[intPtr--], getTypeReference(0)));
+ }
+
+ protected void consumePrimaryNoNewArrayThis() {
+ // PrimaryNoNewArray ::= 'this'
+ pushOnExpressionStack(new ThisReference(intStack[intPtr--], endPosition));
+ }
+
+ protected void consumePrimitiveType() {
+ // Type ::= PrimitiveType
+ pushOnIntStack(0);
+ }
+
+ protected void consumePushModifiers() {
+ checkAnnotation(); // might update modifiers with AccDeprecated
+ pushOnIntStack(modifiers); // modifiers
+ pushOnIntStack(modifiersSourceStart);
+ resetModifiers();
+ }
+
+ protected void consumePushPosition() {
+ // for source managment purpose
+ // PushPosition ::= $empty
+ pushOnIntStack(endPosition);
+ }
+
+ protected void consumeQualifiedName() {
+ // QualifiedName ::= Name '.' SimpleName
+ /*back from the recursive loop of QualifiedName.
+ Updates identifier length into the length stack*/
+
+ identifierLengthStack[--identifierLengthPtr]++;
+ }
+
+ protected void consumeReferenceType() {
+ // ReferenceType ::= ClassOrInterfaceType
+ pushOnIntStack(0);
+ }
+
+ protected void consumeRestoreDiet() {
+ // RestoreDiet ::= $empty
+ dietInt--;
+ }
+
+ protected void consumeRightParen() {
+ // PushRPAREN ::= ')'
+ pushOnIntStack(rParenPos);
+ }
+
+ // This method is part of an automatic generation : do NOT edit-modify
+ protected void consumeRule(int act) {
+ switch (act) {
+ case 29 : // System.out.println("Type ::= PrimitiveType");
+ consumePrimitiveType();
+ break;
+ case 43 : // System.out.println("ReferenceType ::= ClassOrInterfaceType");
+ consumeReferenceType();
+ break;
+ case 52 : // System.out.println("QualifiedName ::= Name DOT SimpleName");
+ consumeQualifiedName();
+ break;
+ case 53 : // System.out.println("CompilationUnit ::= EnterCompilationUnit PackageDeclarationopt ImportDeclarationsopt");
+ consumeCompilationUnit();
+ break;
+ case 54 : // System.out.println("EnterCompilationUnit ::=");
+ consumeEnterCompilationUnit();
+ break;
+ case 66 : // System.out.println("CatchHeader ::= catch LPAREN FormalParameter RPAREN LBRACE");
+ consumeCatchHeader();
+ break;
+ case 68 : // System.out.println("ImportDeclarations ::= ImportDeclarations ImportDeclaration");
+ consumeImportDeclarations();
+ break;
+ case 70 : // System.out.println("TypeDeclarations ::= TypeDeclarations TypeDeclaration");
+ consumeTypeDeclarations();
+ break;
+ case 71 : // System.out.println("PackageDeclaration ::= PackageDeclarationName SEMICOLON");
+ consumePackageDeclaration();
+ break;
+ case 72 : // System.out.println("PackageDeclarationName ::= package Name");
+ consumePackageDeclarationName();
+ break;
+ case 75 : // System.out.println("SingleTypeImportDeclaration ::= SingleTypeImportDeclarationName SEMICOLON");
+ consumeSingleTypeImportDeclaration();
+ break;
+ case 76 : // System.out.println("SingleTypeImportDeclarationName ::= import Name");
+ consumeSingleTypeImportDeclarationName();
+ break;
+ case 77 : // System.out.println("TypeImportOnDemandDeclaration ::= TypeImportOnDemandDeclarationName SEMICOLON");
+ consumeTypeImportOnDemandDeclaration();
+ break;
+ case 78 : // System.out.println("TypeImportOnDemandDeclarationName ::= import Name DOT MULTIPLY");
+ consumeTypeImportOnDemandDeclarationName();
+ break;
+ case 81 : // System.out.println("TypeDeclaration ::= SEMICOLON");
+ consumeEmptyTypeDeclaration();
+ break;
+ case 95 : // System.out.println("ClassDeclaration ::= ClassHeader ClassBody");
+ consumeClassDeclaration();
+ break;
+ case 96 : // System.out.println("ClassHeader ::= ClassHeaderName ClassHeaderExtendsopt ClassHeaderImplementsopt");
+ consumeClassHeader();
+ break;
+ case 97 : // System.out.println("ClassHeaderName ::= Modifiersopt class Identifier");
+ consumeClassHeaderName();
+ break;
+ case 98 : // System.out.println("ClassHeaderExtends ::= extends ClassType");
+ consumeClassHeaderExtends();
+ break;
+ case 99 : // System.out.println("ClassHeaderImplements ::= implements InterfaceTypeList");
+ consumeClassHeaderImplements();
+ break;
+ case 101 : // System.out.println("InterfaceTypeList ::= InterfaceTypeList COMMA InterfaceType");
+ consumeInterfaceTypeList();
+ break;
+ case 102 : // System.out.println("InterfaceType ::= ClassOrInterfaceType");
+ consumeInterfaceType();
+ break;
+ case 105 : // System.out.println("ClassBodyDeclarations ::= ClassBodyDeclarations ClassBodyDeclaration");
+ consumeClassBodyDeclarations();
+ break;
+ case 109 : // System.out.println("ClassBodyDeclaration ::= Diet NestedMethod Block");
+ consumeClassBodyDeclaration();
+ break;
+ case 110 : // System.out.println("Diet ::=");
+ consumeDiet();
+ break;
+ case 117 : // System.out.println("ClassMemberDeclaration ::= SEMICOLON");
+ consumeEmptyClassMemberDeclaration();
+ break;
+ case 118 : // System.out.println("FieldDeclaration ::= Modifiersopt Type VariableDeclarators SEMICOLON");
+ consumeFieldDeclaration();
+ break;
+ case 120 : // System.out.println("VariableDeclarators ::= VariableDeclarators COMMA VariableDeclarator");
+ consumeVariableDeclarators();
+ break;
+ case 123 : // System.out.println("EnterVariable ::=");
+ consumeEnterVariable();
+ break;
+ case 124 : // System.out.println("ExitVariableWithInitialization ::=");
+ consumeExitVariableWithInitialization();
+ break;
+ case 125 : // System.out.println("ExitVariableWithoutInitialization ::=");
+ consumeExitVariableWithoutInitialization();
+ break;
+ case 126 : // System.out.println("ForceNoDiet ::=");
+ consumeForceNoDiet();
+ break;
+ case 127 : // System.out.println("RestoreDiet ::=");
+ consumeRestoreDiet();
+ break;
+ case 132 : // System.out.println("MethodDeclaration ::= MethodHeader MethodBody");
+ // set to true to consume a method with a body
+ consumeMethodDeclaration(true);
+ break;
+ case 133 : // System.out.println("AbstractMethodDeclaration ::= MethodHeader SEMICOLON");
+ // set to false to consume a method without body
+ consumeMethodDeclaration(false);
+ break;
+ case 134 : // System.out.println("MethodHeader ::= MethodHeaderName MethodHeaderParameters MethodHeaderExtendedDims");
+ consumeMethodHeader();
+ break;
+ case 135 : // System.out.println("MethodPushModifiersHeader ::= MethodPushModifiersHeaderName MethodHeaderParameters");
+ consumeMethodHeader();
+ break;
+ case 136 : // System.out.println("MethodPushModifiersHeaderName ::= Modifiers Type PushModifiers Identifier LPAREN");
+ consumeMethodPushModifiersHeaderName();
+ break;
+ case 137 : // System.out.println("MethodPushModifiersHeaderName ::= Type PushModifiers Identifier LPAREN");
+ consumeMethodPushModifiersHeaderName();
+ break;
+ case 138 : // System.out.println("MethodHeaderName ::= Modifiersopt Type Identifier LPAREN");
+ consumeMethodHeaderName();
+ break;
+ case 139 : // System.out.println("MethodHeaderParameters ::= FormalParameterListopt RPAREN");
+ consumeMethodHeaderParameters();
+ break;
+ case 140 : // System.out.println("MethodHeaderExtendedDims ::= Dimsopt");
+ consumeMethodHeaderExtendedDims();
+ break;
+ case 141 : // System.out.println("MethodHeaderThrowsClause ::= throws ClassTypeList");
+ consumeMethodHeaderThrowsClause();
+ break;
+ case 142 : // System.out.println("ConstructorHeader ::= ConstructorHeaderName MethodHeaderParameters...");
+ consumeConstructorHeader();
+ break;
+ case 143 : // System.out.println("ConstructorHeaderName ::= Modifiersopt Identifier LPAREN");
+ consumeConstructorHeaderName();
+ break;
+ case 145 : // System.out.println("FormalParameterList ::= FormalParameterList COMMA FormalParameter");
+ consumeFormalParameterList();
+ break;
+ case 146 : // System.out.println("FormalParameter ::= Modifiersopt Type VariableDeclaratorId");
+ // the boolean is used to know if the modifiers should be reset
+ consumeFormalParameter();
+ break;
+ case 148 : // System.out.println("ClassTypeList ::= ClassTypeList COMMA ClassTypeElt");
+ consumeClassTypeList();
+ break;
+ case 149 : // System.out.println("ClassTypeElt ::= ClassType");
+ consumeClassTypeElt();
+ break;
+ case 150 : // System.out.println("MethodBody ::= NestedMethod LBRACE BlockStatementsopt RBRACE");
+ consumeMethodBody();
+ break;
+ case 151 : // System.out.println("NestedMethod ::=");
+ consumeNestedMethod();
+ break;
+ case 152 : // System.out.println("StaticInitializer ::= StaticOnly Block");
+ consumeStaticInitializer();
+ break;
+ case 153 : // System.out.println("StaticOnly ::= static");
+ consumeStaticOnly();
+ break;
+ case 154 : // System.out.println("ConstructorDeclaration ::= ConstructorHeader ConstructorBody");
+ consumeConstructorDeclaration();
+ break;
+ case 155 : // System.out.println("ConstructorBody ::= NestedMethod LBRACE ConstructorBlockStatementsopt RBRACE");
+ consumeConstructorBody();
+ break;
+ case 158 : // System.out.println("ConstructorBlockStatementsopt ::= ExplicitConstructorInvocation BlockStatements");
+ consumeConstructorBlockStatements();
+ break;
+ case 159 : // System.out.println("ExplicitConstructorInvocation ::= this LPAREN ArgumentListopt RPAREN SEMICOLON");
+ consumeExplicitConstructorInvocation(0, ExplicitConstructorCall.This);
+ break;
+ case 160 : // System.out.println("ExplicitConstructorInvocation ::= super LPAREN ArgumentListopt RPAREN SEMICOLON");
+ consumeExplicitConstructorInvocation(0, ExplicitConstructorCall.Super);
+ break;
+ case 161 : // System.out.println("ExplicitConstructorInvocation ::= Primary DOT super LPAREN ArgumentListopt RPAREN");
+ consumeExplicitConstructorInvocation(1, ExplicitConstructorCall.Super);
+ break;
+ case 162 : // System.out.println("ExplicitConstructorInvocation ::= Name DOT super LPAREN ArgumentListopt RPAREN...");
+ consumeExplicitConstructorInvocation(2, ExplicitConstructorCall.Super);
+ break;
+ case 163 : // System.out.println("ExplicitConstructorInvocation ::= Primary DOT this LPAREN ArgumentListopt RPAREN...");
+ consumeExplicitConstructorInvocation(1, ExplicitConstructorCall.This);
+ break;
+ case 164 : // System.out.println("ExplicitConstructorInvocation ::= Name DOT this LPAREN ArgumentListopt RPAREN...");
+ consumeExplicitConstructorInvocation(2, ExplicitConstructorCall.This);
+ break;
+ case 165 : // System.out.println("InterfaceDeclaration ::= InterfaceHeader InterfaceBody");
+ consumeInterfaceDeclaration();
+ break;
+ case 166 : // System.out.println("InterfaceHeader ::= InterfaceHeaderName InterfaceHeaderExtendsopt");
+ consumeInterfaceHeader();
+ break;
+ case 167 : // System.out.println("InterfaceHeaderName ::= Modifiersopt interface Identifier");
+ consumeInterfaceHeaderName();
+ break;
+ case 169 : // System.out.println("InterfaceHeaderExtends ::= extends InterfaceTypeList");
+ consumeInterfaceHeaderExtends();
+ break;
+ case 172 : // System.out.println("InterfaceMemberDeclarations ::= InterfaceMemberDeclarations...");
+ consumeInterfaceMemberDeclarations();
+ break;
+ case 173 : // System.out.println("InterfaceMemberDeclaration ::= SEMICOLON");
+ consumeEmptyInterfaceMemberDeclaration();
+ break;
+ case 176 : // System.out.println("InterfaceMemberDeclaration ::= InvalidMethodDeclaration");
+ ignoreMethodBody();
+ break;
+ case 177 : // System.out.println("InvalidConstructorDeclaration ::= ConstructorHeader ConstructorBody");
+ ignoreInvalidConstructorDeclaration(true);
+ break;
+ case 178 : // System.out.println("InvalidConstructorDeclaration ::= ConstructorHeader SEMICOLON");
+ ignoreInvalidConstructorDeclaration(false);
+ break;
+ case 184 : // System.out.println("ArrayInitializer ::= LBRACE ,opt RBRACE");
+ consumeEmptyArrayInitializer();
+ break;
+ case 185 : // System.out.println("ArrayInitializer ::= LBRACE VariableInitializers RBRACE");
+ consumeArrayInitializer();
+ break;
+ case 186 : // System.out.println("ArrayInitializer ::= LBRACE VariableInitializers COMMA RBRACE");
+ consumeArrayInitializer();
+ break;
+ case 188 : // System.out.println("VariableInitializers ::= VariableInitializers COMMA VariableInitializer");
+ consumeVariableInitializers();
+ break;
+ case 189 : // System.out.println("Block ::= OpenBlock LBRACE BlockStatementsopt RBRACE");
+ consumeBlock();
+ break;
+ case 190 : // System.out.println("OpenBlock ::=");
+ consumeOpenBlock();
+ break;
+ case 192 : // System.out.println("BlockStatements ::= BlockStatements BlockStatement");
+ consumeBlockStatements();
+ break;
+ case 196 : // System.out.println("BlockStatement ::= InvalidInterfaceDeclaration");
+ ignoreInterfaceDeclaration();
+ break;
+ case 197 : // System.out.println("LocalVariableDeclarationStatement ::= LocalVariableDeclaration SEMICOLON");
+ consumeLocalVariableDeclarationStatement();
+ break;
+ case 198 : // System.out.println("LocalVariableDeclaration ::= Type PushModifiers VariableDeclarators");
+ consumeLocalVariableDeclaration();
+ break;
+ case 199 : // System.out.println("LocalVariableDeclaration ::= Modifiers Type PushModifiers VariableDeclarators");
+ consumeLocalVariableDeclaration();
+ break;
+ case 200 : // System.out.println("PushModifiers ::=");
+ consumePushModifiers();
+ break;
+ case 223 : // System.out.println("EmptyStatement ::= SEMICOLON");
+ consumeEmptyStatement();
+ break;
+ case 224 : // System.out.println("LabeledStatement ::= Identifier COLON Statement");
+ consumeStatementLabel();
+ break;
+ case 225 : // System.out.println("LabeledStatementNoShortIf ::= Identifier COLON StatementNoShortIf");
+ consumeStatementLabel();
+ break;
+ case 226 : // System.out.println("ExpressionStatement ::= StatementExpression SEMICOLON");
+ consumeExpressionStatement();
+ break;
+ case 234 : // System.out.println("IfThenStatement ::= if LPAREN Expression RPAREN Statement");
+ consumeStatementIfNoElse();
+ break;
+ case 235 : // System.out.println("IfThenElseStatement ::= if LPAREN Expression RPAREN StatementNoShortIf else...");
+ consumeStatementIfWithElse();
+ break;
+ case 236 : // System.out.println("IfThenElseStatementNoShortIf ::= if LPAREN Expression RPAREN StatementNoShortIf...");
+ consumeStatementIfWithElse();
+ break;
+ case 237 : // System.out.println("SwitchStatement ::= switch OpenBlock LPAREN Expression RPAREN SwitchBlock");
+ consumeStatementSwitch();
+ break;
+ case 238 : // System.out.println("SwitchBlock ::= LBRACE RBRACE");
+ consumeEmptySwitchBlock();
+ break;
+ case 241 : // System.out.println("SwitchBlock ::= LBRACE SwitchBlockStatements SwitchLabels RBRACE");
+ consumeSwitchBlock();
+ break;
+ case 243 : // System.out.println("SwitchBlockStatements ::= SwitchBlockStatements SwitchBlockStatement");
+ consumeSwitchBlockStatements();
+ break;
+ case 244 : // System.out.println("SwitchBlockStatement ::= SwitchLabels BlockStatements");
+ consumeSwitchBlockStatement();
+ break;
+ case 246 : // System.out.println("SwitchLabels ::= SwitchLabels SwitchLabel");
+ consumeSwitchLabels();
+ break;
+ case 247 : // System.out.println("SwitchLabel ::= case ConstantExpression COLON");
+ consumeCaseLabel();
+ break;
+ case 248 : // System.out.println("SwitchLabel ::= default COLON");
+ consumeDefaultLabel();
+ break;
+ case 249 : // System.out.println("WhileStatement ::= while LPAREN Expression RPAREN Statement");
+ consumeStatementWhile();
+ break;
+ case 250 : // System.out.println("WhileStatementNoShortIf ::= while LPAREN Expression RPAREN StatementNoShortIf");
+ consumeStatementWhile();
+ break;
+ case 251 : // System.out.println("DoStatement ::= do Statement while LPAREN Expression RPAREN SEMICOLON");
+ consumeStatementDo();
+ break;
+ case 252 : // System.out.println("ForStatement ::= for LPAREN ForInitopt SEMICOLON Expressionopt SEMICOLON...");
+ consumeStatementFor();
+ break;
+ case 253 : // System.out.println("ForStatementNoShortIf ::= for LPAREN ForInitopt SEMICOLON Expressionopt SEMICOLON");
+ consumeStatementFor();
+ break;
+ case 254 : // System.out.println("ForInit ::= StatementExpressionList");
+ consumeForInit();
+ break;
+ case 258 : // System.out.println("StatementExpressionList ::= StatementExpressionList COMMA StatementExpression");
+ consumeStatementExpressionList();
+ break;
+ case 259 : // System.out.println("BreakStatement ::= break SEMICOLON");
+ consumeStatementBreak();
+ break;
+ case 260 : // System.out.println("BreakStatement ::= break Identifier SEMICOLON");
+ consumeStatementBreakWithLabel();
+ break;
+ case 261 : // System.out.println("ContinueStatement ::= continue SEMICOLON");
+ consumeStatementContinue();
+ break;
+ case 262 : // System.out.println("ContinueStatement ::= continue Identifier SEMICOLON");
+ consumeStatementContinueWithLabel();
+ break;
+ case 263 : // System.out.println("ReturnStatement ::= return Expressionopt SEMICOLON");
+ consumeStatementReturn();
+ break;
+ case 264 : // System.out.println("ThrowStatement ::= throw Expression SEMICOLON");
+ consumeStatementThrow();
+ break;
+ case 265 : // System.out.println("SynchronizedStatement ::= OnlySynchronized LPAREN Expression RPAREN Block");
+ consumeStatementSynchronized();
+ break;
+ case 266 : // System.out.println("OnlySynchronized ::= synchronized");
+ consumeOnlySynchronized();
+ break;
+ case 267 : // System.out.println("TryStatement ::= try Block Catches");
+ consumeStatementTry(false);
+ break;
+ case 268 : // System.out.println("TryStatement ::= try Block Catchesopt Finally");
+ consumeStatementTry(true);
+ break;
+ case 270 : // System.out.println("Catches ::= Catches CatchClause");
+ consumeCatches();
+ break;
+ case 271 : // System.out.println("CatchClause ::= catch LPAREN FormalParameter RPAREN Block");
+ consumeStatementCatch();
+ break;
+ case 273 : // System.out.println("PushLPAREN ::= LPAREN");
+ consumeLeftParen();
+ break;
+ case 274 : // System.out.println("PushRPAREN ::= RPAREN");
+ consumeRightParen();
+ break;
+ case 278 : // System.out.println("PrimaryNoNewArray ::= this");
+ consumePrimaryNoNewArrayThis();
+ break;
+ case 279 : // System.out.println("PrimaryNoNewArray ::= PushLPAREN Expression PushRPAREN");
+ consumePrimaryNoNewArray();
+ break;
+ case 282 : // System.out.println("PrimaryNoNewArray ::= Name DOT this");
+ consumePrimaryNoNewArrayNameThis();
+ break;
+ case 283 : // System.out.println("PrimaryNoNewArray ::= Name DOT super");
+ consumePrimaryNoNewArrayNameSuper();
+ break;
+ case 284 : // System.out.println("PrimaryNoNewArray ::= Name DOT class");
+ consumePrimaryNoNewArrayName();
+ break;
+ case 285 : // System.out.println("PrimaryNoNewArray ::= ArrayType DOT class");
+ consumePrimaryNoNewArrayArrayType();
+ break;
+ case 286 : // System.out.println("PrimaryNoNewArray ::= PrimitiveType DOT class");
+ consumePrimaryNoNewArrayPrimitiveType();
+ break;
+ case 289 : // System.out.println("AllocationHeader ::= new ClassType LPAREN ArgumentListopt RPAREN");
+ consumeAllocationHeader();
+ break;
+ case 290 : // System.out.println("ClassInstanceCreationExpression ::= new ClassType LPAREN ArgumentListopt RPAREN...");
+ consumeClassInstanceCreationExpression();
+ break;
+ case 291 : // System.out.println("ClassInstanceCreationExpression ::= Primary DOT new SimpleName LPAREN...");
+ consumeClassInstanceCreationExpressionQualified();
+ break;
+ case 292 : // System.out.println("ClassInstanceCreationExpression ::= ClassInstanceCreationExpressionName new...");
+ consumeClassInstanceCreationExpressionQualified();
+ break;
+ case 293 : // System.out.println("ClassInstanceCreationExpressionName ::= Name DOT");
+ consumeClassInstanceCreationExpressionName();
+ break;
+ case 294 : // System.out.println("ClassBodyopt ::=");
+ consumeClassBodyopt();
+ break;
+ case 296 : // System.out.println("EnterAnonymousClassBody ::=");
+ consumeEnterAnonymousClassBody();
+ break;
+ case 298 : // System.out.println("ArgumentList ::= ArgumentList COMMA Expression");
+ consumeArgumentList();
+ break;
+ case 299 : // System.out.println("ArrayCreationExpression ::= new PrimitiveType DimWithOrWithOutExprs...");
+ consumeArrayCreationExpression();
+ break;
+ case 300 : // System.out.println("ArrayCreationExpression ::= new ClassOrInterfaceType DimWithOrWithOutExprs...");
+ consumeArrayCreationExpression();
+ break;
+ case 302 : // System.out.println("DimWithOrWithOutExprs ::= DimWithOrWithOutExprs DimWithOrWithOutExpr");
+ consumeDimWithOrWithOutExprs();
+ break;
+ case 304 : // System.out.println("DimWithOrWithOutExpr ::= LBRACKET RBRACKET");
+ consumeDimWithOrWithOutExpr();
+ break;
+ case 305 : // System.out.println("Dims ::= DimsLoop");
+ consumeDims();
+ break;
+ case 308 : // System.out.println("OneDimLoop ::= LBRACKET RBRACKET");
+ consumeOneDimLoop();
+ break;
+ case 309 : // System.out.println("FieldAccess ::= Primary DOT Identifier");
+ consumeFieldAccess(false);
+ break;
+ case 310 : // System.out.println("FieldAccess ::= super DOT Identifier");
+ consumeFieldAccess(true);
+ break;
+ case 311 : // System.out.println("MethodInvocation ::= Name LPAREN ArgumentListopt RPAREN");
+ consumeMethodInvocationName();
+ break;
+ case 312 : // System.out.println("MethodInvocation ::= Primary DOT Identifier LPAREN ArgumentListopt RPAREN");
+ consumeMethodInvocationPrimary();
+ break;
+ case 313 : // System.out.println("MethodInvocation ::= super DOT Identifier LPAREN ArgumentListopt RPAREN");
+ consumeMethodInvocationSuper();
+ break;
+ case 314 : // System.out.println("ArrayAccess ::= Name LBRACKET Expression RBRACKET");
+ consumeArrayAccess(true);
+ break;
+ case 315 : // System.out.println("ArrayAccess ::= PrimaryNoNewArray LBRACKET Expression RBRACKET");
+ consumeArrayAccess(false);
+ break;
+ case 317 : // System.out.println("PostfixExpression ::= Name");
+ consumePostfixExpression();
+ break;
+ case 320 : // System.out.println("PostIncrementExpression ::= PostfixExpression PLUS_PLUS");
+ consumeUnaryExpression(OperatorExpression.PLUS, true);
+ break;
+ case 321 : // System.out.println("PostDecrementExpression ::= PostfixExpression MINUS_MINUS");
+ consumeUnaryExpression(OperatorExpression.MINUS, true);
+ break;
+ case 322 : // System.out.println("PushPosition ::=");
+ consumePushPosition();
+ break;
+ case 325 : // System.out.println("UnaryExpression ::= PLUS PushPosition UnaryExpression");
+ consumeUnaryExpression(OperatorExpression.PLUS);
+ break;
+ case 326 : // System.out.println("UnaryExpression ::= MINUS PushPosition UnaryExpression");
+ consumeUnaryExpression(OperatorExpression.MINUS);
+ break;
+ case 328 : // System.out.println("PreIncrementExpression ::= PLUS_PLUS PushPosition UnaryExpression");
+ consumeUnaryExpression(OperatorExpression.PLUS, false);
+ break;
+ case 329 : // System.out.println("PreDecrementExpression ::= MINUS_MINUS PushPosition UnaryExpression");
+ consumeUnaryExpression(OperatorExpression.MINUS, false);
+ break;
+ case 331 : // System.out.println("UnaryExpressionNotPlusMinus ::= TWIDDLE PushPosition UnaryExpression");
+ consumeUnaryExpression(OperatorExpression.TWIDDLE);
+ break;
+ case 332 : // System.out.println("UnaryExpressionNotPlusMinus ::= NOT PushPosition UnaryExpression");
+ consumeUnaryExpression(OperatorExpression.NOT);
+ break;
+ case 334 : // System.out.println("CastExpression ::= PushLPAREN PrimitiveType Dimsopt PushRPAREN UnaryExpression");
+ consumeCastExpression();
+ break;
+ case 335 : // System.out.println("CastExpression ::= PushLPAREN Name Dims PushRPAREN UnaryExpressionNotPlusMinus");
+ consumeCastExpression();
+ break;
+ case 336 : // System.out.println("CastExpression ::= PushLPAREN Expression PushRPAREN UnaryExpressionNotPlusMinus");
+ consumeCastExpressionLL1();
+ break;
+ case 338 : // System.out.println("MultiplicativeExpression ::= MultiplicativeExpression MULTIPLY UnaryExpression");
+ consumeBinaryExpression(OperatorExpression.MULTIPLY);
+ break;
+ case 339 : // System.out.println("MultiplicativeExpression ::= MultiplicativeExpression DIVIDE UnaryExpression");
+ consumeBinaryExpression(OperatorExpression.DIVIDE);
+ break;
+ case 340 : // System.out.println("MultiplicativeExpression ::= MultiplicativeExpression REMAINDER UnaryExpression");
+ consumeBinaryExpression(OperatorExpression.REMAINDER);
+ break;
+ case 342 : // System.out.println("AdditiveExpression ::= AdditiveExpression PLUS MultiplicativeExpression");
+ consumeBinaryExpression(OperatorExpression.PLUS);
+ break;
+ case 343 : // System.out.println("AdditiveExpression ::= AdditiveExpression MINUS MultiplicativeExpression");
+ consumeBinaryExpression(OperatorExpression.MINUS);
+ break;
+ case 345 : // System.out.println("ShiftExpression ::= ShiftExpression LEFT_SHIFT AdditiveExpression");
+ consumeBinaryExpression(OperatorExpression.LEFT_SHIFT);
+ break;
+ case 346 : // System.out.println("ShiftExpression ::= ShiftExpression RIGHT_SHIFT AdditiveExpression");
+ consumeBinaryExpression(OperatorExpression.RIGHT_SHIFT);
+ break;
+ case 347 : // System.out.println("ShiftExpression ::= ShiftExpression UNSIGNED_RIGHT_SHIFT AdditiveExpression");
+ consumeBinaryExpression(OperatorExpression.UNSIGNED_RIGHT_SHIFT);
+ break;
+ case 349 : // System.out.println("RelationalExpression ::= RelationalExpression LESS ShiftExpression");
+ consumeBinaryExpression(OperatorExpression.LESS);
+ break;
+ case 350 : // System.out.println("RelationalExpression ::= RelationalExpression GREATER ShiftExpression");
+ consumeBinaryExpression(OperatorExpression.GREATER);
+ break;
+ case 351 : // System.out.println("RelationalExpression ::= RelationalExpression LESS_EQUAL ShiftExpression");
+ consumeBinaryExpression(OperatorExpression.LESS_EQUAL);
+ break;
+ case 352 : // System.out.println("RelationalExpression ::= RelationalExpression GREATER_EQUAL ShiftExpression");
+ consumeBinaryExpression(OperatorExpression.GREATER_EQUAL);
+ break;
+ case 353 : // System.out.println("RelationalExpression ::= RelationalExpression instanceof ReferenceType");
+ consumeInstanceOfExpression(OperatorExpression.INSTANCEOF);
+ break;
+ case 355 : // System.out.println("EqualityExpression ::= EqualityExpression EQUAL_EQUAL RelationalExpression");
+ consumeEqualityExpression(OperatorExpression.EQUAL_EQUAL);
+ break;
+ case 356 : // System.out.println("EqualityExpression ::= EqualityExpression NOT_EQUAL RelationalExpression");
+ consumeEqualityExpression(OperatorExpression.NOT_EQUAL);
+ break;
+ case 358 : // System.out.println("AndExpression ::= AndExpression AND EqualityExpression");
+ consumeBinaryExpression(OperatorExpression.AND);
+ break;
+ case 360 : // System.out.println("ExclusiveOrExpression ::= ExclusiveOrExpression XOR AndExpression");
+ consumeBinaryExpression(OperatorExpression.XOR);
+ break;
+ case 362 : // System.out.println("InclusiveOrExpression ::= InclusiveOrExpression OR ExclusiveOrExpression");
+ consumeBinaryExpression(OperatorExpression.OR);
+ break;
+ case 364 : // System.out.println("ConditionalAndExpression ::= ConditionalAndExpression AND_AND InclusiveOrExpression");
+ consumeBinaryExpression(OperatorExpression.AND_AND);
+ break;
+ case 366 : // System.out.println("ConditionalOrExpression ::= ConditionalOrExpression OR_OR ConditionalAndExpression");
+ consumeBinaryExpression(OperatorExpression.OR_OR);
+ break;
+ case 368 : // System.out.println("ConditionalExpression ::= ConditionalOrExpression QUESTION Expression COLON...");
+ consumeConditionalExpression(OperatorExpression.QUESTIONCOLON);
+ break;
+ case 371 : // System.out.println("Assignment ::= LeftHandSide AssignmentOperator AssignmentExpression");
+ consumeAssignment();
+ break;
+ case 373 : // System.out.println("Assignment ::= InvalidArrayInitializerAssignement");
+ ignoreExpressionAssignment();
+ break;
+ case 374 : // System.out.println("LeftHandSide ::= Name");
+ consumeLeftHandSide();
+ break;
+ case 377 : // System.out.println("AssignmentOperator ::= EQUAL");
+ consumeAssignmentOperator(EQUAL);
+ break;
+ case 378 : // System.out.println("AssignmentOperator ::= MULTIPLY_EQUAL");
+ consumeAssignmentOperator(MULTIPLY);
+ break;
+ case 379 : // System.out.println("AssignmentOperator ::= DIVIDE_EQUAL");
+ consumeAssignmentOperator(DIVIDE);
+ break;
+ case 380 : // System.out.println("AssignmentOperator ::= REMAINDER_EQUAL");
+ consumeAssignmentOperator(REMAINDER);
+ break;
+ case 381 : // System.out.println("AssignmentOperator ::= PLUS_EQUAL");
+ consumeAssignmentOperator(PLUS);
+ break;
+ case 382 : // System.out.println("AssignmentOperator ::= MINUS_EQUAL");
+ consumeAssignmentOperator(MINUS);
+ break;
+ case 383 : // System.out.println("AssignmentOperator ::= LEFT_SHIFT_EQUAL");
+ consumeAssignmentOperator(LEFT_SHIFT);
+ break;
+ case 384 : // System.out.println("AssignmentOperator ::= RIGHT_SHIFT_EQUAL");
+ consumeAssignmentOperator(RIGHT_SHIFT);
+ break;
+ case 385 : // System.out.println("AssignmentOperator ::= UNSIGNED_RIGHT_SHIFT_EQUAL");
+ consumeAssignmentOperator(UNSIGNED_RIGHT_SHIFT);
+ break;
+ case 386 : // System.out.println("AssignmentOperator ::= AND_EQUAL");
+ consumeAssignmentOperator(AND);
+ break;
+ case 387 : // System.out.println("AssignmentOperator ::= XOR_EQUAL");
+ consumeAssignmentOperator(XOR);
+ break;
+ case 388 : // System.out.println("AssignmentOperator ::= OR_EQUAL");
+ consumeAssignmentOperator(OR);
+ break;
+ case 395 : // System.out.println("Expressionopt ::=");
+ consumeEmptyExpression();
+ break;
+ case 399 : // System.out.println("ImportDeclarationsopt ::=");
+ consumeEmptyImportDeclarationsopt();
+ break;
+ case 400 : // System.out.println("ImportDeclarationsopt ::= ImportDeclarations");
+ consumeImportDeclarationsopt();
+ break;
+ case 401 : // System.out.println("TypeDeclarationsopt ::=");
+ consumeEmptyTypeDeclarationsopt();
+ break;
+ case 402 : // System.out.println("TypeDeclarationsopt ::= TypeDeclarations");
+ consumeTypeDeclarationsopt();
+ break;
+ case 403 : // System.out.println("ClassBodyDeclarationsopt ::=");
+ consumeEmptyClassBodyDeclarationsopt();
+ break;
+ case 404 : // System.out.println("ClassBodyDeclarationsopt ::= NestedType ClassBodyDeclarations");
+ consumeClassBodyDeclarationsopt();
+ break;
+ case 405 : // System.out.println("Modifiersopt ::=");
+ consumeDefaultModifiers();
+ break;
+ case 406 : // System.out.println("Modifiersopt ::= Modifiers");
+ consumeModifiers();
+ break;
+ case 407 : // System.out.println("BlockStatementsopt ::=");
+ consumeEmptyBlockStatementsopt();
+ break;
+ case 409 : // System.out.println("Dimsopt ::=");
+ consumeEmptyDimsopt();
+ break;
+ case 411 : // System.out.println("ArgumentListopt ::=");
+ consumeEmptyArgumentListopt();
+ break;
+ case 415 : // System.out.println("FormalParameterListopt ::=");
+ consumeFormalParameterListopt();
+ break;
+ case 419 : // System.out.println("InterfaceMemberDeclarationsopt ::=");
+ consumeEmptyInterfaceMemberDeclarationsopt();
+ break;
+ case 420 : // System.out.println("InterfaceMemberDeclarationsopt ::= NestedType InterfaceMemberDeclarations");
+ consumeInterfaceMemberDeclarationsopt();
+ break;
+ case 421 : // System.out.println("NestedType ::=");
+ consumeNestedType();
+ break;
+ case 422 : // System.out.println("ForInitopt ::=");
+ consumeEmptyForInitopt();
+ break;
+ case 424 : // System.out.println("ForUpdateopt ::=");
+ consumeEmptyForUpdateopt();
+ break;
+ case 428 : // System.out.println("Catchesopt ::=");
+ consumeEmptyCatchesopt();
+ break;
+ case 430 : // System.out.println("ArrayInitializeropt ::=");
+ consumeEmptyArrayInitializeropt();
+ break;
+ }
+ }
+
+ protected void consumeSingleTypeImportDeclaration() {
+ // SingleTypeImportDeclaration ::= SingleTypeImportDeclarationName ';'
+
+ ImportReference impt = (ImportReference) astStack[astPtr];
+ // flush annotations defined prior to import statements
+ impt.declarationSourceEnd =
+ this.flushAnnotationsDefinedPriorTo(impt.declarationSourceEnd);
+
+ // recovery
+ if (currentElement != null) {
+ lastCheckPoint = impt.declarationSourceEnd + 1;
+ currentElement = currentElement.add(impt, 0);
+ lastIgnoredToken = -1;
+ restartRecovery = true;
+ // used to avoid branching back into the regular automaton
+ }
+ }
+
+ protected void consumeSingleTypeImportDeclarationName() {
+ // SingleTypeImportDeclarationName ::= 'import' Name
+ /* push an ImportRef build from the last name
+ stored in the identifier stack. */
+
+ ImportReference impt;
+ int length;
+ char[][] tokens =
+ new char[length = identifierLengthStack[identifierLengthPtr--]][];
+ identifierPtr -= length;
+ long[] positions = new long[length];
+ System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length);
+ System.arraycopy(
+ identifierPositionStack,
+ identifierPtr + 1,
+ positions,
+ 0,
+ length);
+ pushOnAstStack(impt = new ImportReference(tokens, positions, false));
+
+ if (currentToken == TokenNameSEMICOLON) {
+ impt.declarationSourceEnd = scanner.currentPosition - 1;
+ } else {
+ impt.declarationSourceEnd = impt.sourceEnd;
+ }
+ //endPosition is just before the ;
+ impt.declarationSourceStart = intStack[intPtr--];
+
+ // recovery
+ if (currentElement != null) {
+ lastCheckPoint = impt.declarationSourceEnd + 1;
+ currentElement = currentElement.add(impt, 0);
+ lastIgnoredToken = -1;
+ restartRecovery = true;
+ // used to avoid branching back into the regular automaton
+ }
+ }
+
+ protected void consumeStatementBreak() {
+ // BreakStatement ::= 'break' ';'
+ // break pushs a position on intStack in case there is no label
+
+ pushOnAstStack(new Break(null, intStack[intPtr--], endPosition));
+ }
+
+ protected void consumeStatementBreakWithLabel() {
+ // BreakStatement ::= 'break' Identifier ';'
+ // break pushs a position on intStack in case there is no label
+
+ pushOnAstStack(
+ new Break(identifierStack[identifierPtr--], intStack[intPtr--], endPosition));
+ identifierLengthPtr--;
+ }
+
+ protected void consumeStatementCatch() {
+ // CatchClause ::= 'catch' '(' FormalParameter ')' Block
+
+ //catch are stored directly into the Try
+ //has they always comes two by two....
+ //we remove one entry from the astlengthPtr.
+ //The construction of the try statement must
+ //then fetch the catches using 2*i and 2*i + 1
+
+ astLengthPtr--;
+ listLength = 0;
+ // reset formalParameter counter (incremented for catch variable)
+ }
+
+ protected void consumeStatementContinue() {
+ // ContinueStatement ::= 'continue' ';'
+ // continue pushs a position on intStack in case there is no label
+
+ pushOnAstStack(new Continue(null, intStack[intPtr--], endPosition));
+ }
+
+ protected void consumeStatementContinueWithLabel() {
+ // ContinueStatement ::= 'continue' Identifier ';'
+ // continue pushs a position on intStack in case there is no label
+
+ pushOnAstStack(
+ new Continue(
+ identifierStack[identifierPtr--],
+ intStack[intPtr--],
+ endPosition));
+ identifierLengthPtr--;
+ }
+
+ protected void consumeStatementDo() {
+ // DoStatement ::= 'do' Statement 'while' '(' Expression ')' ';'
+
+ //the 'while' pushes a value on intStack that we need to remove
+ intPtr--;
+
+ //optimize the push/pop
+ if (astLengthStack[astLengthPtr] == 0) {
+ astLengthStack[astLengthPtr] = 1;
+ expressionLengthPtr--;
+ astStack[++astPtr] =
+ new DoStatement(
+ expressionStack[expressionPtr--],
+ null,
+ intStack[intPtr--],
+ endPosition);
+ } else {
+ expressionLengthPtr--;
+ astStack[astPtr] =
+ new DoStatement(
+ expressionStack[expressionPtr--],
+ (Statement) astStack[astPtr],
+ intStack[intPtr--],
+ endPosition);
+ }
+ }
+
+ protected void consumeStatementExpressionList() {
+ // StatementExpressionList ::= StatementExpressionList ',' StatementExpression
+ concatExpressionLists();
+ }
+
+ protected void consumeStatementFor() {
+ // ForStatement ::= 'for' '(' ForInitopt ';' Expressionopt ';' ForUpdateopt ')' Statement
+ // ForStatementNoShortIf ::= 'for' '(' ForInitopt ';' Expressionopt ';' ForUpdateopt ')' StatementNoShortIf
+
+ int length;
+ Expression cond = null;
+ Statement[] inits, updates;
+ Statement action;
+ boolean scope = true;
+
+ //statements
+ if (astLengthStack[astLengthPtr--] != 0) {
+ action = (Statement) astStack[astPtr--];
+ } else {
+ action = null;
+ }
+
+ //updates are on the expresion stack
+ if ((length = expressionLengthStack[expressionLengthPtr--]) == 0) {
+ updates = null;
+ } else {
+ expressionPtr -= length;
+ System.arraycopy(
+ expressionStack,
+ expressionPtr + 1,
+ updates = new Statement[length],
+ 0,
+ length);
+ }
+
+ if (expressionLengthStack[expressionLengthPtr--] != 0)
+ cond = expressionStack[expressionPtr--];
+
+ //inits may be on two different stacks
+ if ((length = astLengthStack[astLengthPtr--]) == 0) {
+ inits = null;
+ scope = false;
+ } else {
+ if (length == -1) { //on expressionStack
+ scope = false;
+ length = expressionLengthStack[expressionLengthPtr--];
+ expressionPtr -= length;
+ System.arraycopy(
+ expressionStack,
+ expressionPtr + 1,
+ inits = new Statement[length],
+ 0,
+ length);
+ } else { //on astStack
+ astPtr -= length;
+ System.arraycopy(
+ astStack,
+ astPtr + 1,
+ inits = new Statement[length],
+ 0,
+ length);
+ }
+ };
+
+ pushOnAstStack(
+ new ForStatement(
+ inits,
+ cond,
+ updates,
+ action,
+ scope,
+ intStack[intPtr--],
+ endPosition));
+ }
+
+ protected void consumeStatementIfNoElse() {
+ // IfThenStatement ::= 'if' '(' Expression ')' Statement
+
+ //optimize the push/pop
+ if (astLengthStack[astLengthPtr] == 0) {
+ astLengthStack[astLengthPtr] = 1;
+ expressionLengthPtr--;
+ astStack[++astPtr] =
+ new IfStatement(
+ expressionStack[expressionPtr--],
+ Block.None,
+ intStack[intPtr--],
+ endPosition);
+ } else {
+ expressionLengthPtr--;
+ astStack[astPtr] =
+ new IfStatement(
+ expressionStack[expressionPtr--],
+ (Statement) astStack[astPtr],
+ intStack[intPtr--],
+ endPosition);
+ }
+ }
+
+ protected void consumeStatementIfWithElse() {
+ // IfThenElseStatement ::= 'if' '(' Expression ')' StatementNoShortIf 'else' Statement
+ // IfThenElseStatementNoShortIf ::= 'if' '(' Expression ')' StatementNoShortIf 'else' StatementNoShortIf
+
+ int lengthE, lengthT;
+ lengthE = astLengthStack[astLengthPtr--]; //first decrement
+
+ if (((lengthT = astLengthStack[astLengthPtr]) != 0) && (lengthE != 0)) {
+ expressionLengthPtr--;
+ //optimize the push/pop
+ astStack[--astPtr] =
+ new IfStatement(
+ expressionStack[expressionPtr--],
+ (Statement) astStack[astPtr],
+ (Statement) astStack[astPtr + 1],
+ intStack[intPtr--],
+ endPosition);
+ } else {
+ astLengthPtr--; //second decrement
+ expressionLengthPtr--;
+ pushOnAstStack(new IfStatement(expressionStack[expressionPtr--],
+ //here only one of lengthE/T can be different 0
+ (lengthT == 0) ? Block.None : (Statement) astStack[astPtr--],
+ (lengthE == 0) ? Block.None : (Statement) astStack[astPtr--],
+ intStack[intPtr--],
+ endPosition));
+ }
+ }
+
+ protected void consumeStatementLabel() {
+ // LabeledStatement ::= 'Identifier' ':' Statement
+ // LabeledStatementNoShortIf ::= 'Identifier' ':' StatementNoShortIf
+
+ //optimize push/pop
+
+ if (astLengthStack[astLengthPtr] == 0) {
+ astLengthStack[astLengthPtr] = 1;
+ astStack[++astPtr] =
+ new LabeledStatement(
+ identifierStack[identifierPtr],
+ Block.None,
+ (int) (identifierPositionStack[identifierPtr--] >>> 32),
+ endPosition);
+ } else {
+ astStack[astPtr] =
+ new LabeledStatement(
+ identifierStack[identifierPtr],
+ (Statement) astStack[astPtr],
+ (int) (identifierPositionStack[identifierPtr--] >>> 32),
+ endPosition);
+ }
+
+ identifierLengthPtr--;
+ }
+
+ protected void consumeStatementReturn() {
+ // ReturnStatement ::= 'return' Expressionopt ';'
+ // return pushs a position on intStack in case there is no expression
+
+ if (expressionLengthStack[expressionLengthPtr--] != 0) {
+ pushOnAstStack(
+ new ReturnStatement(
+ expressionStack[expressionPtr--],
+ intStack[intPtr--],
+ endPosition));
+ } else {
+ pushOnAstStack(new ReturnStatement(null, intStack[intPtr--], endPosition));
+ }
+ }
+
+ protected void consumeStatementSwitch() {
+ // SwitchStatement ::= 'switch' OpenBlock '(' Expression ')' SwitchBlock
+
+ //OpenBlock just makes the semantic action blockStart()
+ //the block is inlined but a scope need to be created
+ //if some declaration occurs.
+
+ int length;
+ SwitchStatement s = new SwitchStatement();
+ expressionLengthPtr--;
+ s.testExpression = expressionStack[expressionPtr--];
+ if ((length = astLengthStack[astLengthPtr--]) != 0) {
+ astPtr -= length;
+ System.arraycopy(
+ astStack,
+ astPtr + 1,
+ s.statements = new Statement[length],
+ 0,
+ length);
+ }
+ s.explicitDeclarations = realBlockStack[realBlockPtr--];
+ pushOnAstStack(s);
+ intPtr--; // because of OpenBlock
+ s.sourceStart = intStack[intPtr--];
+ s.sourceEnd = endPosition;
+ }
+
+ protected void consumeStatementSynchronized() {
+ // SynchronizedStatement ::= OnlySynchronized '(' Expression ')' Block
+ //optimize the push/pop
+
+ Expression exp;
+ if (astLengthStack[astLengthPtr] == 0) {
+ astLengthStack[astLengthPtr] = 1;
+ expressionLengthPtr--;
+ astStack[++astPtr] =
+ new SynchronizedStatement(
+ exp = expressionStack[expressionPtr--],
+ Block.None,
+ exp.sourceStart,
+ exp.sourceEnd);
+ } else {
+ expressionLengthPtr--;
+ astStack[astPtr] =
+ new SynchronizedStatement(
+ exp = expressionStack[expressionPtr--],
+ (Block) astStack[astPtr],
+ exp.sourceStart,
+ exp.sourceEnd);
+ }
+ resetModifiers();
+ }
+
+ protected void consumeStatementThrow() {
+ // ThrowStatement ::= 'throw' Expression ';'
+ expressionLengthPtr--;
+ pushOnAstStack(
+ new ThrowStatement(expressionStack[expressionPtr--], intStack[intPtr--]));
+ }
+
+ protected void consumeStatementTry(boolean withFinally) {
+ //TryStatement ::= 'try' Block Catches
+ //TryStatement ::= 'try' Block Catchesopt Finally
+
+ int length;
+ TryStatement tryStmt = new TryStatement();
+ //finally
+ if (withFinally) {
+ astLengthPtr--;
+ tryStmt.finallyBlock = (Block) astStack[astPtr--];
+ }
+ //catches are handle by two <argument-block> [see statementCatch]
+ if ((length = astLengthStack[astLengthPtr--]) != 0) {
+ if (length == 1) {
+ tryStmt.catchBlocks = new Block[] {(Block) astStack[astPtr--] };
+ tryStmt.catchArguments = new Argument[] {(Argument) astStack[astPtr--] };
+ } else {
+ Block[] bks = (tryStmt.catchBlocks = new Block[length]);
+ Argument[] args = (tryStmt.catchArguments = new Argument[length]);
+ while (length-- > 0) {
+ bks[length] = (Block) astStack[astPtr--];
+ args[length] = (Argument) astStack[astPtr--];
+ }
+ }
+ }
+ //try
+ astLengthPtr--;
+ tryStmt.tryBlock = (Block) astStack[astPtr--];
+
+ //positions
+ tryStmt.sourceEnd = endPosition;
+ tryStmt.sourceStart = intStack[intPtr--];
+ pushOnAstStack(tryStmt);
+ }
+
+ protected void consumeStatementWhile() {
+ // WhileStatement ::= 'while' '(' Expression ')' Statement
+ // WhileStatementNoShortIf ::= 'while' '(' Expression ')' StatementNoShortIf
+
+ //optimize the push/pop
+ if (astLengthStack[astLengthPtr] == 0) {
+ astLengthStack[astLengthPtr] = 1;
+ expressionLengthPtr--;
+ astStack[++astPtr] =
+ new WhileStatement(
+ expressionStack[expressionPtr--],
+ null,
+ intStack[intPtr--],
+ endPosition);
+ } else {
+ expressionLengthPtr--;
+ astStack[astPtr] =
+ new WhileStatement(
+ expressionStack[expressionPtr--],
+ (Statement) astStack[astPtr],
+ intStack[intPtr--],
+ endPosition);
+ }
+ }
+
+ protected void consumeStaticInitializer() {
+ // StaticInitializer ::= StaticOnly Block
+ //push an Initializer
+ //optimize the push/pop
+ Initializer initializer = new Initializer((Block) astStack[astPtr], AccStatic);
+ astStack[astPtr] = initializer;
+ initializer.sourceEnd = endStatementPosition;
+ initializer.declarationSourceEnd =
+ flushAnnotationsDefinedPriorTo(endStatementPosition);
+ nestedMethod[nestedType]--;
+ initializer.declarationSourceStart = intStack[intPtr--];
+
+ // recovery
+ if (currentElement != null) {
+ lastCheckPoint = initializer.declarationSourceEnd;
+ currentElement = currentElement.add(initializer, 0);
+ lastIgnoredToken = -1;
+ }
+ }
+
+ protected void consumeStaticOnly() {
+ // StaticOnly ::= 'static'
+ checkAnnotation(); // might update declaration source start
+ pushOnIntStack(
+ modifiersSourceStart >= 0 ? modifiersSourceStart : scanner.startPosition);
+ jumpOverMethodBody();
+ nestedMethod[nestedType]++;
+ resetModifiers();
+
+ // recovery
+ if (currentElement != null) {
+ recoveredStaticInitializerStart = intStack[intPtr];
+ // remember start position only for static initializers
+ }
+ }
+
+ protected void consumeSwitchBlock() {
+ // SwitchBlock ::= '{' SwitchBlockStatements SwitchLabels '}'
+ concatNodeLists();
+ }
+
+ protected void consumeSwitchBlockStatement() {
+ // SwitchBlockStatement ::= SwitchLabels BlockStatements
+ concatNodeLists();
+ }
+
+ protected void consumeSwitchBlockStatements() {
+ // SwitchBlockStatements ::= SwitchBlockStatements SwitchBlockStatement
+ concatNodeLists();
+ }
+
+ protected void consumeSwitchLabels() {
+ // SwitchLabels ::= SwitchLabels SwitchLabel
+ optimizedConcatNodeLists();
+ }
+
+ protected void consumeToken(int type) {
+ /* remember the last consumed value */
+ /* try to minimize the number of build values */
+
+ //System.out.println(scanner.toStringAction(type));
+ switch (type) {
+
+ case TokenNameIdentifier :
+ pushIdentifier();
+ break;
+
+ case TokenNameinterface :
+ adjustInterfaceModifiers();
+ //'class' is pushing an int (position) on the stack ==> 'interface' needs to do it too....
+ pushOnIntStack(scanner.startPosition);
+ break;
+
+ case TokenNameabstract :
+ checkAndSetModifiers(AccAbstract);
+ break;
+ case TokenNamestrictfp :
+ checkAndSetModifiers(AccStrictfp);
+ break;
+ case TokenNamefinal :
+ checkAndSetModifiers(AccFinal);
+ break;
+ case TokenNamenative :
+ checkAndSetModifiers(AccNative);
+ break;
+ case TokenNameprivate :
+ checkAndSetModifiers(AccPrivate);
+ break;
+ case TokenNameprotected :
+ checkAndSetModifiers(AccProtected);
+ break;
+ case TokenNamepublic :
+ checkAndSetModifiers(AccPublic);
+ break;
+ case TokenNametransient :
+ checkAndSetModifiers(AccTransient);
+ break;
+ case TokenNamevolatile :
+ checkAndSetModifiers(AccVolatile);
+ break;
+ case TokenNamestatic :
+ checkAndSetModifiers(AccStatic);
+ break;
+ case TokenNamesynchronized :
+ checkAndSetModifiers(AccSynchronized);
+ break;
+
+ //==============================
+
+ case TokenNamevoid :
+ pushIdentifier(-T_void);
+ pushOnIntStack(scanner.startPosition);
+ break;
+ //push a default dimension while void is not part of the primitive
+ //declaration baseType and so takes the place of a type without getting into
+ //regular type parsing that generates a dimension on intStack
+
+ case TokenNameboolean :
+ pushIdentifier(-T_boolean);
+ pushOnIntStack(scanner.startPosition);
+ break;
+ case TokenNamebyte :
+ pushIdentifier(-T_byte);
+ pushOnIntStack(scanner.startPosition);
+ break;
+ case TokenNamechar :
+ pushIdentifier(-T_char);
+ pushOnIntStack(scanner.startPosition);
+ break;
+ case TokenNamedouble :
+ pushIdentifier(-T_double);
+ pushOnIntStack(scanner.startPosition);
+ break;
+ case TokenNamefloat :
+ pushIdentifier(-T_float);
+ pushOnIntStack(scanner.startPosition);
+ break;
+ case TokenNameint :
+ pushIdentifier(-T_int);
+ pushOnIntStack(scanner.startPosition);
+ break;
+ case TokenNamelong :
+ pushIdentifier(-T_long);
+ pushOnIntStack(scanner.startPosition);
+ break;
+ case TokenNameshort :
+ pushIdentifier(-T_short);
+ pushOnIntStack(scanner.startPosition);
+ break;
+
+ //==============================
+
+ case TokenNameIntegerLiteral :
+ pushOnExpressionStack(
+ new IntLiteral(
+ scanner.getCurrentTokenSource(),
+ scanner.startPosition,
+ scanner.currentPosition - 1));
+ break;
+ case TokenNameLongLiteral :
+ pushOnExpressionStack(
+ new LongLiteral(
+ scanner.getCurrentTokenSource(),
+ scanner.startPosition,
+ scanner.currentPosition - 1));
+ break;
+ case TokenNameFloatingPointLiteral :
+ pushOnExpressionStack(
+ new FloatLiteral(
+ scanner.getCurrentTokenSource(),
+ scanner.startPosition,
+ scanner.currentPosition - 1));
+ break;
+ case TokenNameDoubleLiteral :
+ pushOnExpressionStack(
+ new DoubleLiteral(
+ scanner.getCurrentTokenSource(),
+ scanner.startPosition,
+ scanner.currentPosition - 1));
+ break;
+ case TokenNameCharacterLiteral :
+ pushOnExpressionStack(
+ new CharLiteral(
+ scanner.getCurrentTokenSource(),
+ scanner.startPosition,
+ scanner.currentPosition - 1));
+ break;
+ case TokenNameStringLiteral :
+ pushOnExpressionStack(
+ new StringLiteral(
+ scanner.getCurrentTokenSourceString(),
+ scanner.startPosition,
+ scanner.currentPosition - 1));
+ break;
+ case TokenNamefalse :
+ pushOnExpressionStack(
+ new FalseLiteral(scanner.startPosition, scanner.currentPosition - 1));
+ break;
+ case TokenNametrue :
+ pushOnExpressionStack(
+ new TrueLiteral(scanner.startPosition, scanner.currentPosition - 1));
+ break;
+ case TokenNamenull :
+ pushOnExpressionStack(
+ new NullLiteral(scanner.startPosition, scanner.currentPosition - 1));
+ break;
+
+ //============================
+ case TokenNamesuper :
+ case TokenNamethis :
+ endPosition = scanner.currentPosition - 1;
+ pushOnIntStack(scanner.startPosition);
+ break;
+ case TokenNameimport :
+ case TokenNamepackage :
+ case TokenNamethrow :
+ case TokenNamenew :
+ case TokenNamedo :
+ case TokenNameif :
+ case TokenNamefor :
+ case TokenNameswitch :
+ case TokenNametry :
+ case TokenNamewhile :
+ case TokenNamebreak :
+ case TokenNamecontinue :
+ case TokenNameclass :
+ case TokenNamereturn :
+ pushOnIntStack(scanner.startPosition);
+ break;
+
+ //let extra semantic action decide when to push
+
+ case TokenNamedefault :
+ case TokenNameRBRACKET :
+ case TokenNamePLUS_PLUS :
+ case TokenNameMINUS_MINUS :
+ case TokenNamePLUS :
+ case TokenNameMINUS :
+ case TokenNameNOT :
+ case TokenNameTWIDDLE :
+ endPosition = scanner.startPosition;
+ break;
+ case TokenNameRBRACE :
+ case TokenNameSEMICOLON :
+ endStatementPosition = scanner.currentPosition - 1;
+ endPosition = scanner.startPosition - 1;
+ //the item is not part of the potential futur expression/statement
+ break;
+ // in order to handle ( expression) ////// (cast)expression///// foo(x)
+ case TokenNameRPAREN :
+ rParenPos = scanner.currentPosition - 1;
+ // position of the end of right parenthesis (in case of unicode \u0029) lex00101
+ break;
+ case TokenNameLPAREN :
+ lParenPos = scanner.startPosition;
+ break;
+ // case TokenNameQUESTION :
+ // case TokenNameCOMMA :
+ // case TokenNameCOLON :
+ // case TokenNameEQUAL :
+ // case TokenNameLBRACKET :
+ // case TokenNameDOT :
+ // case TokenNameERROR :
+ // case TokenNameEOF :
+ // case TokenNamecase :
+ // case TokenNamecatch :
+ // case TokenNameelse :
+ // case TokenNameextends :
+ // case TokenNamefinally :
+ // case TokenNameimplements :
+ // case TokenNamethrows :
+ // case TokenNameinstanceof :
+ // case TokenNameEQUAL_EQUAL :
+ // case TokenNameLESS_EQUAL :
+ // case TokenNameGREATER_EQUAL :
+ // case TokenNameNOT_EQUAL :
+ // case TokenNameLEFT_SHIFT :
+ // case TokenNameRIGHT_SHIFT :
+ // case TokenNameUNSIGNED_RIGHT_SHIFT :
+ // case TokenNamePLUS_EQUAL :
+ // case TokenNameMINUS_EQUAL :
+ // case TokenNameMULTIPLY_EQUAL :
+ // case TokenNameDIVIDE_EQUAL :
+ // case TokenNameAND_EQUAL :
+ // case TokenNameOR_EQUAL :
+ // case TokenNameXOR_EQUAL :
+ // case TokenNameREMAINDER_EQUAL :
+ // case TokenNameLEFT_SHIFT_EQUAL :
+ // case TokenNameRIGHT_SHIFT_EQUAL :
+ // case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL :
+ // case TokenNameOR_OR :
+ // case TokenNameAND_AND :
+ // case TokenNameREMAINDER :
+ // case TokenNameXOR :
+ // case TokenNameAND :
+ // case TokenNameMULTIPLY :
+ // case TokenNameOR :
+ // case TokenNameDIVIDE :
+ // case TokenNameGREATER :
+ // case TokenNameLESS :
+
+ }
+ }
+
+ protected void consumeTypeDeclarations() {
+ // TypeDeclarations ::= TypeDeclarations TypeDeclaration
+ concatNodeLists();
+ }
+
+ protected void consumeTypeDeclarationsopt() {
+ // TypeDeclarationsopt ::= TypeDeclarations
+ int length;
+ if ((length = astLengthStack[astLengthPtr--]) != 0) {
+ astPtr -= length;
+ System.arraycopy(
+ astStack,
+ astPtr + 1,
+ compilationUnit.types = new TypeDeclaration[length],
+ 0,
+ length);
+ }
+ }
+
+ protected void consumeTypeImportOnDemandDeclaration() {
+ // TypeImportOnDemandDeclaration ::= TypeImportOnDemandDeclarationName ';'
+
+ ImportReference impt = (ImportReference) astStack[astPtr];
+ // flush annotations defined prior to import statements
+ impt.declarationSourceEnd =
+ this.flushAnnotationsDefinedPriorTo(impt.declarationSourceEnd);
+
+ // recovery
+ if (currentElement != null) {
+ lastCheckPoint = impt.declarationSourceEnd + 1;
+ currentElement = currentElement.add(impt, 0);
+ restartRecovery = true;
+ lastIgnoredToken = -1;
+ // used to avoid branching back into the regular automaton
+ }
+ }
+
+ protected void consumeTypeImportOnDemandDeclarationName() {
+ // TypeImportOnDemandDeclarationName ::= 'import' Name '.' '*'
+ /* push an ImportRef build from the last name
+ stored in the identifier stack. */
+
+ ImportReference impt;
+ int length;
+ char[][] tokens =
+ new char[length = identifierLengthStack[identifierLengthPtr--]][];
+ identifierPtr -= length;
+ long[] positions = new long[length];
+ System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length);
+ System.arraycopy(
+ identifierPositionStack,
+ identifierPtr + 1,
+ positions,
+ 0,
+ length);
+ pushOnAstStack(impt = new ImportReference(tokens, positions, true));
+
+ if (currentToken == TokenNameSEMICOLON) {
+ impt.declarationSourceEnd = scanner.currentPosition - 1;
+ } else {
+ impt.declarationSourceEnd = impt.sourceEnd;
+ }
+ //endPosition is just before the ;
+ impt.declarationSourceStart = intStack[intPtr--];
+
+ // recovery
+ if (currentElement != null) {
+ lastCheckPoint = impt.declarationSourceEnd + 1;
+ currentElement = currentElement.add(impt, 0);
+ lastIgnoredToken = -1;
+ restartRecovery = true;
+ // used to avoid branching back into the regular automaton
+ }
+ }
+
+ protected void consumeUnaryExpression(int op) {
+ // UnaryExpression ::= '+' PushPosition UnaryExpression
+ // UnaryExpression ::= '-' PushPosition UnaryExpression
+ // UnaryExpressionNotPlusMinus ::= '~' PushPosition UnaryExpression
+ // UnaryExpressionNotPlusMinus ::= '!' PushPosition UnaryExpression
+
+ //optimize the push/pop
+
+ //handle manually the -2147483648 while it is not a real
+ //computation of an - and 2147483648 (notice that 2147483648
+ //is Integer.MAX_VALUE+1.....)
+ //Same for -9223372036854775808L ............
+
+ //intStack have the position of the operator
+
+ Expression r, exp = expressionStack[expressionPtr];
+ if (op == MINUS) {
+ if ((exp instanceof IntLiteral)
+ && (((IntLiteral) exp).mayRepresentMIN_VALUE())) {
+ r = expressionStack[expressionPtr] = new IntLiteralMinValue();
+ } else {
+ if ((exp instanceof LongLiteral)
+ && (((LongLiteral) exp).mayRepresentMIN_VALUE())) {
+ r = expressionStack[expressionPtr] = new LongLiteralMinValue();
+ } else {
+ r = expressionStack[expressionPtr] = new UnaryExpression(exp, op);
+ }
+ }
+ } else {
+ r = expressionStack[expressionPtr] = new UnaryExpression(exp, op);
+ }
+ r.sourceStart = intStack[intPtr--];
+ r.sourceEnd = exp.sourceEnd;
+ }
+
+ protected void consumeUnaryExpression(int op, boolean post) {
+ // PreIncrementExpression ::= '++' PushPosition UnaryExpression
+ // PreDecrementExpression ::= '--' PushPosition UnaryExpression
+
+ // ++ and -- operators
+ //optimize the push/pop
+
+ //intStack has the position of the operator when prefix
+
+ Expression leftHandSide = expressionStack[expressionPtr];
+ if (leftHandSide instanceof Reference) {
+ // ++foo()++ is unvalid
+ if (post) {
+ expressionStack[expressionPtr] =
+ new PostfixExpression(leftHandSide, IntLiteral.One, op, endPosition + 1);
+ } else {
+ expressionStack[expressionPtr] =
+ new PrefixExpression(leftHandSide, IntLiteral.One, op, intStack[intPtr--]);
+ }
+ } else {
+ //the ++ or the -- is NOT taken into account if code gen proceeds
+ if (!post) {
+ intPtr--;
+ }
+ problemReporter().invalidUnaryExpression(leftHandSide);
+ }
+ }
+
+ protected void consumeVariableDeclarators() {
+ // VariableDeclarators ::= VariableDeclarators ',' VariableDeclarator
+ optimizedConcatNodeLists();
+ }
+
+ protected void consumeVariableInitializers() {
+ // VariableInitializers ::= VariableInitializers ',' VariableInitializer
+ concatExpressionLists();
+ }
+
+ protected FieldDeclaration createFieldDeclaration(
+ Expression initialization,
+ char[] name,
+ int sourceStart,
+ int sourceEnd) {
+ return new FieldDeclaration(null, name, sourceStart, sourceEnd);
+ }
+
+ public CompilationUnitDeclaration dietParse(
+ ICompilationUnit sourceUnit,
+ CompilationResult compilationResult) {
+
+ CompilationUnitDeclaration parsedUnit;
+ boolean old = diet;
+ try {
+ diet = true;
+ parsedUnit = parse(sourceUnit, compilationResult);
+ } finally {
+ diet = old;
+ }
+ return parsedUnit;
+ }
+
+ protected void dispatchDeclarationInto(int length) {
+ /* they are length on astStack that should go into
+ methods fields constructors lists of the typeDecl
+
+ Return if there is a constructor declaration in the methods declaration */
+
+ // Looks for the size of each array .
+
+ if (length == 0)
+ return;
+ int[] flag = new int[length + 1]; //plus one -- see <HERE>
+ int size1 = 0, size2 = 0, size3 = 0;
+ for (int i = length - 1; i >= 0; i--) {
+ AstNode astNode = astStack[astPtr--];
+ if (astNode instanceof AbstractMethodDeclaration) {
+ //methods and constructors have been regrouped into one single list
+ flag[i] = 3;
+ size2++;
+ } else {
+ if (astNode instanceof TypeDeclaration) {
+ flag[i] = 4;
+ size3++;
+ } else {
+ //field
+ flag[i] = 1;
+ size1++;
+ }
+ }
+ }
+
+ //arrays creation
+ TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr];
+ if (size1 != 0)
+ typeDecl.fields = new FieldDeclaration[size1];
+ if (size2 != 0)
+ typeDecl.methods = new AbstractMethodDeclaration[size2];
+ if (size3 != 0)
+ typeDecl.memberTypes = new MemberTypeDeclaration[size3];
+
+ //arrays fill up
+ size1 = size2 = size3 = 0;
+ int flagI = flag[0], start = 0;
+ int length2;
+ for (int end = 0; end <= length; end++) //<HERE> the plus one allows to
+ {
+ if (flagI != flag[end]) //treat the last element as a ended flag.....
+ { //array copy
+ switch (flagI) {
+ case 1 :
+ size1 += (length2 = end - start);
+ System.arraycopy(
+ astStack,
+ astPtr + start + 1,
+ typeDecl.fields,
+ size1 - length2,
+ length2);
+ break;
+ case 3 :
+ size2 += (length2 = end - start);
+ System.arraycopy(
+ astStack,
+ astPtr + start + 1,
+ typeDecl.methods,
+ size2 - length2,
+ length2);
+ break;
+ case 4 :
+ size3 += (length2 = end - start);
+ System.arraycopy(
+ astStack,
+ astPtr + start + 1,
+ typeDecl.memberTypes,
+ size3 - length2,
+ length2);
+ break;
+ };
+ flagI = flag[start = end];
+ }
+ }
+
+ if (typeDecl.memberTypes != null) {
+ for (int i = typeDecl.memberTypes.length - 1; i >= 0; i--) {
+ typeDecl.memberTypes[i].enclosingType = typeDecl;
+ }
+ }
+ }
+
+ protected CompilationUnitDeclaration endParse(int act) {
+
+ this.lastAct = act;
+
+ if (currentElement != null) {
+ currentElement.topElement().updateParseTree();
+ if (VERBOSE_RECOVERY) {
+ System.out.println("SYNTAX RECOVERY--------------------------");
+ System.out.println(compilationUnit);
+ System.out.println("----------------------------------");
+ }
+ } else {
+ if (diet & VERBOSE_RECOVERY) {
+ System.out.println("REGULAR PARSE--------------------------");
+ System.out.println(compilationUnit);
+ System.out.println("----------------------------------");
+ }
+ }
+ if (scanner.recordLineSeparator) {
+ compilationUnit.compilationResult.lineSeparatorPositions = scanner.lineEnds();
+ }
+ return compilationUnit;
+ }
+
+ /*
+ * Flush annotations defined prior to a given positions.
+ *
+ * Note: annotations are stacked in syntactical order
+ *
+ * Either answer given <position>, or the end position of a comment line
+ * immediately following the <position> (same line)
+ *
+ * e.g.
+ * void foo(){
+ * } // end of method foo
+ */
+
+ public int flushAnnotationsDefinedPriorTo(int position) {
+
+ int lastAnnotationIndex = scanner.commentPtr;
+ if (lastAnnotationIndex < 0)
+ return position; // no comment
+
+ // compute the index of the first obsolete comment
+ int index = lastAnnotationIndex;
+ int validCount = 0;
+ while (index >= 0) {
+ int commentEnd = scanner.commentStops[index];
+ if (commentEnd < 0)
+ commentEnd = -commentEnd; // negative end position for non-javadoc comments
+ if (commentEnd <= position) {
+ break;
+ }
+ index--;
+ validCount++;
+ }
+ // if the source at <position> is immediately followed by a line comment, then
+ // flush this comment and shift <position> to the comment end.
+ if (validCount > 0) {
+ int immediateCommentEnd = -scanner.commentStops[index + 1];
+ //non-javadoc comment end positions are negative
+ if (immediateCommentEnd > 0) { // only tolerating non-javadoc comments
+ // is there any line break until the end of the immediate comment ? (thus only tolerating line comment)
+ immediateCommentEnd--; // comment end in one char too far
+ if (scanner.searchLineNumber(position)
+ == scanner.searchLineNumber(immediateCommentEnd)) {
+ position = immediateCommentEnd;
+ validCount--; // flush this comment
+ index++;
+ }
+ }
+ }
+ if (index < 0)
+ return position; // no obsolete comment
+
+ if (validCount > 0) {
+ // move valid comment infos, overriding obsolete comment infos
+ System.arraycopy(
+ scanner.commentStarts,
+ index + 1,
+ scanner.commentStarts,
+ 0,
+ validCount);
+ System.arraycopy(
+ scanner.commentStops,
+ index + 1,
+ scanner.commentStops,
+ 0,
+ validCount);
+ }
+ scanner.commentPtr = validCount - 1;
+ return position;
+ }
+
+ public final int getFirstToken() {
+ // the first token is a virtual token that
+ // allows the parser to parse several goals
+ // even if they aren't LALR(1)....
+ // Goal ::= '++' CompilationUnit
+ // Goal ::= '--' MethodBody
+ // Goal ::= '==' ConstructorBody
+ // -- Initializer
+ // Goal ::= '>>' StaticInitializer
+ // Goal ::= '>>' Block
+ // -- error recovery
+ // Goal ::= '>>>' Headers
+ // Goal ::= '*' BlockStatements
+ // Goal ::= '*' MethodPushModifiersHeader
+ // -- JDOM
+ // Goal ::= '&&' FieldDeclaration
+ // Goal ::= '||' ImportDeclaration
+ // Goal ::= '?' PackageDeclaration
+ // Goal ::= '+' TypeDeclaration
+ // Goal ::= '/' GenericMethodDeclaration
+ // Goal ::= '&' ClassBodyDeclaration
+ // -- code snippet
+ // Goal ::= '%' Expression
+ // -- completion parser
+ // Goal ::= '!' ConstructorBlockStatementsopt
+ // Goal ::= '~' BlockStatementsopt
+
+ return firstToken;
+ }
+
+ /*
+ * Answer back an array of sourceStart/sourceEnd positions of the available JavaDoc comments.
+ * The array is a flattened structure: 2*n entries with consecutives start and end positions.
+ *
+ * If no JavaDoc is available, then null is answered instead of an empty array.
+ *
+ * e.g. { 10, 20, 25, 45 } --> javadoc1 from 10 to 20, javadoc2 from 25 to 45
+ */
+ public int[] getJavaDocPositions() {
+
+ int javadocCount = 0;
+ for (int i = 0, max = scanner.commentPtr; i <= max; i++) {
+ // javadoc only (non javadoc comment have negative end positions.)
+ if (scanner.commentStops[i] > 0) {
+ javadocCount++;
+ }
+ }
+ if (javadocCount == 0)
+ return null;
+
+ int[] positions = new int[2 * javadocCount];
+ int index = 0;
+ for (int i = 0, max = scanner.commentPtr; i <= max; i++) {
+ // javadoc only (non javadoc comment have negative end positions.)
+ if (scanner.commentStops[i] > 0) {
+ positions[index++] = scanner.commentStarts[i];
+ positions[index++] = scanner.commentStops[i] - 1; //stop is one over
+ }
+ }
+ return positions;
+ }
+
+ protected TypeReference getTypeReference(int dim) { /* build a Reference on a variable that may be qualified or not
+ This variable is a type reference and dim will be its dimensions*/
+
+ int length;
+ TypeReference ref;
+ if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) {
+ // single variable reference
+ if (dim == 0) {
+ ref =
+ new SingleTypeReference(
+ identifierStack[identifierPtr],
+ identifierPositionStack[identifierPtr--]);
+ } else {
+ ref =
+ new ArrayTypeReference(
+ identifierStack[identifierPtr],
+ dim,
+ identifierPositionStack[identifierPtr--]);
+ }
+ } else {
+ if (length < 0) { //flag for precompiled type reference on base types
+ ref = TypeReference.baseTypeReference(-length, dim);
+ ref.sourceStart = intStack[intPtr--];
+ } else { //Qualified variable reference
+ char[][] tokens = new char[length][];
+ identifierPtr -= length;
+ long[] positions = new long[length];
+ System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length);
+ System.arraycopy(
+ identifierPositionStack,
+ identifierPtr + 1,
+ positions,
+ 0,
+ length);
+ if (dim == 0)
+ ref = new QualifiedTypeReference(tokens, positions);
+ else
+ ref = new ArrayQualifiedTypeReference(tokens, dim, positions);
+ }
+ };
+ return ref;
+ }
+
+ protected Expression getTypeReference(Expression exp) {
+
+ exp.bits &= ~NameReference.RestrictiveFlagMASK;
+ exp.bits |= TYPE;
+ return exp;
+ }
+
+ protected NameReference getUnspecifiedReference() {
+ /* build a (unspecified) NameReference which may be qualified*/
+
+ int length;
+ NameReference ref;
+ if ((length = identifierLengthStack[identifierLengthPtr--]) == 1)
+ // single variable reference
+ ref =
+ new SingleNameReference(
+ identifierStack[identifierPtr],
+ identifierPositionStack[identifierPtr--]);
+ else
+ //Qualified variable reference
+ {
+ char[][] tokens = new char[length][];
+ identifierPtr -= length;
+ System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length);
+ ref =
+ new QualifiedNameReference(
+ tokens,
+ (int) (identifierPositionStack[identifierPtr + 1] >> 32),
+ // sourceStart
+ (int) identifierPositionStack[identifierPtr + length]); // sourceEnd
+ };
+ return ref;
+ }
+
+ protected NameReference getUnspecifiedReferenceOptimized() {
+ /* build a (unspecified) NameReference which may be qualified
+ The optimization occurs for qualified reference while we are
+ certain in this case the last item of the qualified name is
+ a field access. This optimization is IMPORTANT while it results
+ that when a NameReference is build, the type checker should always
+ look for that it is not a type reference */
+
+ int length;
+ NameReference ref;
+ if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) {
+ // single variable reference
+ ref =
+ new SingleNameReference(
+ identifierStack[identifierPtr],
+ identifierPositionStack[identifierPtr--]);
+ ref.bits &= ~NameReference.RestrictiveFlagMASK;
+ ref.bits |= LOCAL | FIELD;
+ return ref;
+ }
+
+ //Qualified-variable-reference
+ //In fact it is variable-reference DOT field-ref , but it would result in a type
+ //conflict tha can be only reduce by making a superclass (or inetrface ) between
+ //nameReference and FiledReference or putting FieldReference under NameReference
+ //or else..........This optimisation is not really relevant so just leave as it is
+
+ char[][] tokens = new char[length][];
+ identifierPtr -= length;
+ System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length);
+ ref =
+ new QualifiedNameReference(
+ tokens,
+ (int) (identifierPositionStack[identifierPtr + 1] >> 32),
+ // sourceStart
+ (int) identifierPositionStack[identifierPtr + length]); // sourceEnd
+ ref.bits &= ~NameReference.RestrictiveFlagMASK;
+ ref.bits |= LOCAL | FIELD;
+ return ref;
+ }
+
+ public void goForBlockStatementsOrMethodHeaders() {
+ //tells the scanner to go for block statements or method headers parsing
+
+ firstToken = TokenNameMULTIPLY;
+ scanner.recordLineSeparator = false;
+ }
+
+ public void goForClassBodyDeclarations() {
+ //tells the scanner to go for any body declarations parsing
+
+ firstToken = TokenNameAND;
+ scanner.recordLineSeparator = true;
+ }
+
+ public void goForCompilationUnit() {
+ //tells the scanner to go for compilation unit parsing
+
+ firstToken = TokenNamePLUS_PLUS;
+ scanner.linePtr = -1;
+ scanner.recordLineSeparator = true;
+ }
+
+ public void goForConstructorBody() {
+ //tells the scanner to go for compilation unit parsing
+
+ firstToken = TokenNameEQUAL_EQUAL;
+ scanner.recordLineSeparator = false;
+ }
+
+ public void goForExpression() {
+ //tells the scanner to go for an expression parsing
+
+ firstToken = TokenNameREMAINDER;
+ scanner.recordLineSeparator = false;
+ }
+
+ public void goForFieldDeclaration() {
+ //tells the scanner to go for field declaration parsing
+
+ firstToken = TokenNameAND_AND;
+ scanner.recordLineSeparator = true;
+ }
+
+ public void goForGenericMethodDeclaration() {
+ //tells the scanner to go for generic method declarations parsing
+
+ firstToken = TokenNameDIVIDE;
+ scanner.recordLineSeparator = true;
+ }
+
+ public void goForHeaders() {
+ //tells the scanner to go for headers only parsing
+
+ firstToken = TokenNameUNSIGNED_RIGHT_SHIFT;
+ scanner.recordLineSeparator = true;
+ }
+
+ public void goForImportDeclaration() {
+ //tells the scanner to go for import declaration parsing
+
+ firstToken = TokenNameOR_OR;
+ scanner.recordLineSeparator = true;
+ }
+
+ public void goForInitializer() {
+ //tells the scanner to go for initializer parsing
+
+ firstToken = TokenNameRIGHT_SHIFT;
+ scanner.recordLineSeparator = false;
+ }
+
+ public void goForMethodBody() {
+ //tells the scanner to go for method body parsing
+
+ firstToken = TokenNameMINUS_MINUS;
+ scanner.recordLineSeparator = false;
+ }
+
+ public void goForPackageDeclaration() {
+ //tells the scanner to go for package declaration parsing
+
+ firstToken = TokenNameQUESTION;
+ scanner.recordLineSeparator = true;
+ }
+
+ public void goForTypeDeclaration() {
+ //tells the scanner to go for type (interface or class) declaration parsing
+
+ firstToken = TokenNamePLUS;
+ scanner.recordLineSeparator = true;
+ }
+
+ public final static void grammar() {
+ /*
+ --main options
+ %options ACTION, AN=JavaAction.java, GP=java,
+ %options FILE-PREFIX=java, ESCAPE=$, PREFIX=TokenName, OUTPUT-SIZE=125 ,
+ %options NOGOTO-DEFAULT, SINGLE-PRODUCTIONS, LALR=1 , TABLE=TIME ,
+
+ --error recovering options.....
+ %options ERROR_MAPS
+
+ --grammar understanding options
+ %options first follow
+ %options TRACE=FULL ,
+ %options VERBOSE
+
+ --Usefull macros helping reading/writing semantic actions
+ $Define
+ $putCase
+ /. case $rule_number : // System.out.println("$rule_text");
+ ./
+
+ $break
+ /.
+ break ;
+ ./
+
+ -- here it starts really ------------------------------------------
+ $Terminals
+
+ Identifier
+
+ abstract boolean break byte case catch char class
+ continue default do double else extends false final finally float
+ for if implements import instanceof int
+ interface long native new null package private
+ protected public return short static strictfp super switch
+ synchronized this throw throws transient true try void
+ volatile while
+
+ IntegerLiteral
+ LongLiteral
+ FloatingPointLiteral
+ DoubleLiteral
+ CharacterLiteral
+ StringLiteral
+
+ PLUS_PLUS
+ MINUS_MINUS
+ EQUAL_EQUAL
+ LESS_EQUAL
+ GREATER_EQUAL
+ NOT_EQUAL
+ LEFT_SHIFT
+ RIGHT_SHIFT
+ UNSIGNED_RIGHT_SHIFT
+ PLUS_EQUAL
+ MINUS_EQUAL
+ MULTIPLY_EQUAL
+ DIVIDE_EQUAL
+ AND_EQUAL
+ OR_EQUAL
+ XOR_EQUAL
+ REMAINDER_EQUAL
+ LEFT_SHIFT_EQUAL
+ RIGHT_SHIFT_EQUAL
+ UNSIGNED_RIGHT_SHIFT_EQUAL
+ OR_OR
+ AND_AND
+ PLUS
+ MINUS
+ NOT
+ REMAINDER
+ XOR
+ AND
+ MULTIPLY
+ OR
+ TWIDDLE
+ DIVIDE
+ GREATER
+ LESS
+ LPAREN
+ RPAREN
+ LBRACE
+ RBRACE
+ LBRACKET
+ RBRACKET
+ SEMICOLON
+ QUESTION
+ COLON
+ COMMA
+ DOT
+ EQUAL
+
+ -- BodyMarker
+
+ $Alias
+
+ '++' ::= PLUS_PLUS
+ '--' ::= MINUS_MINUS
+ '==' ::= EQUAL_EQUAL
+ '<=' ::= LESS_EQUAL
+ '>=' ::= GREATER_EQUAL
+ '!=' ::= NOT_EQUAL
+ '<<' ::= LEFT_SHIFT
+ '>>' ::= RIGHT_SHIFT
+ '>>>' ::= UNSIGNED_RIGHT_SHIFT
+ '+=' ::= PLUS_EQUAL
+ '-=' ::= MINUS_EQUAL
+ '*=' ::= MULTIPLY_EQUAL
+ '/=' ::= DIVIDE_EQUAL
+ '&=' ::= AND_EQUAL
+ '|=' ::= OR_EQUAL
+ '^=' ::= XOR_EQUAL
+ '%=' ::= REMAINDER_EQUAL
+ '<<=' ::= LEFT_SHIFT_EQUAL
+ '>>=' ::= RIGHT_SHIFT_EQUAL
+ '>>>=' ::= UNSIGNED_RIGHT_SHIFT_EQUAL
+ '||' ::= OR_OR
+ '&&' ::= AND_AND
+
+ '+' ::= PLUS
+ '-' ::= MINUS
+ '!' ::= NOT
+ '%' ::= REMAINDER
+ '^' ::= XOR
+ '&' ::= AND
+ '*' ::= MULTIPLY
+ '|' ::= OR
+ '~' ::= TWIDDLE
+ '/' ::= DIVIDE
+ '>' ::= GREATER
+ '<' ::= LESS
+ '(' ::= LPAREN
+ ')' ::= RPAREN
+ '{' ::= LBRACE
+ '}' ::= RBRACE
+ '[' ::= LBRACKET
+ ']' ::= RBRACKET
+ ';' ::= SEMICOLON
+ '?' ::= QUESTION
+ ':' ::= COLON
+ ',' ::= COMMA
+ '.' ::= DOT
+ '=' ::= EQUAL
+
+ $Start
+ Goal
+
+ $Rules
+
+ /. // This method is part of an automatic generation : do NOT edit-modify
+ protected void consumeRule(int act) {
+ switch ( act ) {
+ ./
+
+
+
+ Goal ::= '++' CompilationUnit
+ Goal ::= '--' MethodBody
+ Goal ::= '==' ConstructorBody
+ -- Initializer
+ Goal ::= '>>' StaticInitializer
+ Goal ::= '>>' ClassBodyDeclaration
+ -- error recovery
+ Goal ::= '>>>' Headers
+ Goal ::= '*' BlockStatements
+ Goal ::= '*' MethodPushModifiersHeader
+ Goal ::= '*' CatchHeader
+ -- JDOM
+ Goal ::= '&&' FieldDeclaration
+ Goal ::= '||' ImportDeclaration
+ Goal ::= '?' PackageDeclaration
+ Goal ::= '+' TypeDeclaration
+ Goal ::= '/' GenericMethodDeclaration
+ Goal ::= '&' ClassBodyDeclaration
+ -- code snippet
+ Goal ::= '%' Expression
+ -- completion parser
+ Goal ::= '!' ConstructorBlockStatementsopt
+ Goal ::= '~' BlockStatementsopt
+
+ Literal -> IntegerLiteral
+ Literal -> LongLiteral
+ Literal -> FloatingPointLiteral
+ Literal -> DoubleLiteral
+ Literal -> CharacterLiteral
+ Literal -> StringLiteral
+ Literal -> null
+ Literal -> BooleanLiteral
+ BooleanLiteral -> true
+ BooleanLiteral -> false
+
+ -------------------------------------------------------------
+ -------------------------------------------------------------
+ --a Type results in both a push of its dimension(s) and its name(s).
+
+ Type ::= PrimitiveType
+ /.$putCase consumePrimitiveType(); $break ./
+ Type -> ReferenceType
+
+ PrimitiveType -> NumericType
+ NumericType -> IntegralType
+ NumericType -> FloatingPointType
+
+ PrimitiveType -> 'boolean'
+ PrimitiveType -> 'void'
+ IntegralType -> 'byte'
+ IntegralType -> 'short'
+ IntegralType -> 'int'
+ IntegralType -> 'long'
+ IntegralType -> 'char'
+ FloatingPointType -> 'float'
+ FloatingPointType -> 'double'
+
+ ReferenceType ::= ClassOrInterfaceType
+ /.$putCase consumeReferenceType(); $break ./
+ ReferenceType -> ArrayType -- here a push of dimensions is done, that explains the two previous push 0
+
+ ClassOrInterfaceType -> Name
+
+ --
+ -- These rules have been rewritten to avoid some conflicts introduced
+ -- by adding the 1.1 features
+ --
+ -- ArrayType ::= PrimitiveType '[' ']'
+ -- ArrayType ::= Name '[' ']'
+ -- ArrayType ::= ArrayType '[' ']'
+ --
+
+ ArrayType ::= PrimitiveType Dims
+ ArrayType ::= Name Dims
+
+ ClassType -> ClassOrInterfaceType
+
+
+ --------------------------------------------------------------
+ --------------------------------------------------------------
+
+ Name -> SimpleName
+ Name -> QualifiedName
+
+ SimpleName -> 'Identifier'
+
+ QualifiedName ::= Name '.' SimpleName
+ /.$putCase consumeQualifiedName(); $break ./
+
+ CompilationUnit ::= EnterCompilationUnit PackageDeclarationopt ImportDeclarationsopt TypeDeclarationsopt
+ /.$putCase consumeCompilationUnit(); $break ./
+
+ EnterCompilationUnit ::= $empty
+ /.$putCase consumeEnterCompilationUnit(); $break ./
+
+ Headers -> Header
+ Headers ::= Headers Header
+
+ Header -> ImportDeclaration
+ Header -> PackageDeclaration
+ Header -> ClassHeader
+ Header -> InterfaceHeader
+ Header -> StaticInitializer
+ Header -> MethodHeader
+ Header -> ConstructorHeader
+ Header -> FieldDeclaration
+ Header -> AllocationHeader
+
+ CatchHeader ::= 'catch' '(' FormalParameter ')' '{'
+ /.$putCase consumeCatchHeader(); $break ./
+
+ ImportDeclarations -> ImportDeclaration
+ ImportDeclarations ::= ImportDeclarations ImportDeclaration
+ /.$putCase consumeImportDeclarations(); $break ./
+
+ TypeDeclarations -> TypeDeclaration
+ TypeDeclarations ::= TypeDeclarations TypeDeclaration
+ /.$putCase consumeTypeDeclarations(); $break ./
+
+ PackageDeclaration ::= PackageDeclarationName ';'
+ /.$putCase consumePackageDeclaration(); $break ./
+
+ PackageDeclarationName ::= 'package' Name
+ /.$putCase consumePackageDeclarationName(); $break ./
+
+ ImportDeclaration -> SingleTypeImportDeclaration
+ ImportDeclaration -> TypeImportOnDemandDeclaration
+
+ SingleTypeImportDeclaration ::= SingleTypeImportDeclarationName ';'
+ /.$putCase consumeSingleTypeImportDeclaration(); $break ./
+
+ SingleTypeImportDeclarationName ::= 'import' Name
+ /.$putCase consumeSingleTypeImportDeclarationName(); $break ./
+
+ TypeImportOnDemandDeclaration ::= TypeImportOnDemandDeclarationName ';'
+ /.$putCase consumeTypeImportOnDemandDeclaration(); $break ./
+
+ TypeImportOnDemandDeclarationName ::= 'import' Name '.' '*'
+ /.$putCase consumeTypeImportOnDemandDeclarationName(); $break ./
+
+ TypeDeclaration -> ClassDeclaration
+ TypeDeclaration -> InterfaceDeclaration
+ -- this declaration in part of a list od declaration and we will
+ -- use and optimized list length calculation process
+ -- thus we decrement the number while it will be incremend.....
+ TypeDeclaration ::= ';'
+ /. $putCase consumeEmptyTypeDeclaration(); $break ./
+
+ --18.7 Only in the LALR(1) Grammar
+
+ Modifiers ::= Modifier
+ Modifiers ::= Modifiers Modifier
+
+ Modifier -> 'public'
+ Modifier -> 'protected'
+ Modifier -> 'private'
+ Modifier -> 'static'
+ Modifier -> 'abstract'
+ Modifier -> 'final'
+ Modifier -> 'native'
+ Modifier -> 'synchronized'
+ Modifier -> 'transient'
+ Modifier -> 'volatile'
+ Modifier -> 'strictfp'
+
+ --18.8 Productions from 8: Class Declarations
+ --ClassModifier ::=
+ -- 'abstract'
+ -- | 'final'
+ -- | 'public'
+ --18.8.1 Productions from 8.1: Class Declarations
+
+ ClassDeclaration ::= ClassHeader ClassBody
+ /.$putCase consumeClassDeclaration(); $break ./
+
+ ClassHeader ::= ClassHeaderName ClassHeaderExtendsopt ClassHeaderImplementsopt
+ /.$putCase consumeClassHeader(); $break ./
+
+ ClassHeaderName ::= Modifiersopt 'class' 'Identifier'
+ /.$putCase consumeClassHeaderName(); $break ./
+
+ ClassHeaderExtends ::= 'extends' ClassType
+ /.$putCase consumeClassHeaderExtends(); $break ./
+
+ ClassHeaderImplements ::= 'implements' InterfaceTypeList
+ /.$putCase consumeClassHeaderImplements(); $break ./
+
+ InterfaceTypeList -> InterfaceType
+ InterfaceTypeList ::= InterfaceTypeList ',' InterfaceType
+ /.$putCase consumeInterfaceTypeList(); $break ./
+
+ InterfaceType ::= ClassOrInterfaceType
+ /.$putCase consumeInterfaceType(); $break ./
+
+ ClassBody ::= '{' ClassBodyDeclarationsopt '}'
+
+ ClassBodyDeclarations ::= ClassBodyDeclaration
+ ClassBodyDeclarations ::= ClassBodyDeclarations ClassBodyDeclaration
+ /.$putCase consumeClassBodyDeclarations(); $break ./
+
+ ClassBodyDeclaration -> ClassMemberDeclaration
+ ClassBodyDeclaration -> StaticInitializer
+ ClassBodyDeclaration -> ConstructorDeclaration
+ --1.1 feature
+ ClassBodyDeclaration ::= Diet NestedMethod Block
+ /.$putCase consumeClassBodyDeclaration(); $break ./
+ Diet ::= $empty
+ /.$putCase consumeDiet(); $break./
+
+ ClassMemberDeclaration -> FieldDeclaration
+ ClassMemberDeclaration -> MethodDeclaration
+ --1.1 feature
+ ClassMemberDeclaration -> ClassDeclaration
+ --1.1 feature
+ ClassMemberDeclaration -> InterfaceDeclaration
+
+ -- Empty declarations are not valid Java ClassMemberDeclarations.
+ -- However, since the current (2/14/97) Java compiler accepts them
+ -- (in fact, some of the official tests contain this erroneous
+ -- syntax)
+
+ GenericMethodDeclaration -> MethodDeclaration
+ GenericMethodDeclaration -> ConstructorDeclaration
+
+ ClassMemberDeclaration ::= ';'
+ /.$putCase consumeEmptyClassMemberDeclaration(); $break./
+
+ --18.8.2 Productions from 8.3: Field Declarations
+ --VariableModifier ::=
+ -- 'public'
+ -- | 'protected'
+ -- | 'private'
+ -- | 'static'
+ -- | 'final'
+ -- | 'transient'
+ -- | 'volatile'
+
+ FieldDeclaration ::= Modifiersopt Type VariableDeclarators ';'
+ /.$putCase consumeFieldDeclaration(); $break ./
+
+ VariableDeclarators -> VariableDeclarator
+ VariableDeclarators ::= VariableDeclarators ',' VariableDeclarator
+ /.$putCase consumeVariableDeclarators(); $break ./
+
+ VariableDeclarator ::= VariableDeclaratorId EnterVariable ExitVariableWithoutInitialization
+
+ VariableDeclarator ::= VariableDeclaratorId EnterVariable '=' ForceNoDiet VariableInitializer RestoreDiet ExitVariableWithInitialization
+
+ EnterVariable ::= $empty
+ /.$putCase consumeEnterVariable(); $break ./
+
+ ExitVariableWithInitialization ::= $empty
+ /.$putCase consumeExitVariableWithInitialization(); $break ./
+
+ ExitVariableWithoutInitialization ::= $empty
+ /.$putCase consumeExitVariableWithoutInitialization(); $break ./
+
+ ForceNoDiet ::= $empty
+ /.$putCase consumeForceNoDiet(); $break ./
+ RestoreDiet ::= $empty
+ /.$putCase consumeRestoreDiet(); $break ./
+
+ VariableDeclaratorId ::= 'Identifier' Dimsopt
+
+ VariableInitializer -> Expression
+ VariableInitializer -> ArrayInitializer
+
+ --18.8.3 Productions from 8.4: Method Declarations
+ --MethodModifier ::=
+ -- 'public'
+ -- | 'protected'
+ -- | 'private'
+ -- | 'static'
+ -- | 'abstract'
+ -- | 'final'
+ -- | 'native'
+ -- | 'synchronized'
+ --
+
+ MethodDeclaration -> AbstractMethodDeclaration
+ MethodDeclaration ::= MethodHeader MethodBody
+ /.$putCase // set to true to consume a method with a body
+ consumeMethodDeclaration(true); $break ./
+
+ AbstractMethodDeclaration ::= MethodHeader ';'
+ /.$putCase // set to false to consume a method without body
+ consumeMethodDeclaration(false); $break ./
+
+ MethodHeader ::= MethodHeaderName MethodHeaderParameters MethodHeaderExtendedDims MethodHeaderThrowsClauseopt
+ /.$putCase consumeMethodHeader(); $break ./
+
+ MethodPushModifiersHeader ::= MethodPushModifiersHeaderName MethodHeaderParameters MethodHeaderExtendedDims MethodHeaderThrowsClauseopt
+ /.$putCase consumeMethodHeader(); $break ./
+
+ MethodPushModifiersHeaderName ::= Modifiers Type PushModifiers 'Identifier' '('
+ /.$putCase consumeMethodPushModifiersHeaderName(); $break ./
+
+ MethodPushModifiersHeaderName ::= Type PushModifiers 'Identifier' '('
+ /.$putCase consumeMethodPushModifiersHeaderName(); $break ./
+
+ MethodHeaderName ::= Modifiersopt Type 'Identifier' '('
+ /.$putCase consumeMethodHeaderName(); $break ./
+
+ MethodHeaderParameters ::= FormalParameterListopt ')'
+ /.$putCase consumeMethodHeaderParameters(); $break ./
+
+ MethodHeaderExtendedDims ::= Dimsopt
+ /.$putCase consumeMethodHeaderExtendedDims(); $break ./
+
+ MethodHeaderThrowsClause ::= 'throws' ClassTypeList
+ /.$putCase consumeMethodHeaderThrowsClause(); $break ./
+
+ ConstructorHeader ::= ConstructorHeaderName MethodHeaderParameters MethodHeaderThrowsClauseopt
+ /.$putCase consumeConstructorHeader(); $break ./
+
+ ConstructorHeaderName ::= Modifiersopt 'Identifier' '('
+ /.$putCase consumeConstructorHeaderName(); $break ./
+
+ FormalParameterList -> FormalParameter
+ FormalParameterList ::= FormalParameterList ',' FormalParameter
+ /.$putCase consumeFormalParameterList(); $break ./
+
+ --1.1 feature
+ FormalParameter ::= Modifiersopt Type VariableDeclaratorId
+ /.$putCase // the boolean is used to know if the modifiers should be reset
+ consumeFormalParameter(); $break ./
+
+ ClassTypeList -> ClassTypeElt
+ ClassTypeList ::= ClassTypeList ',' ClassTypeElt
+ /.$putCase consumeClassTypeList(); $break ./
+
+ ClassTypeElt ::= ClassType
+ /.$putCase consumeClassTypeElt(); $break ./
+
+
+ MethodBody ::= NestedMethod '{' BlockStatementsopt '}'
+ /.$putCase consumeMethodBody(); $break ./
+
+ NestedMethod ::= $empty
+ /.$putCase consumeNestedMethod(); $break ./
+
+ --18.8.4 Productions from 8.5: Static Initializers
+
+ StaticInitializer ::= StaticOnly Block
+ /.$putCase consumeStaticInitializer(); $break./
+
+ StaticOnly ::= 'static'
+ /.$putCase consumeStaticOnly(); $break ./
+
+ --18.8.5 Productions from 8.6: Constructor Declarations
+ --ConstructorModifier ::=
+ -- 'public'
+ -- | 'protected'
+ -- | 'private'
+ --
+ --
+ ConstructorDeclaration ::= ConstructorHeader ConstructorBody
+ /.$putCase consumeConstructorDeclaration() ; $break ./
+
+ -- the rules ExplicitConstructorInvocationopt has been expanded
+ -- in the rule below in order to make the grammar lalr(1).
+ -- ConstructorBody ::= '{' ExplicitConstructorInvocationopt BlockStatementsopt '}'
+ -- Other inlining has occured into the next rule too....
+
+ ConstructorBody ::= NestedMethod '{' ConstructorBlockStatementsopt '}'
+ /.$putCase consumeConstructorBody(); $break ./
+
+ ConstructorBlockStatementsopt -> BlockStatementsopt
+
+ ConstructorBlockStatementsopt -> ExplicitConstructorInvocation
+
+ ConstructorBlockStatementsopt ::= ExplicitConstructorInvocation BlockStatements
+ /.$putCase consumeConstructorBlockStatements(); $break ./
+
+ ExplicitConstructorInvocation ::= 'this' '(' ArgumentListopt ')' ';'
+ /.$putCase consumeExplicitConstructorInvocation(0,ExplicitConstructorCall.This); $break ./
+
+ ExplicitConstructorInvocation ::= 'super' '(' ArgumentListopt ')' ';'
+ /.$putCase consumeExplicitConstructorInvocation(0,ExplicitConstructorCall.Super); $break ./
+
+ --1.1 feature
+ ExplicitConstructorInvocation ::= Primary '.' 'super' '(' ArgumentListopt ')' ';'
+ /.$putCase consumeExplicitConstructorInvocation(1, ExplicitConstructorCall.Super); $break ./
+
+ --1.1 feature
+ ExplicitConstructorInvocation ::= Name '.' 'super' '(' ArgumentListopt ')' ';'
+ /.$putCase consumeExplicitConstructorInvocation(2, ExplicitConstructorCall.Super); $break ./
+
+ --1.1 feature
+ ExplicitConstructorInvocation ::= Primary '.' 'this' '(' ArgumentListopt ')' ';'
+ /.$putCase consumeExplicitConstructorInvocation(1, ExplicitConstructorCall.This); $break ./
+
+ --1.1 feature
+ ExplicitConstructorInvocation ::= Name '.' 'this' '(' ArgumentListopt ')' ';'
+ /.$putCase consumeExplicitConstructorInvocation(2, ExplicitConstructorCall.This); $break ./
+
+ --18.9 Productions from 9: Interface Declarations
+
+ --18.9.1 Productions from 9.1: Interface Declarations
+ --InterfaceModifier ::=
+ -- 'public'
+ -- | 'abstract'
+ --
+ InterfaceDeclaration ::= InterfaceHeader InterfaceBody
+ /.$putCase consumeInterfaceDeclaration(); $break ./
+
+ InterfaceHeader ::= InterfaceHeaderName InterfaceHeaderExtendsopt
+ /.$putCase consumeInterfaceHeader(); $break ./
+
+ InterfaceHeaderName ::= Modifiersopt 'interface' 'Identifier'
+ /.$putCase consumeInterfaceHeaderName(); $break ./
+
+ -- This rule will be used to accept inner local interface and then report a relevant error message
+ InvalidInterfaceDeclaration -> InterfaceHeader InterfaceBody
+
+ InterfaceHeaderExtends ::= 'extends' InterfaceTypeList
+ /.$putCase consumeInterfaceHeaderExtends(); $break ./
+
+ InterfaceBody ::= '{' InterfaceMemberDeclarationsopt '}'
+
+ InterfaceMemberDeclarations -> InterfaceMemberDeclaration
+ InterfaceMemberDeclarations ::= InterfaceMemberDeclarations InterfaceMemberDeclaration
+ /.$putCase consumeInterfaceMemberDeclarations(); $break ./
+
+ --same as for class members
+ InterfaceMemberDeclaration ::= ';'
+ /.$putCase consumeEmptyInterfaceMemberDeclaration(); $break ./
+
+ -- This rule is added to be able to parse non abstract method inside interface and then report a relevent error message
+ InvalidMethodDeclaration -> MethodHeader MethodBody
+
+ InterfaceMemberDeclaration -> ConstantDeclaration
+ InterfaceMemberDeclaration ::= InvalidMethodDeclaration
+ /.$putCase ignoreMethodBody(); $break ./
+
+ -- These rules are added to be able to parse constructors inside interface and then report a relevent error message
+ InvalidConstructorDeclaration ::= ConstructorHeader ConstructorBody
+ /.$putCase ignoreInvalidConstructorDeclaration(true); $break ./
+
+ InvalidConstructorDeclaration ::= ConstructorHeader ';'
+ /.$putCase ignoreInvalidConstructorDeclaration(false); $break ./
+
+ InterfaceMemberDeclaration -> AbstractMethodDeclaration
+ InterfaceMemberDeclaration -> InvalidConstructorDeclaration
+
+ --1.1 feature
+ InterfaceMemberDeclaration -> ClassDeclaration
+ --1.1 feature
+ InterfaceMemberDeclaration -> InterfaceDeclaration
+
+ ConstantDeclaration -> FieldDeclaration
+
+ ArrayInitializer ::= '{' ,opt '}'
+ /.$putCase consumeEmptyArrayInitializer(); $break ./
+ ArrayInitializer ::= '{' VariableInitializers '}'
+ /.$putCase consumeArrayInitializer(); $break ./
+ ArrayInitializer ::= '{' VariableInitializers , '}'
+ /.$putCase consumeArrayInitializer(); $break ./
+
+ VariableInitializers ::= VariableInitializer
+ VariableInitializers ::= VariableInitializers ',' VariableInitializer
+ /.$putCase consumeVariableInitializers(); $break ./
+
+ Block ::= OpenBlock '{' BlockStatementsopt '}'
+ /.$putCase consumeBlock(); $break ./
+ OpenBlock ::= $empty
+ /.$putCase consumeOpenBlock() ; $break ./
+
+ BlockStatements -> BlockStatement
+ BlockStatements ::= BlockStatements BlockStatement
+ /.$putCase consumeBlockStatements() ; $break ./
+
+ BlockStatement -> LocalVariableDeclarationStatement
+ BlockStatement -> Statement
+ --1.1 feature
+ BlockStatement -> ClassDeclaration
+ BlockStatement ::= InvalidInterfaceDeclaration
+ /.$putCase ignoreInterfaceDeclaration(); $break ./
+
+ LocalVariableDeclarationStatement ::= LocalVariableDeclaration ';'
+ /.$putCase consumeLocalVariableDeclarationStatement(); $break ./
+
+ LocalVariableDeclaration ::= Type PushModifiers VariableDeclarators
+ /.$putCase consumeLocalVariableDeclaration(); $break ./
+
+ -- 1.1 feature
+ -- The modifiers part of this rule makes the grammar more permissive.
+ -- The only modifier here is final. We put Modifiers to allow multiple modifiers
+ -- This will require to check the validity of the modifier
+
+ LocalVariableDeclaration ::= Modifiers Type PushModifiers VariableDeclarators
+ /.$putCase consumeLocalVariableDeclaration(); $break ./
+
+ PushModifiers ::= $empty
+ /.$putCase consumePushModifiers(); $break ./
+
+ Statement -> StatementWithoutTrailingSubstatement
+ Statement -> LabeledStatement
+ Statement -> IfThenStatement
+ Statement -> IfThenElseStatement
+ Statement -> WhileStatement
+ Statement -> ForStatement
+
+ StatementNoShortIf -> StatementWithoutTrailingSubstatement
+ StatementNoShortIf -> LabeledStatementNoShortIf
+ StatementNoShortIf -> IfThenElseStatementNoShortIf
+ StatementNoShortIf -> WhileStatementNoShortIf
+ StatementNoShortIf -> ForStatementNoShortIf
+
+ StatementWithoutTrailingSubstatement -> Block
+ StatementWithoutTrailingSubstatement -> EmptyStatement
+ StatementWithoutTrailingSubstatement -> ExpressionStatement
+ StatementWithoutTrailingSubstatement -> SwitchStatement
+ StatementWithoutTrailingSubstatement -> DoStatement
+ StatementWithoutTrailingSubstatement -> BreakStatement
+ StatementWithoutTrailingSubstatement -> ContinueStatement
+ StatementWithoutTrailingSubstatement -> ReturnStatement
+ StatementWithoutTrailingSubstatement -> SynchronizedStatement
+ StatementWithoutTrailingSubstatement -> ThrowStatement
+ StatementWithoutTrailingSubstatement -> TryStatement
+
+ EmptyStatement ::= ';'
+ /.$putCase consumeEmptyStatement(); $break ./
+
+ LabeledStatement ::= 'Identifier' ':' Statement
+ /.$putCase consumeStatementLabel() ; $break ./
+
+ LabeledStatementNoShortIf ::= 'Identifier' ':' StatementNoShortIf
+ /.$putCase consumeStatementLabel() ; $break ./
+
+ ExpressionStatement ::= StatementExpression ';'
+ /. $putCase consumeExpressionStatement(); $break ./
+
+ StatementExpression ::= Assignment
+ StatementExpression ::= PreIncrementExpression
+ StatementExpression ::= PreDecrementExpression
+ StatementExpression ::= PostIncrementExpression
+ StatementExpression ::= PostDecrementExpression
+ StatementExpression ::= MethodInvocation
+ StatementExpression ::= ClassInstanceCreationExpression
+
+ IfThenStatement ::= 'if' '(' Expression ')' Statement
+ /.$putCase consumeStatementIfNoElse(); $break ./
+
+ IfThenElseStatement ::= 'if' '(' Expression ')' StatementNoShortIf 'else' Statement
+ /.$putCase consumeStatementIfWithElse(); $break ./
+
+ IfThenElseStatementNoShortIf ::= 'if' '(' Expression ')' StatementNoShortIf 'else' StatementNoShortIf
+ /.$putCase consumeStatementIfWithElse(); $break ./
+
+ SwitchStatement ::= 'switch' OpenBlock '(' Expression ')' SwitchBlock
+ /.$putCase consumeStatementSwitch() ; $break ./
+
+ SwitchBlock ::= '{' '}'
+ /.$putCase consumeEmptySwitchBlock() ; $break ./
+
+ SwitchBlock ::= '{' SwitchBlockStatements '}'
+ SwitchBlock ::= '{' SwitchLabels '}'
+ SwitchBlock ::= '{' SwitchBlockStatements SwitchLabels '}'
+ /.$putCase consumeSwitchBlock() ; $break ./
+
+ SwitchBlockStatements -> SwitchBlockStatement
+ SwitchBlockStatements ::= SwitchBlockStatements SwitchBlockStatement
+ /.$putCase consumeSwitchBlockStatements() ; $break ./
+
+ SwitchBlockStatement ::= SwitchLabels BlockStatements
+ /.$putCase consumeSwitchBlockStatement() ; $break ./
+
+ SwitchLabels -> SwitchLabel
+ SwitchLabels ::= SwitchLabels SwitchLabel
+ /.$putCase consumeSwitchLabels() ; $break ./
+
+ SwitchLabel ::= 'case' ConstantExpression ':'
+ /. $putCase consumeCaseLabel(); $break ./
+
+ SwitchLabel ::= 'default' ':'
+ /. $putCase consumeDefaultLabel(); $break ./
+
+ WhileStatement ::= 'while' '(' Expression ')' Statement
+ /.$putCase consumeStatementWhile() ; $break ./
+
+ WhileStatementNoShortIf ::= 'while' '(' Expression ')' StatementNoShortIf
+ /.$putCase consumeStatementWhile() ; $break ./
+
+ DoStatement ::= 'do' Statement 'while' '(' Expression ')' ';'
+ /.$putCase consumeStatementDo() ; $break ./
+
+ ForStatement ::= 'for' '(' ForInitopt ';' Expressionopt ';' ForUpdateopt ')' Statement
+ /.$putCase consumeStatementFor() ; $break ./
+ ForStatementNoShortIf ::= 'for' '(' ForInitopt ';' Expressionopt ';' ForUpdateopt ')' StatementNoShortIf
+ /.$putCase consumeStatementFor() ; $break ./
+
+ --the minus one allows to avoid a stack-to-stack transfer
+ ForInit ::= StatementExpressionList
+ /.$putCase consumeForInit() ; $break ./
+ ForInit -> LocalVariableDeclaration
+
+ ForUpdate -> StatementExpressionList
+
+ StatementExpressionList -> StatementExpression
+ StatementExpressionList ::= StatementExpressionList ',' StatementExpression
+ /.$putCase consumeStatementExpressionList() ; $break ./
+
+ BreakStatement ::= 'break' ';'
+ /.$putCase consumeStatementBreak() ; $break ./
+
+ BreakStatement ::= 'break' Identifier ';'
+ /.$putCase consumeStatementBreakWithLabel() ; $break ./
+
+ ContinueStatement ::= 'continue' ';'
+ /.$putCase consumeStatementContinue() ; $break ./
+
+ ContinueStatement ::= 'continue' Identifier ';'
+ /.$putCase consumeStatementContinueWithLabel() ; $break ./
+
+ ReturnStatement ::= 'return' Expressionopt ';'
+ /.$putCase consumeStatementReturn() ; $break ./
+
+ ThrowStatement ::= 'throw' Expression ';'
+ /.$putCase consumeStatementThrow();
+ $break ./
+
+ SynchronizedStatement ::= OnlySynchronized '(' Expression ')' Block
+ /.$putCase consumeStatementSynchronized(); $break ./
+ OnlySynchronized ::= 'synchronized'
+ /.$putCase consumeOnlySynchronized(); $break ./
+
+
+ TryStatement ::= 'try' Block Catches
+ /.$putCase consumeStatementTry(false); $break ./
+ TryStatement ::= 'try' Block Catchesopt Finally
+ /.$putCase consumeStatementTry(true); $break ./
+
+ Catches -> CatchClause
+ Catches ::= Catches CatchClause
+ /.$putCase consumeCatches(); $break ./
+
+ CatchClause ::= 'catch' '(' FormalParameter ')' Block
+ /.$putCase consumeStatementCatch() ; $break ./
+
+ Finally ::= 'finally' Block
+
+ --18.12 Productions from 14: Expressions
+
+ --for source positionning purpose
+ PushLPAREN ::= '('
+ /.$putCase consumeLeftParen(); $break ./
+ PushRPAREN ::= ')'
+ /.$putCase consumeRightParen(); $break ./
+
+ Primary -> PrimaryNoNewArray
+ Primary -> ArrayCreationExpression
+
+ PrimaryNoNewArray -> Literal
+ PrimaryNoNewArray ::= 'this'
+ /.$putCase consumePrimaryNoNewArrayThis(); $break ./
+
+ PrimaryNoNewArray ::= PushLPAREN Expression PushRPAREN
+ /.$putCase consumePrimaryNoNewArray(); $break ./
+
+ PrimaryNoNewArray -> ClassInstanceCreationExpression
+ PrimaryNoNewArray -> FieldAccess
+ --1.1 feature
+ PrimaryNoNewArray ::= Name '.' 'this'
+ /.$putCase consumePrimaryNoNewArrayNameThis(); $break ./
+ PrimaryNoNewArray ::= Name '.' 'super'
+ /.$putCase consumePrimaryNoNewArrayNameSuper(); $break ./
+
+ --1.1 feature
+ --PrimaryNoNewArray ::= Type '.' 'class'
+ --inline Type in the previous rule in order to make the grammar LL1 instead
+ -- of LL2. The result is the 3 next rules.
+ PrimaryNoNewArray ::= Name '.' 'class'
+ /.$putCase consumePrimaryNoNewArrayName(); $break ./
+
+ PrimaryNoNewArray ::= ArrayType '.' 'class'
+ /.$putCase consumePrimaryNoNewArrayArrayType(); $break ./
+
+ PrimaryNoNewArray ::= PrimitiveType '.' 'class'
+ /.$putCase consumePrimaryNoNewArrayPrimitiveType(); $break ./
+
+ PrimaryNoNewArray -> MethodInvocation
+ PrimaryNoNewArray -> ArrayAccess
+
+ --1.1 feature
+ --
+ -- In Java 1.0 a ClassBody could not appear at all in a
+ -- ClassInstanceCreationExpression.
+ --
+
+ AllocationHeader ::= 'new' ClassType '(' ArgumentListopt ')'
+ /.$putCase consumeAllocationHeader(); $break ./
+
+ ClassInstanceCreationExpression ::= 'new' ClassType '(' ArgumentListopt ')' ClassBodyopt
+ /.$putCase consumeClassInstanceCreationExpression(); $break ./
+ --1.1 feature
+
+ ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
+ /.$putCase consumeClassInstanceCreationExpressionQualified() ; $break ./
+
+ --1.1 feature
+ ClassInstanceCreationExpression ::= ClassInstanceCreationExpressionName 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
+ /.$putCase consumeClassInstanceCreationExpressionQualified() ; $break ./
+
+ ClassInstanceCreationExpressionName ::= Name '.'
+ /.$putCase consumeClassInstanceCreationExpressionName() ; $break ./
+
+ ClassBodyopt ::= $empty --test made using null as contents
+ /.$putCase consumeClassBodyopt(); $break ./
+ ClassBodyopt ::= EnterAnonymousClassBody ClassBody
+
+ EnterAnonymousClassBody ::= $empty
+ /.$putCase consumeEnterAnonymousClassBody(); $break ./
+
+ ArgumentList ::= Expression
+ ArgumentList ::= ArgumentList ',' Expression
+ /.$putCase consumeArgumentList(); $break ./
+
+ --Thess rules are re-written in order to be ll1
+ --ArrayCreationExpression ::= 'new' ArrayType ArrayInitializer
+ --ArrayCreationExpression ::= 'new' PrimitiveType DimExprs Dimsopt
+ --ArrayCreationExpression ::= 'new' ClassOrInterfaceType DimExprs Dimsopt
+ --DimExprs ::= DimExpr
+ --DimExprs ::= DimExprs DimExpr
+
+ ArrayCreationExpression ::= 'new' PrimitiveType DimWithOrWithOutExprs ArrayInitializeropt
+ /.$putCase consumeArrayCreationExpression(); $break ./
+ ArrayCreationExpression ::= 'new' ClassOrInterfaceType DimWithOrWithOutExprs ArrayInitializeropt
+ /.$putCase consumeArrayCreationExpression(); $break ./
+
+ DimWithOrWithOutExprs ::= DimWithOrWithOutExpr
+ DimWithOrWithOutExprs ::= DimWithOrWithOutExprs DimWithOrWithOutExpr
+ /.$putCase consumeDimWithOrWithOutExprs(); $break ./
+
+ DimWithOrWithOutExpr ::= '[' Expression ']'
+ DimWithOrWithOutExpr ::= '[' ']'
+ /. $putCase consumeDimWithOrWithOutExpr(); $break ./
+ -- -----------------------------------------------
+
+ Dims ::= DimsLoop
+ /. $putCase consumeDims(); $break ./
+ DimsLoop -> OneDimLoop
+ DimsLoop ::= DimsLoop OneDimLoop
+ OneDimLoop ::= '[' ']'
+ /. $putCase consumeOneDimLoop(); $break ./
+
+ FieldAccess ::= Primary '.' 'Identifier'
+ /.$putCase consumeFieldAccess(false); $break ./
+
+ FieldAccess ::= 'super' '.' 'Identifier'
+ /.$putCase consumeFieldAccess(true); $break ./
+
+ MethodInvocation ::= Name '(' ArgumentListopt ')'
+ /.$putCase consumeMethodInvocationName(); $break ./
+
+ MethodInvocation ::= Primary '.' 'Identifier' '(' ArgumentListopt ')'
+ /.$putCase consumeMethodInvocationPrimary(); $break ./
+
+ MethodInvocation ::= 'super' '.' 'Identifier' '(' ArgumentListopt ')'
+ /.$putCase consumeMethodInvocationSuper(); $break ./
+
+ ArrayAccess ::= Name '[' Expression ']'
+ /.$putCase consumeArrayAccess(true); $break ./
+ ArrayAccess ::= PrimaryNoNewArray '[' Expression ']'
+ /.$putCase consumeArrayAccess(false); $break ./
+
+ PostfixExpression -> Primary
+ PostfixExpression ::= Name
+ /.$putCase consumePostfixExpression(); $break ./
+ PostfixExpression -> PostIncrementExpression
+ PostfixExpression -> PostDecrementExpression
+
+ PostIncrementExpression ::= PostfixExpression '++'
+ /.$putCase consumeUnaryExpression(OperatorExpression.PLUS,true); $break ./
+
+ PostDecrementExpression ::= PostfixExpression '--'
+ /.$putCase consumeUnaryExpression(OperatorExpression.MINUS,true); $break ./
+
+ --for source managment purpose
+ PushPosition ::= $empty
+ /.$putCase consumePushPosition(); $break ./
+
+ UnaryExpression -> PreIncrementExpression
+ UnaryExpression -> PreDecrementExpression
+ UnaryExpression ::= '+' PushPosition UnaryExpression
+ /.$putCase consumeUnaryExpression(OperatorExpression.PLUS); $break ./
+ UnaryExpression ::= '-' PushPosition UnaryExpression
+ /.$putCase consumeUnaryExpression(OperatorExpression.MINUS); $break ./
+ UnaryExpression -> UnaryExpressionNotPlusMinus
+
+ PreIncrementExpression ::= '++' PushPosition UnaryExpression
+ /.$putCase consumeUnaryExpression(OperatorExpression.PLUS,false); $break ./
+
+ PreDecrementExpression ::= '--' PushPosition UnaryExpression
+ /.$putCase consumeUnaryExpression(OperatorExpression.MINUS,false); $break ./
+
+ UnaryExpressionNotPlusMinus -> PostfixExpression
+ UnaryExpressionNotPlusMinus ::= '~' PushPosition UnaryExpression
+ /.$putCase consumeUnaryExpression(OperatorExpression.TWIDDLE); $break ./
+ UnaryExpressionNotPlusMinus ::= '!' PushPosition UnaryExpression
+ /.$putCase consumeUnaryExpression(OperatorExpression.NOT); $break ./
+ UnaryExpressionNotPlusMinus -> CastExpression
+
+ CastExpression ::= PushLPAREN PrimitiveType Dimsopt PushRPAREN UnaryExpression
+ /.$putCase consumeCastExpression(); $break ./
+ CastExpression ::= PushLPAREN Name Dims PushRPAREN UnaryExpressionNotPlusMinus
+ /.$putCase consumeCastExpression(); $break ./
+ -- Expression is here only in order to make the grammar LL1
+ CastExpression ::= PushLPAREN Expression PushRPAREN UnaryExpressionNotPlusMinus
+ /.$putCase consumeCastExpressionLL1(); $break ./
+
+ MultiplicativeExpression -> UnaryExpression
+ MultiplicativeExpression ::= MultiplicativeExpression '*' UnaryExpression
+ /.$putCase consumeBinaryExpression(OperatorExpression.MULTIPLY); $break ./
+ MultiplicativeExpression ::= MultiplicativeExpression '/' UnaryExpression
+ /.$putCase consumeBinaryExpression(OperatorExpression.DIVIDE); $break ./
+ MultiplicativeExpression ::= MultiplicativeExpression '%' UnaryExpression
+ /.$putCase consumeBinaryExpression(OperatorExpression.REMAINDER); $break ./
+
+ AdditiveExpression -> MultiplicativeExpression
+ AdditiveExpression ::= AdditiveExpression '+' MultiplicativeExpression
+ /.$putCase consumeBinaryExpression(OperatorExpression.PLUS); $break ./
+ AdditiveExpression ::= AdditiveExpression '-' MultiplicativeExpression
+ /.$putCase consumeBinaryExpression(OperatorExpression.MINUS); $break ./
+
+ ShiftExpression -> AdditiveExpression
+ ShiftExpression ::= ShiftExpression '<<' AdditiveExpression
+ /.$putCase consumeBinaryExpression(OperatorExpression.LEFT_SHIFT); $break ./
+ ShiftExpression ::= ShiftExpression '>>' AdditiveExpression
+ /.$putCase consumeBinaryExpression(OperatorExpression.RIGHT_SHIFT); $break ./
+ ShiftExpression ::= ShiftExpression '>>>' AdditiveExpression
+ /.$putCase consumeBinaryExpression(OperatorExpression.UNSIGNED_RIGHT_SHIFT); $break ./
+
+ RelationalExpression -> ShiftExpression
+ RelationalExpression ::= RelationalExpression '<' ShiftExpression
+ /.$putCase consumeBinaryExpression(OperatorExpression.LESS); $break ./
+ RelationalExpression ::= RelationalExpression '>' ShiftExpression
+ /.$putCase consumeBinaryExpression(OperatorExpression.GREATER); $break ./
+ RelationalExpression ::= RelationalExpression '<=' ShiftExpression
+ /.$putCase consumeBinaryExpression(OperatorExpression.LESS_EQUAL); $break ./
+ RelationalExpression ::= RelationalExpression '>=' ShiftExpression
+ /.$putCase consumeBinaryExpression(OperatorExpression.GREATER_EQUAL); $break ./
+ RelationalExpression ::= RelationalExpression 'instanceof' ReferenceType
+ /.$putCase consumeInstanceOfExpression(OperatorExpression.INSTANCEOF); $break ./
+
+ EqualityExpression -> RelationalExpression
+ EqualityExpression ::= EqualityExpression '==' RelationalExpression
+ /.$putCase consumeEqualityExpression(OperatorExpression.EQUAL_EQUAL); $break ./
+ EqualityExpression ::= EqualityExpression '!=' RelationalExpression
+ /.$putCase consumeEqualityExpression(OperatorExpression.NOT_EQUAL); $break ./
+
+ AndExpression -> EqualityExpression
+ AndExpression ::= AndExpression '&' EqualityExpression
+ /.$putCase consumeBinaryExpression(OperatorExpression.AND); $break ./
+
+ ExclusiveOrExpression -> AndExpression
+ ExclusiveOrExpression ::= ExclusiveOrExpression '^' AndExpression
+ /.$putCase consumeBinaryExpression(OperatorExpression.XOR); $break ./
+
+ InclusiveOrExpression -> ExclusiveOrExpression
+ InclusiveOrExpression ::= InclusiveOrExpression '|' ExclusiveOrExpression
+ /.$putCase consumeBinaryExpression(OperatorExpression.OR); $break ./
+
+ ConditionalAndExpression -> InclusiveOrExpression
+ ConditionalAndExpression ::= ConditionalAndExpression '&&' InclusiveOrExpression
+ /.$putCase consumeBinaryExpression(OperatorExpression.AND_AND); $break ./
+
+ ConditionalOrExpression -> ConditionalAndExpression
+ ConditionalOrExpression ::= ConditionalOrExpression '||' ConditionalAndExpression
+ /.$putCase consumeBinaryExpression(OperatorExpression.OR_OR); $break ./
+
+ ConditionalExpression -> ConditionalOrExpression
+ ConditionalExpression ::= ConditionalOrExpression '?' Expression ':' ConditionalExpression
+ /.$putCase consumeConditionalExpression(OperatorExpression.QUESTIONCOLON) ; $break ./
+
+ AssignmentExpression -> ConditionalExpression
+ AssignmentExpression -> Assignment
+
+ Assignment ::= LeftHandSide AssignmentOperator AssignmentExpression
+ /.$putCase consumeAssignment(); $break ./
+
+ -- this rule is added to parse an array initializer in a assigment and then report a syntax error knowing the exact senario
+ InvalidArrayInitializerAssignement ::= LeftHandSide AssignmentOperator ArrayInitializer
+ Assignment ::= InvalidArrayInitializerAssignement
+ /.$putcase ignoreExpressionAssignment();$break ./
+
+ LeftHandSide ::= Name
+ /.$putCase consumeLeftHandSide(); $break ./
+ LeftHandSide -> FieldAccess
+ LeftHandSide -> ArrayAccess
+
+ AssignmentOperator ::= '='
+ /.$putCase consumeAssignmentOperator(EQUAL); $break ./
+ AssignmentOperator ::= '*='
+ /.$putCase consumeAssignmentOperator(MULTIPLY); $break ./
+ AssignmentOperator ::= '/='
+ /.$putCase consumeAssignmentOperator(DIVIDE); $break ./
+ AssignmentOperator ::= '%='
+ /.$putCase consumeAssignmentOperator(REMAINDER); $break ./
+ AssignmentOperator ::= '+='
+ /.$putCase consumeAssignmentOperator(PLUS); $break ./
+ AssignmentOperator ::= '-='
+ /.$putCase consumeAssignmentOperator(MINUS); $break ./
+ AssignmentOperator ::= '<<='
+ /.$putCase consumeAssignmentOperator(LEFT_SHIFT); $break ./
+ AssignmentOperator ::= '>>='
+ /.$putCase consumeAssignmentOperator(RIGHT_SHIFT); $break ./
+ AssignmentOperator ::= '>>>='
+ /.$putCase consumeAssignmentOperator(UNSIGNED_RIGHT_SHIFT); $break ./
+ AssignmentOperator ::= '&='
+ /.$putCase consumeAssignmentOperator(AND); $break ./
+ AssignmentOperator ::= '^='
+ /.$putCase consumeAssignmentOperator(XOR); $break ./
+ AssignmentOperator ::= '|='
+ /.$putCase consumeAssignmentOperator(OR); $break ./
+
+ Expression -> AssignmentExpression
+
+ ConstantExpression -> Expression
+
+ -- The following rules are for optional nonterminals.
+ --
+
+ PackageDeclarationopt -> $empty
+ PackageDeclarationopt -> PackageDeclaration
+
+ ClassHeaderExtendsopt ::= $empty
+ ClassHeaderExtendsopt -> ClassHeaderExtends
+
+ Expressionopt ::= $empty
+ /.$putCase consumeEmptyExpression(); $break ./
+ Expressionopt -> Expression
+
+
+ ---------------------------------------------------------------------------------------
+ --
+ -- The rules below are for optional terminal symbols. An optional comma,
+ -- is only used in the context of an array initializer - It is a
+ -- "syntactic sugar" that otherwise serves no other purpose. By contrast,
+ -- an optional identifier is used in the definition of a break and
+ -- continue statement. When the identifier does not appear, a NULL
+ -- is produced. When the identifier is present, the user should use the
+ -- corresponding TOKEN(i) method. See break statement as an example.
+ --
+ ---------------------------------------------------------------------------------------
+
+ ,opt -> $empty
+ ,opt -> ,
+
+ ImportDeclarationsopt ::= $empty
+ /.$putCase consumeEmptyImportDeclarationsopt(); $break ./
+ ImportDeclarationsopt ::= ImportDeclarations
+ /.$putCase consumeImportDeclarationsopt(); $break ./
+
+
+ TypeDeclarationsopt ::= $empty
+ /.$putCase consumeEmptyTypeDeclarationsopt(); $break ./
+ TypeDeclarationsopt ::= TypeDeclarations
+ /.$putCase consumeTypeDeclarationsopt(); $break ./
+
+ ClassBodyDeclarationsopt ::= $empty
+ /.$putCase consumeEmptyClassBodyDeclarationsopt(); $break ./
+ ClassBodyDeclarationsopt ::= NestedType ClassBodyDeclarations
+ /.$putCase consumeClassBodyDeclarationsopt(); $break ./
+
+ Modifiersopt ::= $empty
+ /. $putCase consumeDefaultModifiers(); $break ./
+ Modifiersopt ::= Modifiers
+ /.$putCase consumeModifiers(); $break ./
+
+ BlockStatementsopt ::= $empty
+ /.$putCase consumeEmptyBlockStatementsopt(); $break ./
+ BlockStatementsopt -> BlockStatements
+
+ Dimsopt ::= $empty
+ /. $putCase consumeEmptyDimsopt(); $break ./
+ Dimsopt -> Dims
+
+ ArgumentListopt ::= $empty
+ /. $putCase consumeEmptyArgumentListopt(); $break ./
+ ArgumentListopt -> ArgumentList
+
+ MethodHeaderThrowsClauseopt ::= $empty
+ MethodHeaderThrowsClauseopt -> MethodHeaderThrowsClause
+
+ FormalParameterListopt ::= $empty
+ /.$putcase consumeFormalParameterListopt(); $break ./
+ FormalParameterListopt -> FormalParameterList
+
+ ClassHeaderImplementsopt ::= $empty
+ ClassHeaderImplementsopt -> ClassHeaderImplements
+
+ InterfaceMemberDeclarationsopt ::= $empty
+ /. $putCase consumeEmptyInterfaceMemberDeclarationsopt(); $break ./
+ InterfaceMemberDeclarationsopt ::= NestedType InterfaceMemberDeclarations
+ /. $putCase consumeInterfaceMemberDeclarationsopt(); $break ./
+
+ NestedType ::= $empty
+ /.$putCase consumeNestedType(); $break./
+
+ ForInitopt ::= $empty
+ /. $putCase consumeEmptyForInitopt(); $break ./
+ ForInitopt -> ForInit
+
+ ForUpdateopt ::= $empty
+ /. $putCase consumeEmptyForUpdateopt(); $break ./
+ ForUpdateopt -> ForUpdate
+
+ InterfaceHeaderExtendsopt ::= $empty
+ InterfaceHeaderExtendsopt -> InterfaceHeaderExtends
+
+ Catchesopt ::= $empty
+ /. $putCase consumeEmptyCatchesopt(); $break ./
+ Catchesopt -> Catches
+
+ ArrayInitializeropt ::= $empty
+ /. $putCase consumeEmptyArrayInitializeropt(); $break ./
+ ArrayInitializeropt -> ArrayInitializer
+
+ /. }
+ } ./
+
+ ---------------------------------------------------------------------------------------
+
+ $names
+
+ -- BodyMarker ::= '"class Identifier { ... MethodHeader "'
+
+ -- void ::= 'void'
+
+ PLUS_PLUS ::= '++'
+ MINUS_MINUS ::= '--'
+ EQUAL_EQUAL ::= '=='
+ LESS_EQUAL ::= '<='
+ GREATER_EQUAL ::= '>='
+ NOT_EQUAL ::= '!='
+ LEFT_SHIFT ::= '<<'
+ RIGHT_SHIFT ::= '>>'
+ UNSIGNED_RIGHT_SHIFT ::= '>>>'
+ PLUS_EQUAL ::= '+='
+ MINUS_EQUAL ::= '-='
+ MULTIPLY_EQUAL ::= '*='
+ DIVIDE_EQUAL ::= '/='
+ AND_EQUAL ::= '&='
+ OR_EQUAL ::= '|='
+ XOR_EQUAL ::= '^='
+ REMAINDER_EQUAL ::= '%='
+ LEFT_SHIFT_EQUAL ::= '<<='
+ RIGHT_SHIFT_EQUAL ::= '>>='
+ UNSIGNED_RIGHT_SHIFT_EQUAL ::= '>>>='
+ OR_OR ::= '||'
+ AND_AND ::= '&&'
+
+ PLUS ::= '+'
+ MINUS ::= '-'
+ NOT ::= '!'
+ REMAINDER ::= '%'
+ XOR ::= '^'
+ AND ::= '&'
+ MULTIPLY ::= '*'
+ OR ::= '|'
+ TWIDDLE ::= '~'
+ DIVIDE ::= '/'
+ GREATER ::= '>'
+ LESS ::= '<'
+ LPAREN ::= '('
+ RPAREN ::= ')'
+ LBRACE ::= '{'
+ RBRACE ::= '}'
+ LBRACKET ::= '['
+ RBRACKET ::= ']'
+ SEMICOLON ::= ';'
+ QUESTION ::= '?'
+ COLON ::= ':'
+ COMMA ::= ','
+ DOT ::= '.'
+ EQUAL ::= '='
+
+ $end
+ -- need a carriage return after the $end
+ */
+ }
+
+ protected void ignoreExpressionAssignment() {
+ // Assignment ::= InvalidArrayInitializerAssignement
+ int op = intStack[intPtr--]; //<--the encoded operator
+ ArrayInitializer arrayInitializer =
+ (ArrayInitializer) expressionStack[expressionPtr--];
+ expressionLengthPtr--;
+ // report a syntax error and abort parsing
+ problemReporter().arrayConstantsOnlyInArrayInitializers(
+ arrayInitializer.sourceStart(),
+ arrayInitializer.sourceEnd());
+ }
+
+ protected void ignoreInterfaceDeclaration() {
+ // BlockStatement ::= InvalidInterfaceDeclaration
+ //InterfaceDeclaration ::= Modifiersopt 'interface' 'Identifier' ExtendsInterfacesopt InterfaceHeader InterfaceBody
+
+ // length declarations
+ int length;
+ if ((length = astLengthStack[astLengthPtr--]) != 0) {
+ //there are length declarations
+ //dispatch according to the type of the declarations
+ dispatchDeclarationInto(length);
+ }
+
+ flushAnnotationsDefinedPriorTo(endStatementPosition);
+
+ // report the problem and continue parsing
+ TypeDeclaration typeDecl = (TypeDeclaration) astStack[astPtr];
+ problemReporter().cannotDeclareLocalInterface(
+ typeDecl.name,
+ typeDecl.sourceStart,
+ typeDecl.sourceEnd);
+
+ // remove the ast node created in interface header
+ astPtr--;
+ // Don't create an astnode for this inner interface, but have to push
+ // a 0 on the astLengthStack to be consistent with the reduction made
+ // at the end of the method:
+ // public void parse(MethodDeclaration md, CompilationUnitDeclaration unit)
+ pushOnAstLengthStack(0);
+ }
+
+ protected void ignoreInvalidConstructorDeclaration(boolean hasBody) {
+ // InvalidConstructorDeclaration ::= ConstructorHeader ConstructorBody ==> true
+ // InvalidConstructorDeclaration ::= ConstructorHeader ';' ==> false
+
+ /*
+ astStack : modifiers arguments throws statements
+ identifierStack : name
+ ==>
+ astStack : MethodDeclaration
+ identifierStack :
+ */
+
+ //must provide a default constructor call when needed
+
+ int length;
+ if (hasBody) {
+ // pop the position of the { (body of the method) pushed in block decl
+ intPtr--;
+ }
+
+ //statements
+ if (hasBody) {
+ realBlockPtr--;
+ }
+
+ if (hasBody && ((length = astLengthStack[astLengthPtr--]) != 0)) {
+ astPtr -= length;
+ }
+
+ // now we know that the top of stack is a constructorDeclaration
+ ConstructorDeclaration cd = (ConstructorDeclaration) astStack[astPtr];
+
+ //watch for } that could be given as a unicode ! ( u007D is '}' )
+ flushAnnotationsDefinedPriorTo(endStatementPosition);
+
+ }
+
+ protected void ignoreMethodBody() {
+ // InterfaceMemberDeclaration ::= InvalidMethodDeclaration
+
+ /*
+ astStack : modifiers arguments throws statements
+ identifierStack : type name
+ intStack : dim dim dim
+ ==>
+ astStack : MethodDeclaration
+ identifierStack :
+ intStack :
+ */
+
+ // pop the position of the { (body of the method) pushed in block decl
+ intPtr--;
+ // retrieve end position of method declarator
+
+ //statements
+ realBlockPtr--;
+ int length;
+ if ((length = astLengthStack[astLengthPtr--]) != 0) {
+ astPtr -= length;
+ }
+
+ //watch for } that could be given as a unicode ! ( u007D is '}' )
+ MethodDeclaration md = (MethodDeclaration) astStack[astPtr];
+ md.bodyEnd = endPosition;
+ md.declarationSourceEnd = flushAnnotationsDefinedPriorTo(endStatementPosition);
+
+ // report the problem and continue the parsing - narrowing the problem onto the method
+ problemReporter().abstractMethodNeedingNoBody(
+ md,
+ compilationUnit.compilationResult);
+ }
+
+ public void initialize() {
+ //positionning the parser for a new compilation unit
+ //avoiding stack reallocation and all that....
+ astPtr = -1;
+ astLengthPtr = -1;
+ expressionPtr = -1;
+ expressionLengthPtr = -1;
+ identifierPtr = -1;
+ identifierLengthPtr = -1;
+ intPtr = -1;
+ nestedMethod[nestedType = 0] = 0; // need to reset for further reuse
+ variablesCounter[nestedType] = 0;
+ dimensions = 0;
+ realBlockPtr = -1;
+ compilationUnit = null;
+ referenceContext = null;
+ endStatementPosition = 0;
+
+ //remove objects from stack too, while the same parser/compiler couple is
+ //re-used between two compilations ....
+
+ int astLength = astStack.length;
+ if (noAstNodes.length < astLength) {
+ noAstNodes = new AstNode[astLength];
+ //System.out.println("Resized AST stacks : "+ astLength);
+
+ }
+ System.arraycopy(noAstNodes, 0, astStack, 0, astLength);
+
+ int expressionLength = expressionStack.length;
+ if (noExpressions.length < expressionLength) {
+ noExpressions = new Expression[expressionLength];
+ //System.out.println("Resized EXPR stacks : "+ expressionLength);
+ }
+ System.arraycopy(noExpressions, 0, expressionStack, 0, expressionLength);
+
+ // reset scanner state
+ scanner.commentPtr = -1;
+ scanner.eofPosition = Integer.MAX_VALUE;
+
+ resetModifiers();
+
+ // recovery
+ lastCheckPoint = -1;
+ currentElement = null;
+ restartRecovery = false;
+ hasReportedError = false;
+ recoveredStaticInitializerStart = 0;
+ lastIgnoredToken = -1;
+ lastErrorEndPosition = -1;
+ }
+
+ public void initializeScanner() {
+ this.scanner = new Scanner();
+ }
+
+ public final static void initTables() throws java.io.IOException {
+
+ final String prefix = FILEPREFIX;
+ int i = 0;
+ lhs = readTable(prefix + (++i) + ".rsc");
+ char[] chars = readTable(prefix + (++i) + ".rsc");
+ check_table = new short[chars.length];
+ for (int c = chars.length; c-- > 0;) {
+ check_table[c] = (short) (chars[c] - 32768);
+ }
+ asb = readTable(prefix + (++i) + ".rsc");
+ asr = readTable(prefix + (++i) + ".rsc");
+ symbol_index = readTable(prefix + (++i) + ".rsc");
+ action = lhs;
+ }
+
+ public final void jumpOverMethodBody() {
+ //on diet parsing.....do not buffer method statements
+
+ //the scanner.diet is reinitialized to false
+ //automatically by the scanner once it has jumped over
+ //the statements
+
+ if (diet && (dietInt == 0))
+ scanner.diet = true;
+ }
+
+ /*
+ * Move checkpoint location (current implementation is moving it by one token)
+ *
+ * Answers true if successfully moved checkpoint (i.e. did not attempt to move it
+ * beyond end of file).
+ */
+ protected boolean moveRecoveryCheckpoint() {
+
+ int pos = lastCheckPoint;
+ /* reset scanner, and move checkpoint by one token */
+ scanner.startPosition = pos;
+ scanner.currentPosition = pos;
+ scanner.diet = false; // quit jumping over method bodies
+
+ /* if about to restart, then no need to shift token */
+ if (restartRecovery) {
+ lastIgnoredToken = -1;
+ return true;
+ }
+
+ /* protect against shifting on an invalid token */
+ lastIgnoredToken = nextIgnoredToken;
+ nextIgnoredToken = -1;
+ do {
+ try {
+ nextIgnoredToken = scanner.getNextToken();
+ if (scanner.currentPosition == scanner.startPosition) {
+ scanner.currentPosition++; // on fake completion identifier
+ nextIgnoredToken = -1;
+ }
+
+ } catch (InvalidInputException e) {
+ pos = scanner.currentPosition;
+ }
+ } while (nextIgnoredToken < 0);
+
+ if (nextIgnoredToken == TokenNameEOF) { // no more recovery after this point
+ if (currentToken == TokenNameEOF) { // already tried one iteration on EOF
+ return false;
+ }
+ }
+ lastCheckPoint = scanner.currentPosition;
+
+ /* reset scanner again to previous checkpoint location*/
+ scanner.startPosition = pos;
+ scanner.currentPosition = pos;
+ scanner.commentPtr = -1;
+
+ return true;
+
+ /*
+ The following implementation moves the checkpoint location by one line:
+
+ int pos = lastCheckPoint;
+ // reset scanner, and move checkpoint by one token
+ scanner.startPosition = pos;
+ scanner.currentPosition = pos;
+ scanner.diet = false; // quit jumping over method bodies
+
+ // if about to restart, then no need to shift token
+ if (restartRecovery){
+ lastIgnoredToken = -1;
+ return true;
+ }
+
+ // protect against shifting on an invalid token
+ lastIgnoredToken = nextIgnoredToken;
+ nextIgnoredToken = -1;
+
+ boolean wasTokenizingWhiteSpace = scanner.tokenizeWhiteSpace;
+ scanner.tokenizeWhiteSpace = true;
+ checkpointMove:
+ do {
+ try {
+ nextIgnoredToken = scanner.getNextToken();
+ switch(nextIgnoredToken){
+ case Scanner.TokenNameWHITESPACE :
+ if(scanner.searchLineNumber(scanner.startPosition)
+ == scanner.searchLineNumber(scanner.currentPosition)){
+ nextIgnoredToken = -1;
+ }
+ break;
+ case TokenNameSEMICOLON :
+ case TokenNameLBRACE :
+ case TokenNameRBRACE :
+ break;
+ case TokenNameIdentifier :
+ if(scanner.currentPosition == scanner.startPosition){
+ scanner.currentPosition++; // on fake completion identifier
+ }
+ default:
+ nextIgnoredToken = -1;
+ break;
+ case TokenNameEOF :
+ break checkpointMove;
+ }
+ } catch(InvalidInputException e){
+ pos = scanner.currentPosition;
+ }
+ } while (nextIgnoredToken < 0);
+ scanner.tokenizeWhiteSpace = wasTokenizingWhiteSpace;
+
+ if (nextIgnoredToken == TokenNameEOF) { // no more recovery after this point
+ if (currentToken == TokenNameEOF) { // already tried one iteration on EOF
+ return false;
+ }
+ }
+ lastCheckPoint = scanner.currentPosition;
+
+ // reset scanner again to previous checkpoint location
+ scanner.startPosition = pos;
+ scanner.currentPosition = pos;
+ scanner.commentPtr = -1;
+
+ return true;
+ */
+ }
+
+ protected MessageSend newMessageSend() {
+ // '(' ArgumentListopt ')'
+ // the arguments are on the expression stack
+
+ MessageSend m = new MessageSend();
+ int length;
+ if ((length = expressionLengthStack[expressionLengthPtr--]) != 0) {
+ expressionPtr -= length;
+ System.arraycopy(
+ expressionStack,
+ expressionPtr + 1,
+ m.arguments = new Expression[length],
+ 0,
+ length);
+ };
+ return m;
+ }
+
+ protected static int ntAction(int state, int sym) {
+ return action[state + sym];
+ }
+
+ private final void optimizedConcatNodeLists() {
+ /*back from a recursive loop. Virtualy group the
+ astNode into an array using astLengthStack*/
+
+ /*
+ * This is a case where you have two sublists into the astStack that you want
+ * to merge in one list. There is no action required on the astStack. The only
+ * thing you need to do is merge the two lengths specified on the astStackLength.
+ * The top two length are for example:
+ * ... p n
+ * and you want to result in a list like:
+ * ... n+p
+ * This means that the p could be equals to 0 in case there is no astNode pushed
+ * on the astStack.
+ * Look at the InterfaceMemberDeclarations for an example.
+ * This case optimizes the fact that p == 1.
+ */
+
+ astLengthStack[--astLengthPtr]++;
+ }
+
+ protected static int original_state(int state) {
+ return -check(state);
+ }
+
+ /*main loop of the automat
+ When a rule is reduced, the method consumeRule(int) is called with the number
+ of the consumed rule. When a terminal is consumed, the method consumeToken(int) is
+ called in order to remember (when needed) the consumed token */
+ // (int)asr[asi(act)]
+ // name[symbol_index[currentKind]]
+ protected void parse() {
+
+ hasReportedError = false;
+ int act = START_STATE;
+ stateStackTop = -1;
+ currentToken = getFirstToken();
+ ProcessTerminals : for (;;) {
+ try {
+ stack[++stateStackTop] = act;
+ } catch (IndexOutOfBoundsException e) {
+ int oldStackLength = stack.length;
+ int oldStack[] = stack;
+ stack = new int[oldStackLength + StackIncrement];
+ System.arraycopy(oldStack, 0, stack, 0, oldStackLength);
+ stack[stateStackTop] = act;
+ };
+
+ act = tAction(act, currentToken);
+
+ if (act == ERROR_ACTION || restartRecovery) {
+ int errorPos = scanner.currentPosition;
+ if (!hasReportedError) {
+ this.reportSyntaxError(ERROR_ACTION, currentToken, stateStackTop);
+ hasReportedError = true;
+ }
+ if (resumeOnSyntaxError()) {
+ if (act == ERROR_ACTION)
+ lastErrorEndPosition = errorPos;
+ act = START_STATE;
+ stateStackTop = -1;
+ currentToken = getFirstToken();
+ continue ProcessTerminals;
+ } else {
+ act = ERROR_ACTION;
+ }
+ break ProcessTerminals;
+ }
+ if (act <= NUM_RULES)
+ stateStackTop--;
+ else
+ if (act > ERROR_ACTION) { /* shift-reduce */
+ consumeToken(currentToken);
+ if (currentElement != null)
+ this.recoveryTokenCheck();
+ try {
+ currentToken = scanner.getNextToken();
+ } catch (InvalidInputException e) {
+ if (!hasReportedError) {
+ this.problemReporter().scannerError(this, e.getMessage());
+ hasReportedError = true;
+ }
+ lastCheckPoint = scanner.currentPosition;
+ restartRecovery = true;
+ }
+ act -= ERROR_ACTION;
+ } else
+ if (act < ACCEPT_ACTION) { /* shift */
+ consumeToken(currentToken);
+ if (currentElement != null)
+ this.recoveryTokenCheck();
+ try {
+ currentToken = scanner.getNextToken();
+ } catch (InvalidInputException e) {
+ if (!hasReportedError) {
+ this.problemReporter().scannerError(this, e.getMessage());
+ hasReportedError = true;
+ }
+ lastCheckPoint = scanner.currentPosition;
+ restartRecovery = true;
+ }
+ continue ProcessTerminals;
+ } else
+ break ProcessTerminals;
+
+ ProcessNonTerminals : do { /* reduce */
+ consumeRule(act);
+ stateStackTop -= (rhs[act] - 1);
+ act = ntAction(stack[stateStackTop], lhs[act]);
+ } while (act <= NUM_RULES);
+ }
+ endParse(act);
+ }
+
+ // A P I
+
+ public void parse(ConstructorDeclaration cd, CompilationUnitDeclaration unit) {
+ //only parse the method body of cd
+ //fill out its statements
+
+ //convert bugs into parse error
+
+ initialize();
+ goForConstructorBody();
+ nestedMethod[nestedType]++;
+
+ referenceContext = cd;
+ compilationUnit = unit;
+
+ scanner.resetTo(cd.sourceEnd + 1, cd.declarationSourceEnd);
+ try {
+ parse();
+ } catch (AbortCompilation ex) {
+ lastAct = ERROR_ACTION;
+ } finally {
+ nestedMethod[nestedType]--;
+ }
+
+ if (lastAct == ERROR_ACTION) {
+ initialize();
+ return;
+ }
+
+ //statements
+ cd.explicitDeclarations = realBlockStack[realBlockPtr--];
+ int length;
+ if ((length = astLengthStack[astLengthPtr--]) != 0) {
+ astPtr -= length;
+ if (astStack[astPtr + 1] instanceof ExplicitConstructorCall)
+ //avoid a isSomeThing that would only be used here BUT what is faster between two alternatives ?
+ {
+ System.arraycopy(
+ astStack,
+ astPtr + 2,
+ cd.statements = new Statement[length - 1],
+ 0,
+ length - 1);
+ cd.constructorCall = (ExplicitConstructorCall) astStack[astPtr + 1];
+ } else { //need to add explicitly the super();
+ System.arraycopy(
+ astStack,
+ astPtr + 1,
+ cd.statements = new Statement[length],
+ 0,
+ length);
+ cd.constructorCall = SuperReference.implicitSuperConstructorCall();
+ }
+ } else {
+ cd.constructorCall = SuperReference.implicitSuperConstructorCall();
+ }
+
+ if (cd.constructorCall.sourceEnd == 0) {
+ cd.constructorCall.sourceEnd = cd.sourceEnd;
+ cd.constructorCall.sourceStart = cd.sourceStart;
+ }
+ }
+
+ // A P I
+
+ public void parse(
+ Initializer ini,
+ TypeDeclaration type,
+ CompilationUnitDeclaration unit) {
+ //only parse the method body of md
+ //fill out method statements
+
+ //convert bugs into parse error
+
+ initialize();
+ goForInitializer();
+ nestedMethod[nestedType]++;
+
+ referenceContext = type;
+ compilationUnit = unit;
+
+ scanner.resetTo(ini.sourceStart, ini.sourceEnd); // just on the beginning {
+ try {
+ parse();
+ } catch (AbortCompilation ex) {
+ lastAct = ERROR_ACTION;
+ } finally {
+ nestedMethod[nestedType]--;
+ }
+
+ if (lastAct == ERROR_ACTION) {
+ return;
+ }
+
+ ini.block = ((Initializer) astStack[astPtr]).block;
+ }
+
+ // A P I
+
+ public void parse(MethodDeclaration md, CompilationUnitDeclaration unit) {
+ //only parse the method body of md
+ //fill out method statements
+
+ //convert bugs into parse error
+
+ if (md.isAbstract())
+ return;
+ if (md.isNative())
+ return;
+ if ((md.modifiers & AccSemicolonBody) != 0)
+ return;
+
+ initialize();
+ goForMethodBody();
+ nestedMethod[nestedType]++;
+
+ referenceContext = md;
+ compilationUnit = unit;
+
+ scanner.resetTo(md.sourceEnd + 1, md.declarationSourceEnd);
+ // reset the scanner to parser from { down to }
+ try {
+ parse();
+ } catch (AbortCompilation ex) {
+ lastAct = ERROR_ACTION;
+ } finally {
+ nestedMethod[nestedType]--;
+ }
+
+ if (lastAct == ERROR_ACTION) {
+ return;
+ }
+
+ //refill statements
+ md.explicitDeclarations = realBlockStack[realBlockPtr--];
+ int length;
+ if ((length = astLengthStack[astLengthPtr--]) != 0)
+ System.arraycopy(
+ astStack,
+ (astPtr -= length) + 1,
+ md.statements = new Statement[length],
+ 0,
+ length);
+ }
+
+ // A P I
+
+ public CompilationUnitDeclaration parse(
+ ICompilationUnit sourceUnit,
+ CompilationResult compilationResult) {
+ // parses a compilation unit and manages error handling (even bugs....)
+
+ CompilationUnitDeclaration unit;
+ try {
+ /* automaton initialization */
+ initialize();
+ goForCompilationUnit();
+
+ /* scanner initialization */
+ scanner.setSourceBuffer(sourceUnit.getContents());
+ int sourceLength = scanner.source.length;
+
+ /* unit creation */
+ referenceContext =
+ compilationUnit =
+ new CompilationUnitDeclaration(
+ problemReporter,
+ compilationResult,
+ scanner.source.length);
+ /* run automaton */
+ parse();
+ } finally {
+ unit = compilationUnit;
+ compilationUnit = null; // reset parser
+ }
+ return unit;
+ }
+
+ // A P I
+
+ public CompilationUnitDeclaration parse(
+ ICompilationUnit sourceUnit,
+ CompilationResult compilationResult,
+ int start,
+ int end) {
+ // parses a compilation unit and manages error handling (even bugs....)
+
+ CompilationUnitDeclaration unit;
+ try {
+ /* automaton initialization */
+ initialize();
+ goForCompilationUnit();
+
+ /* scanner initialization */
+ scanner.setSourceBuffer(sourceUnit.getContents());
+ int sourceLength = scanner.source.length;
+ scanner.resetTo(start, end);
+ /* unit creation */
+ referenceContext =
+ compilationUnit =
+ new CompilationUnitDeclaration(
+ problemReporter,
+ compilationResult,
+ scanner.source.length);
+ /* run automaton */
+ parse();
+ } finally {
+ unit = compilationUnit;
+ compilationUnit = null; // reset parser
+ }
+ return unit;
+ }
+
+ /**
+ * Returns this parser's problem reporter initialized with its reference context.
+ * Also it is assumed that a problem is going to be reported, so initializes
+ * the compilation result's line positions.
+ */
+ public ProblemReporter problemReporter() {
+ if (scanner.recordLineSeparator) {
+ compilationUnit.compilationResult.lineSeparatorPositions = scanner.lineEnds();
+ }
+ problemReporter.referenceContext = referenceContext;
+ return problemReporter;
+ }
+
+ protected void pushIdentifier() {
+ /*push the consumeToken on the identifier stack.
+ Increase the total number of identifier in the stack.
+ identifierPtr points on the next top */
+
+ try {
+ identifierStack[++identifierPtr] = scanner.getCurrentIdentifierSource();
+ identifierPositionStack[identifierPtr] =
+ (((long) scanner.startPosition) << 32) + (scanner.currentPosition - 1);
+ } catch (IndexOutOfBoundsException e) {
+ /*---stack reallaocation (identifierPtr is correct)---*/
+ int oldStackLength = identifierStack.length;
+ char[][] oldStack = identifierStack;
+ identifierStack = new char[oldStackLength + 20][];
+ System.arraycopy(oldStack, 0, identifierStack, 0, oldStackLength);
+ identifierStack[identifierPtr] = scanner.getCurrentTokenSource();
+ /*identifier position stack*/
+ long[] oldPos = identifierPositionStack;
+ identifierPositionStack = new long[oldStackLength + 20];
+ System.arraycopy(oldPos, 0, identifierPositionStack, 0, oldStackLength);
+ identifierPositionStack[identifierPtr] =
+ (((long) scanner.startPosition) << 32) + (scanner.currentPosition - 1);
+ };
+
+ try {
+ identifierLengthStack[++identifierLengthPtr] = 1;
+ } catch (IndexOutOfBoundsException e) {
+ /*---stack reallocation (identifierLengthPtr is correct)---*/
+ int oldStackLength = identifierLengthStack.length;
+ int oldStack[] = identifierLengthStack;
+ identifierLengthStack = new int[oldStackLength + 10];
+ System.arraycopy(oldStack, 0, identifierLengthStack, 0, oldStackLength);
+ identifierLengthStack[identifierLengthPtr] = 1;
+ };
+
+ }
+
+ protected void pushIdentifier(int flag) {
+ /*push a special flag on the stack :
+ -zero stands for optional Name
+ -negative number for direct ref to base types.
+ identifierLengthPtr points on the top */
+
+ try {
+ identifierLengthStack[++identifierLengthPtr] = flag;
+ } catch (IndexOutOfBoundsException e) {
+ /*---stack reallaocation (identifierLengthPtr is correct)---*/
+ int oldStackLength = identifierLengthStack.length;
+ int oldStack[] = identifierLengthStack;
+ identifierLengthStack = new int[oldStackLength + 10];
+ System.arraycopy(oldStack, 0, identifierLengthStack, 0, oldStackLength);
+ identifierLengthStack[identifierLengthPtr] = flag;
+ };
+
+ }
+
+ protected void pushOnAstLengthStack(int pos) {
+ try {
+ astLengthStack[++astLengthPtr] = pos;
+ } catch (IndexOutOfBoundsException e) {
+ int oldStackLength = astLengthStack.length;
+ int[] oldPos = astLengthStack;
+ astLengthStack = new int[oldStackLength + StackIncrement];
+ System.arraycopy(oldPos, 0, astLengthStack, 0, oldStackLength);
+ astLengthStack[astLengthPtr] = pos;
+ }
+ }
+
+ protected void pushOnAstStack(AstNode node) {
+ /*add a new obj on top of the ast stack
+ astPtr points on the top*/
+
+ try {
+ astStack[++astPtr] = node;
+ } catch (IndexOutOfBoundsException e) {
+ int oldStackLength = astStack.length;
+ AstNode[] oldStack = astStack;
+ astStack = new AstNode[oldStackLength + AstStackIncrement];
+ System.arraycopy(oldStack, 0, astStack, 0, oldStackLength);
+ astPtr = oldStackLength;
+ astStack[astPtr] = node;
+ }
+
+ try {
+ astLengthStack[++astLengthPtr] = 1;
+ } catch (IndexOutOfBoundsException e) {
+ int oldStackLength = astLengthStack.length;
+ int[] oldPos = astLengthStack;
+ astLengthStack = new int[oldStackLength + AstStackIncrement];
+ System.arraycopy(oldPos, 0, astLengthStack, 0, oldStackLength);
+ astLengthStack[astLengthPtr] = 1;
+ }
+ }
+
+ protected void pushOnExpressionStack(Expression expr) {
+
+ try {
+ expressionStack[++expressionPtr] = expr;
+ } catch (IndexOutOfBoundsException e) {
+ //expressionPtr is correct
+ int oldStackLength = expressionStack.length;
+ Expression[] oldStack = expressionStack;
+ expressionStack = new Expression[oldStackLength + ExpressionStackIncrement];
+ System.arraycopy(oldStack, 0, expressionStack, 0, oldStackLength);
+ expressionStack[expressionPtr] = expr;
+ }
+
+ try {
+ expressionLengthStack[++expressionLengthPtr] = 1;
+ } catch (IndexOutOfBoundsException e) {
+ int oldStackLength = expressionLengthStack.length;
+ int[] oldPos = expressionLengthStack;
+ expressionLengthStack = new int[oldStackLength + ExpressionStackIncrement];
+ System.arraycopy(oldPos, 0, expressionLengthStack, 0, oldStackLength);
+ expressionLengthStack[expressionLengthPtr] = 1;
+ }
+ }
+
+ protected void pushOnExpressionStackLengthStack(int pos) {
+ try {
+ expressionLengthStack[++expressionLengthPtr] = pos;
+ } catch (IndexOutOfBoundsException e) {
+ int oldStackLength = expressionLengthStack.length;
+ int[] oldPos = expressionLengthStack;
+ expressionLengthStack = new int[oldStackLength + StackIncrement];
+ System.arraycopy(oldPos, 0, expressionLengthStack, 0, oldStackLength);
+ expressionLengthStack[expressionLengthPtr] = pos;
+ }
+ }
+
+ protected void pushOnIntStack(int pos) {
+
+ try {
+ intStack[++intPtr] = pos;
+ } catch (IndexOutOfBoundsException e) {
+ //intPtr is correct
+ int oldStackLength = intStack.length;
+ int oldStack[] = intStack;
+ intStack = new int[oldStackLength + StackIncrement];
+ System.arraycopy(oldStack, 0, intStack, 0, oldStackLength);
+ intStack[intPtr] = pos;
+ }
+ }
+
+ protected static char[] readTable(String filename) throws java.io.IOException {
+
+ //files are located at Parser.class directory
+
+ InputStream stream = Parser.class.getResourceAsStream(filename);
+ if (stream == null) {
+ throw new java.io.IOException("missing file" + filename);
+ }
+
+ ByteArrayOutputStream os = new ByteArrayOutputStream(32000);
+ // the largest file is 30K
+ byte[] buffer = new byte[10000];
+
+ int streamLength = 0;
+ int lastReadSize = 0;
+ while ((lastReadSize = stream.read(buffer)) > 0) {
+ streamLength += lastReadSize;
+ os.write(buffer, 0, lastReadSize);
+ }
+ byte[] bytes = os.toByteArray();
+ stream.close();
+
+ //minimal integrity check (even size expected)
+ if (streamLength % 2 != 0)
+ throw new java.io.IOException("corrupted file " + filename);
+
+ // convert bytes into chars
+ char[] chars = new char[streamLength / 2];
+ int i = 0;
+ int charIndex = 0;
+
+ while (true) {
+ chars[charIndex++] = (char) (((bytes[i++] & 0xFF) << 8) + (bytes[i++] & 0xFF));
+ if (i == streamLength)
+ break;
+ }
+ return chars;
+ }
+
+ /* Token check performed on every token shift once having entered
+ * recovery mode.
+ */
+ public void recoveryTokenCheck() {
+ switch (currentToken) {
+ case TokenNameLBRACE :
+ {
+ RecoveredElement newElement =
+ currentElement.updateOnOpeningBrace(scanner.currentPosition - 1);
+ lastCheckPoint = scanner.currentPosition;
+ if (newElement != null) { // null means nothing happened
+ restartRecovery = true; // opening brace detected
+ currentElement = newElement;
+ }
+ break;
+ }
+ case TokenNameRBRACE :
+ {
+ endPosition = this.flushAnnotationsDefinedPriorTo(scanner.currentPosition - 1);
+ RecoveredElement newElement =
+ currentElement.updateOnClosingBrace(
+ scanner.startPosition,
+ scanner.currentPosition - 1);
+ lastCheckPoint = scanner.currentPosition;
+ if (newElement != currentElement) {
+ currentElement = newElement;
+ }
+ }
+ }
+ }
+
+ protected void reportSyntaxError(int act, int currentKind, int stateStackTop) {
+
+ /* remember current scanner position */
+ int startPos = scanner.startPosition;
+ int currentPos = scanner.currentPosition;
+
+ String[] expectings;
+ String tokenName = name[symbol_index[currentKind]];
+
+ //fetch all "accurate" possible terminals that could recover the error
+ int start, end = start = asi(stack[stateStackTop]);
+ while (asr[end] != 0)
+ end++;
+ int length = end - start;
+ expectings = new String[length];
+ if (length != 0) {
+ char[] indexes = new char[length];
+ System.arraycopy(asr, start, indexes, 0, length);
+ for (int i = 0; i < length; i++) {
+ expectings[i] = name[symbol_index[indexes[i]]];
+ }
+ }
+
+ //if the pb is an EOF, try to tell the user that they are some
+ if (tokenName.equals(UNEXPECTED_EOF)) {
+ if (!this.checkAndReportBracketAnomalies(problemReporter())) {
+ char[] tokenSource;
+ try {
+ tokenSource = this.scanner.getCurrentTokenSource();
+ } catch (Exception e) {
+ tokenSource = new char[] {
+ };
+ }
+ problemReporter().parseError(
+ this.scanner.startPosition,
+ this.scanner.currentPosition - 1,
+ tokenSource,
+ tokenName,
+ expectings,
+ referenceContext,
+ compilationUnit.compilationResult);
+ }
+ } else { //the next test is HEAVILY grammar DEPENDENT.
+ if ((length == 2)
+ && (tokenName.equals(";"))
+ && (expectings[0] == "++")
+ && (expectings[1] == "--")
+ && (expressionPtr > -1)) {
+ // the ; is not the expected token ==> it ends a statement when an expression is not ended
+ problemReporter().invalidExpressionAsStatement(expressionStack[expressionPtr]);
+ } else {
+ char[] tokenSource;
+ try {
+ tokenSource = this.scanner.getCurrentTokenSource();
+ } catch (Exception e) {
+ tokenSource = new char[] {
+ };
+ }
+ problemReporter().parseError(
+ this.scanner.startPosition,
+ this.scanner.currentPosition - 1,
+ tokenSource,
+ tokenName,
+ expectings,
+ referenceContext,
+ compilationUnit.compilationResult);
+ this.checkAndReportBracketAnomalies(problemReporter());
+ }
+ }
+ /* reset scanner where it was */
+ scanner.startPosition = startPos;
+ scanner.currentPosition = currentPos;
+ }
+
+ protected void resetModifiers() {
+ modifiers = AccDefault;
+ modifiersSourceStart = -1; // <-- see comment into modifiersFlag(int)
+ }
+
+ /*
+ * Reset context so as to resume to regular parse loop
+ */
+ protected void resetStacks() {
+
+ astPtr = -1;
+ astLengthPtr = -1;
+ expressionPtr = -1;
+ expressionLengthPtr = -1;
+ identifierPtr = -1;
+ identifierLengthPtr = -1;
+ intPtr = -1;
+ nestedMethod[nestedType = 0] = 0; // need to reset for further reuse
+ variablesCounter[nestedType] = 0;
+ dimensions = 0;
+ realBlockStack[realBlockPtr = 0] = 0;
+ recoveredStaticInitializerStart = 0;
+ }
+
+ /*
+ * Reset context so as to resume to regular parse loop
+ * If unable to reset for resuming, answers false.
+ *
+ * Move checkpoint location, reset internal stacks and
+ * decide which grammar goal is activated.
+ */
+ protected boolean resumeAfterRecovery() {
+
+ // reset internal stacks
+ this.resetStacks();
+
+ /* attempt to move checkpoint location */
+ if (!this.moveRecoveryCheckpoint())
+ return false;
+
+ // only look for headers
+ if (referenceContext instanceof CompilationUnitDeclaration) {
+ goForHeaders();
+ diet = true; // passed this point, will not consider method bodies
+ return true;
+ }
+ // does not know how to restart
+ return false;
+ }
+
+ /*
+ * Syntax error was detected. Will attempt to perform some recovery action in order
+ * to resume to the regular parse loop.
+ */
+ protected boolean resumeOnSyntaxError() {
+
+ /* request recovery initialization */
+ if (currentElement == null) {
+ currentElement = this.buildInitialRecoveryState();
+ // build some recovered elements
+ }
+ /* do not investigate deeper in recovery when no recovered element */
+ if (currentElement == null)
+ return false;
+
+ /* manual forced recovery restart - after headers */
+ if (restartRecovery) {
+ restartRecovery = false;
+ }
+ /* update recovery state with current error state of the parser */
+ this.updateRecoveryState();
+
+ /* attempt to reset state in order to resume to parse loop */
+ return this.resumeAfterRecovery();
+ }
+
+ protected static int tAction(int state, int sym) {
+ return action[check(state + sym) == sym ? state + sym : state];
+ }
+
+ public String toString() {
+
+ String s = "identifierStack : char[][] = {";
+ for (int i = 0; i <= identifierPtr; i++) {
+ s = s + "\"" + String.valueOf(identifierStack[i]) + "\",";
+ };
+ s = s + "}\n";
+
+ s = s + "identierLengthStack : int[] = {";
+ for (int i = 0; i <= identifierLengthPtr; i++) {
+ s = s + identifierLengthStack[i] + ",";
+ };
+ s = s + "}\n";
+
+ s = s + "astLengthStack : int[] = {";
+ for (int i = 0; i <= astLengthPtr; i++) {
+ s = s + astLengthStack[i] + ",";
+ };
+ s = s + "}\n";
+ s = s + "astPtr : int = " + String.valueOf(astPtr) + "\n";
+
+ s = s + "intStack : int[] = {";
+ for (int i = 0; i <= intPtr; i++) {
+ s = s + intStack[i] + ",";
+ };
+ s = s + "}\n";
+
+ s = s + "expressionLengthStack : int[] = {";
+ for (int i = 0; i <= expressionLengthPtr; i++) {
+ s = s + expressionLengthStack[i] + ",";
+ };
+ s = s + "}\n";
+
+ s = s + "expressionPtr : int = " + String.valueOf(expressionPtr) + "\n";
+
+ s = s + "\n\n\n----------------Scanner--------------\n" + scanner.toString();
+ return s;
+
+ }
+
+ /*
+ * Update recovery state based on current parser/scanner state
+ */
+ protected void updateRecoveryState() {
+
+ /* expose parser state to recovery state */
+ currentElement.updateFromParserState();
+
+ /* check and update recovered state based on current token,
+ this action is also performed when shifting token after recovery
+ got activated once.
+ */
+ this.recoveryTokenCheck();
+ }
+
+ protected void updateSourceDeclarationParts(int variableDeclaratorsCounter) {
+ //fields is a definition of fields that are grouped together like in
+ //public int[] a, b[], c
+ //which results into 3 fields.
+
+ FieldDeclaration field;
+ int endTypeDeclarationPosition =
+ -1 + astStack[astPtr - variableDeclaratorsCounter + 1].sourceStart();
+ for (int i = 0; i < variableDeclaratorsCounter - 1; i++) {
+ //last one is special(see below)
+ field = (FieldDeclaration) astStack[astPtr - i - 1];
+ field.endPart1Position = endTypeDeclarationPosition;
+ field.endPart2Position = -1 + astStack[astPtr - i].sourceStart();
+ }
+ //last one
+ (field = (FieldDeclaration) astStack[astPtr]).endPart1Position =
+ endTypeDeclarationPosition;
+ field.endPart2Position = field.declarationSourceEnd;
+
+ }
+
+ protected void updateSourcePosition(Expression exp) {
+ //update the source Position of the expression
+
+ //intStack : int int
+ //-->
+ //intStack :
+
+ exp.sourceEnd = intStack[intPtr--];
+ exp.sourceStart = intStack[intPtr--];
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ParserBasicInformation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ParserBasicInformation.java
new file mode 100644
index 0000000000..4841874c57
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ParserBasicInformation.java
@@ -0,0 +1,22 @@
+package org.eclipse.jdt.internal.compiler.parser;
+
+public interface ParserBasicInformation {
+
+ public final static int ERROR_SYMBOL = 304,
+ MAX_NAME_LENGTH = 36,
+ NUM_STATES = 586,
+ NT_OFFSET = 305,
+ SCOPE_UBOUND = -1,
+ SCOPE_SIZE = 0,
+ LA_STATE_OFFSET = 17754,
+ MAX_LA = 1,
+ NUM_RULES = 431,
+ NUM_TERMINALS = 104,
+ NUM_NON_TERMINALS = 201,
+ NUM_SYMBOLS = 305,
+ START_STATE = 12614,
+ EOFT_SYMBOL = 156,
+ EOLT_SYMBOL = 156,
+ ACCEPT_ACTION = 17753,
+ ERROR_ACTION = 17754;
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredBlock.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredBlock.java
new file mode 100644
index 0000000000..f901cc3344
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredBlock.java
@@ -0,0 +1,292 @@
+package org.eclipse.jdt.internal.compiler.parser;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/**
+ * Internal block structure for parsing recovery
+ */
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class RecoveredBlock
+ extends RecoveredStatement
+ implements CompilerModifiers, TerminalSymbols {
+
+ public Block blockDeclaration;
+
+ public RecoveredStatement[] statements;
+ public int statementCount;
+
+ public boolean preserveContent = false;
+ public RecoveredLocalVariable pendingArgument;
+ public RecoveredBlock(
+ Block block,
+ RecoveredElement parent,
+ int bracketBalance) {
+ super(block, parent, bracketBalance);
+ this.blockDeclaration = block;
+ this.foundOpeningBrace = true;
+ }
+
+ /*
+ * Record a nested block declaration
+ */
+ public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalance) {
+
+ /* do not consider a nested block starting passed the block end (if set)
+ it must be belonging to an enclosing block */
+ if (blockDeclaration.sourceEnd != 0
+ && nestedBlockDeclaration.sourceStart > blockDeclaration.sourceEnd) {
+ return this.parent.add(nestedBlockDeclaration, bracketBalance);
+ }
+
+ RecoveredBlock element =
+ new RecoveredBlock(nestedBlockDeclaration, this, bracketBalance);
+
+ // if we have a pending Argument, promote it into the new block
+ if (pendingArgument != null) {
+ element.attach(pendingArgument);
+ pendingArgument = null;
+ }
+ this.attach(element);
+ if (nestedBlockDeclaration.sourceEnd == 0)
+ return element;
+ return this;
+ }
+
+ /*
+ * Record a local declaration
+ */
+ public RecoveredElement add(
+ LocalDeclaration localDeclaration,
+ int bracketBalance) {
+
+ /* do not consider a local variable starting passed the block end (if set)
+ it must be belonging to an enclosing block */
+ if (blockDeclaration.sourceEnd != 0
+ && localDeclaration.declarationSourceStart > blockDeclaration.sourceEnd) {
+ return this.parent.add(localDeclaration, bracketBalance);
+ }
+
+ RecoveredLocalVariable element =
+ new RecoveredLocalVariable(localDeclaration, this, bracketBalance);
+
+ if (localDeclaration instanceof Argument) {
+ pendingArgument = element;
+ return this;
+ }
+
+ this.attach(element);
+ if (localDeclaration.declarationSourceEnd == 0)
+ return element;
+ return this;
+ }
+
+ /*
+ * Record a statement declaration
+ */
+ public RecoveredElement add(Statement statement, int bracketBalance) {
+
+ /* do not consider a nested block starting passed the block end (if set)
+ it must be belonging to an enclosing block */
+ if (blockDeclaration.sourceEnd != 0
+ && statement.sourceStart > blockDeclaration.sourceEnd) {
+ return this.parent.add(statement, bracketBalance);
+ }
+
+ RecoveredStatement element =
+ new RecoveredStatement(statement, this, bracketBalance);
+ this.attach(element);
+ if (statement.sourceEnd == 0)
+ return element;
+ return this;
+ }
+
+ /*
+ * Addition of a type to an initializer (act like inside method body)
+ */
+ public RecoveredElement add(
+ TypeDeclaration typeDeclaration,
+ int bracketBalance) {
+
+ /* do not consider a type starting passed the block end (if set)
+ it must be belonging to an enclosing block */
+ if (blockDeclaration.sourceEnd != 0
+ && typeDeclaration.declarationSourceStart > blockDeclaration.sourceEnd) {
+ return this.parent.add(typeDeclaration, bracketBalance);
+ }
+
+ RecoveredStatement element =
+ new RecoveredType(typeDeclaration, this, bracketBalance);
+ this.attach(element);
+ if (typeDeclaration.declarationSourceEnd == 0)
+ return element;
+ return this;
+ }
+
+ /*
+ * Attach a recovered statement
+ */
+ void attach(RecoveredStatement recoveredStatement) {
+
+ if (statements == null) {
+ statements = new RecoveredStatement[5];
+ statementCount = 0;
+ } else {
+ if (statementCount == statements.length) {
+ System.arraycopy(
+ statements,
+ 0,
+ (statements = new RecoveredStatement[2 * statementCount]),
+ 0,
+ statementCount);
+ }
+ }
+ statements[statementCount++] = recoveredStatement;
+ }
+
+ /*
+ * Answer the associated parsed structure
+ */
+ public AstNode parseTree() {
+ return blockDeclaration;
+ }
+
+ public String toString(int tab) {
+ StringBuffer result = new StringBuffer(tabString(tab));
+ result.append("Recovered block:\n");
+ result.append(blockDeclaration.toString(tab + 1));
+ if (this.statements != null) {
+ for (int i = 0; i < this.statementCount; i++) {
+ result.append("\n");
+ result.append(this.statements[i].toString(tab + 1));
+ }
+ }
+ return result.toString();
+ }
+
+ /*
+ * Rebuild a block from the nested structure which is in scope
+ */
+ public Block updatedBlock() {
+
+ // if block was not marked to be preserved or empty, then ignore it
+ if (!preserveContent || statementCount == 0)
+ return null;
+
+ Statement[] updatedStatements = new Statement[statementCount];
+ int updatedCount = 0;
+
+ // only collect the non-null updated statements
+ for (int i = 0; i < statementCount; i++) {
+ Statement updatedStatement = statements[i].updatedStatement();
+ if (updatedStatement != null) {
+ updatedStatements[updatedCount++] = updatedStatement;
+ }
+ }
+ if (updatedCount == 0)
+ return null; // not interesting block
+
+ // resize statement collection if necessary
+ if (updatedCount != statementCount) {
+ blockDeclaration.statements = new Statement[updatedCount];
+ System.arraycopy(
+ updatedStatements,
+ 0,
+ blockDeclaration.statements,
+ 0,
+ updatedCount);
+ } else {
+ blockDeclaration.statements = updatedStatements;
+ }
+
+ return blockDeclaration;
+ }
+
+ /*
+ * Rebuild a statement from the nested structure which is in scope
+ */
+ public Statement updatedStatement() {
+
+ return this.updatedBlock();
+ }
+
+ /*
+ * A closing brace got consumed, might have closed the current element,
+ * in which case both the currentElement is exited
+ */
+ public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd) {
+ if ((--bracketBalance <= 0) && (parent != null)) {
+ this.updateSourceEndIfNecessary(braceEnd);
+
+ /* if the block is the method body, then it closes the method too */
+ RecoveredMethod method = enclosingMethod();
+ if (method != null && method.methodBody == this) {
+ return parent.updateOnClosingBrace(braceStart, braceEnd);
+ }
+ return parent;
+ }
+ return this;
+ }
+
+ /*
+ * An opening brace got consumed, might be the expected opening one of the current element,
+ * in which case the bodyStart is updated.
+ */
+ public RecoveredElement updateOnOpeningBrace(int currentPosition) {
+
+ // create a nested block
+ Block block = new Block(0);
+ block.sourceStart = parser().scanner.startPosition;
+ return this.add(block, 1);
+ }
+
+ /*
+ * Final update the corresponding parse node
+ */
+ public void updateParseTree() {
+
+ this.updatedBlock();
+ }
+
+ /*
+ * Rebuild a flattened block from the nested structure which is in scope
+ */
+ public Statement updateStatement() {
+
+ // if block was closed or empty, then ignore it
+ if (this.blockDeclaration.sourceEnd != 0 || statementCount == 0)
+ return null;
+
+ Statement[] updatedStatements = new Statement[statementCount];
+ int updatedCount = 0;
+
+ // only collect the non-null updated statements
+ for (int i = 0; i < statementCount; i++) {
+ Statement updatedStatement = statements[i].updatedStatement();
+ if (updatedStatement != null) {
+ updatedStatements[updatedCount++] = updatedStatement;
+ }
+ }
+ if (updatedCount == 0)
+ return null; // not interesting block
+
+ // resize statement collection if necessary
+ if (updatedCount != statementCount) {
+ blockDeclaration.statements = new Statement[updatedCount];
+ System.arraycopy(
+ updatedStatements,
+ 0,
+ blockDeclaration.statements,
+ 0,
+ updatedCount);
+ } else {
+ blockDeclaration.statements = updatedStatements;
+ }
+
+ return blockDeclaration;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredElement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredElement.java
new file mode 100644
index 0000000000..2758263c51
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredElement.java
@@ -0,0 +1,349 @@
+package org.eclipse.jdt.internal.compiler.parser;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/**
+ * Internal structure for parsing recovery
+ */
+import org.eclipse.jdt.internal.compiler.ast.*;
+
+public class RecoveredElement {
+
+ public RecoveredElement parent;
+ public int bracketBalance;
+ public boolean foundOpeningBrace;
+ private Parser recoveringParser;
+ public RecoveredElement(RecoveredElement parent, int bracketBalance) {
+ this(parent, bracketBalance, null);
+ }
+
+ public RecoveredElement(
+ RecoveredElement parent,
+ int bracketBalance,
+ Parser parser) {
+ this.parent = parent;
+ this.bracketBalance = bracketBalance;
+ this.recoveringParser = parser;
+ }
+
+ /*
+ * Record a method declaration
+ */
+ public RecoveredElement add(
+ AbstractMethodDeclaration methodDeclaration,
+ int bracketBalance) {
+
+ /* default behavior is to delegate recording to parent if any */
+ if (parent == null) {
+ return this; // ignore
+ } else {
+ this.updateSourceEndIfNecessary(
+ this.previousAvailableLineEnd(methodDeclaration.declarationSourceStart - 1));
+ return this.parent.add(methodDeclaration, bracketBalance);
+ }
+ }
+
+ /*
+ * Record a nested block declaration
+ */
+ public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalance) {
+
+ /* default behavior is to delegate recording to parent if any */
+ if (parent == null) {
+ return this; // ignore
+ } else {
+ this.updateSourceEndIfNecessary(
+ this.previousAvailableLineEnd(nestedBlockDeclaration.sourceStart - 1));
+ return this.parent.add(nestedBlockDeclaration, bracketBalance);
+ }
+ }
+
+ /*
+ * Record a field declaration
+ */
+ public RecoveredElement add(
+ FieldDeclaration fieldDeclaration,
+ int bracketBalance) {
+
+ /* default behavior is to delegate recording to parent if any */
+ if (parent == null) {
+ return this; // ignore
+ } else {
+ this.updateSourceEndIfNecessary(
+ this.previousAvailableLineEnd(fieldDeclaration.declarationSourceStart - 1));
+ return this.parent.add(fieldDeclaration, bracketBalance);
+ }
+ }
+
+ /*
+ * Record an import reference
+ */
+ public RecoveredElement add(
+ ImportReference importReference,
+ int bracketBalance) {
+
+ /* default behavior is to delegate recording to parent if any */
+ if (parent == null) {
+ return this; // ignore
+ } else {
+ this.updateSourceEndIfNecessary(
+ this.previousAvailableLineEnd(importReference.declarationSourceStart - 1));
+ return this.parent.add(importReference, bracketBalance);
+ }
+ }
+
+ /*
+ * Record a local declaration
+ */
+ public RecoveredElement add(
+ LocalDeclaration localDeclaration,
+ int bracketBalance) {
+
+ /* default behavior is to delegate recording to parent if any */
+ if (parent == null) {
+ return this; // ignore
+ } else {
+ this.updateSourceEndIfNecessary(
+ this.previousAvailableLineEnd(localDeclaration.declarationSourceStart - 1));
+ return this.parent.add(localDeclaration, bracketBalance);
+ }
+ }
+
+ /*
+ * Record a statement
+ */
+ public RecoveredElement add(Statement statement, int bracketBalance) {
+
+ /* default behavior is to delegate recording to parent if any */
+ if (parent == null) {
+ return this; // ignore
+ } else {
+ this.updateSourceEndIfNecessary(
+ this.previousAvailableLineEnd(statement.sourceStart - 1));
+ return this.parent.add(statement, bracketBalance);
+ }
+ }
+
+ /*
+ * Record a type declaration
+ */
+ public RecoveredElement add(
+ TypeDeclaration typeDeclaration,
+ int bracketBalance) {
+
+ /* default behavior is to delegate recording to parent if any */
+ if (parent == null) {
+ return this; // ignore
+ } else {
+ this.updateSourceEndIfNecessary(
+ this.previousAvailableLineEnd(typeDeclaration.declarationSourceStart - 1));
+ return this.parent.add(typeDeclaration, bracketBalance);
+ }
+ }
+
+ /*
+ * Answer the depth of this element, considering the parent link.
+ */
+ public int depth() {
+ int depth = 0;
+ RecoveredElement current = this;
+ while ((current = current.parent) != null)
+ depth++;
+ return depth;
+ }
+
+ /*
+ * Answer the enclosing method node, or null if none
+ */
+ public RecoveredMethod enclosingMethod() {
+ RecoveredElement current = this;
+ while (current != null) {
+ if (current instanceof RecoveredMethod) {
+ return (RecoveredMethod) current;
+ }
+ current = current.parent;
+ }
+ return null;
+ }
+
+ /*
+ * Answer the enclosing type node, or null if none
+ */
+ public RecoveredType enclosingType() {
+ RecoveredElement current = this;
+ while (current != null) {
+ if (current instanceof RecoveredType) {
+ return (RecoveredType) current;
+ }
+ current = current.parent;
+ }
+ return null;
+ }
+
+ /*
+ * Answer the closest specified parser
+ */
+ public Parser parser() {
+ RecoveredElement current = this;
+ while (current != null) {
+ if (current.recoveringParser != null) {
+ return current.recoveringParser;
+ }
+ current = current.parent;
+ }
+ return null;
+ }
+
+ /*
+ * Answer the associated parsed structure
+ */
+ public AstNode parseTree() {
+ return null;
+ }
+
+ /*
+ * Iterate the enclosing blocks and tag them so as to preserve their content
+ */
+ public void preserveEnclosingBlocks() {
+ RecoveredElement current = this;
+ while (current != null) {
+ if (current instanceof RecoveredBlock) {
+ ((RecoveredBlock) current).preserveContent = true;
+ }
+ if (current instanceof RecoveredType) { // for anonymous types
+ ((RecoveredType) current).preserveContent = true;
+ }
+ current = current.parent;
+ }
+ }
+
+ /*
+ * Answer the position of the previous line end if
+ * there is nothing but spaces in between it and the
+ * line end. Used to trim spaces on unclosed elements.
+ */
+ public int previousAvailableLineEnd(int position) {
+
+ Parser parser = this.parser();
+ if (parser == null)
+ return position;
+
+ Scanner scanner = parser.scanner;
+ if (scanner.lineEnds == null)
+ return position;
+
+ int index = scanner.searchLineNumber(position);
+ if (index < 2)
+ return position;
+ int previousLineEnd = scanner.lineEnds[index - 2];
+
+ char[] source = scanner.source;
+ for (int i = previousLineEnd + 1; i < position; i++) {
+ if (!(source[i] == ' ' || source[i] == '\t'))
+ return position;
+ }
+ return previousLineEnd;
+ }
+
+ /*
+ * Answer the very source end of the corresponding parse node
+ */
+ public int sourceEnd() {
+ return 0;
+ }
+
+ protected String tabString(int tab) {
+ StringBuffer result = new StringBuffer();
+ for (int i = tab; i > 0; i--) {
+ result.append(" ");
+ }
+ return result.toString();
+ }
+
+ /*
+ * Answer the top node
+ */
+ public RecoveredElement topElement() {
+ RecoveredElement current = this;
+ while (current.parent != null) {
+ current = current.parent;
+ }
+ return current;
+ }
+
+ public String toString() {
+ return toString(0);
+ }
+
+ public String toString(int tab) {
+ return super.toString();
+ }
+
+ /*
+ * Answer the enclosing type node, or null if none
+ */
+ public RecoveredType type() {
+ RecoveredElement current = this;
+ while (current != null) {
+ if (current instanceof RecoveredType) {
+ return (RecoveredType) current;
+ }
+ current = current.parent;
+ }
+ return null;
+ }
+
+ /*
+ * Update the bodyStart of the corresponding parse node
+ */
+ public void updateBodyStart(int bodyStart) {
+ this.foundOpeningBrace = true;
+ }
+
+ /*
+ * Update the corresponding parse node from parser state which
+ * is about to disappear because of restarting recovery
+ */
+ public void updateFromParserState() {
+ }
+
+ /*
+ * A closing brace got consumed, might have closed the current element,
+ * in which case both the currentElement is exited
+ */
+ public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd) {
+ if ((--bracketBalance <= 0) && (parent != null)) {
+ this.updateSourceEndIfNecessary(braceEnd);
+ return parent;
+ }
+ return this;
+ }
+
+ /*
+ * An opening brace got consumed, might be the expected opening one of the current element,
+ * in which case the bodyStart is updated.
+ */
+ public RecoveredElement updateOnOpeningBrace(int braceEnd) {
+
+ if (bracketBalance++ == 0) {
+ this.updateBodyStart(braceEnd + 1);
+ return this;
+ }
+ return null; // no update is necessary
+ }
+
+ /*
+ * Final update the corresponding parse node
+ */
+ public void updateParseTree() {
+ }
+
+ /*
+ * Update the declarationSourceEnd of the corresponding parse node
+ */
+ public void updateSourceEndIfNecessary(int sourceEnd) {
+ }
+
+}
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
new file mode 100644
index 0000000000..02efa11253
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredField.java
@@ -0,0 +1,182 @@
+package org.eclipse.jdt.internal.compiler.parser;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/**
+ * Internal field structure for parsing recovery
+ */
+import org.eclipse.jdt.internal.compiler.ast.*;
+
+public class RecoveredField extends RecoveredElement {
+
+ public FieldDeclaration fieldDeclaration;
+ boolean alreadyCompletedFieldInitialization;
+
+ public RecoveredType[] anonymousTypes;
+ public int anonymousTypeCount;
+ public RecoveredField(
+ FieldDeclaration fieldDeclaration,
+ RecoveredElement parent,
+ int bracketBalance) {
+ this(fieldDeclaration, parent, bracketBalance, null);
+ }
+
+ public RecoveredField(
+ FieldDeclaration fieldDeclaration,
+ RecoveredElement parent,
+ int bracketBalance,
+ Parser parser) {
+ super(parent, bracketBalance, parser);
+ this.fieldDeclaration = fieldDeclaration;
+ this.alreadyCompletedFieldInitialization =
+ fieldDeclaration.initialization != null;
+ }
+
+ /*
+ * Record an expression statement if field is expecting an initialization expression,
+ * used for completion inside field initializers.
+ */
+ public RecoveredElement add(Statement statement, int bracketBalance) {
+
+ if (this.alreadyCompletedFieldInitialization
+ || !(statement instanceof Expression)) {
+ return super.add(statement, bracketBalance);
+ } else {
+ this.alreadyCompletedFieldInitialization = true;
+ this.fieldDeclaration.initialization = (Expression) statement;
+ this.fieldDeclaration.declarationSourceEnd = statement.sourceEnd;
+ return this;
+ }
+ }
+
+ /*
+ * Record a type declaration if this field is expecting an initialization expression
+ * and the type is an anonymous type.
+ * Used for completion inside field initializers.
+ */
+ public RecoveredElement add(
+ TypeDeclaration typeDeclaration,
+ int bracketBalance) {
+
+ if (this.alreadyCompletedFieldInitialization
+ || !(typeDeclaration instanceof AnonymousLocalTypeDeclaration)
+ || (this.fieldDeclaration.declarationSourceEnd != 0
+ && typeDeclaration.sourceStart > this.fieldDeclaration.declarationSourceEnd)) {
+ return super.add(typeDeclaration, bracketBalance);
+ } else {
+ // Prepare anonymous type list
+ if (this.anonymousTypes == null) {
+ this.anonymousTypes = new RecoveredType[5];
+ this.anonymousTypeCount = 0;
+ } else {
+ if (this.anonymousTypeCount == this.anonymousTypes.length) {
+ System.arraycopy(
+ this.anonymousTypes,
+ 0,
+ (this.anonymousTypes = new RecoveredType[2 * this.anonymousTypeCount]),
+ 0,
+ this.anonymousTypeCount);
+ }
+ }
+ // Store type declaration as an anonymous type
+ RecoveredType element =
+ new RecoveredType(typeDeclaration, this, bracketBalance);
+ this.anonymousTypes[this.anonymousTypeCount++] = element;
+ return element;
+ }
+ }
+
+ /*
+ * Answer the associated parsed structure
+ */
+ public AstNode parseTree() {
+ return fieldDeclaration;
+ }
+
+ /*
+ * Answer the very source end of the corresponding parse node
+ */
+ public int sourceEnd() {
+ return this.fieldDeclaration.declarationSourceEnd;
+ }
+
+ public String toString(int tab) {
+ StringBuffer buffer = new StringBuffer(tabString(tab));
+ buffer.append("Recovered field:\n");
+ buffer.append(fieldDeclaration.toString(tab + 1));
+ if (this.anonymousTypes != null) {
+ for (int i = 0; i < this.anonymousTypeCount; i++) {
+ buffer.append("\n");
+ buffer.append(anonymousTypes[i].toString(tab + 1));
+ }
+ }
+ return buffer.toString();
+ }
+
+ public FieldDeclaration updatedFieldDeclaration() {
+
+ if (this.anonymousTypes != null && fieldDeclaration.initialization == null) {
+ for (int i = 0; i < this.anonymousTypeCount; i++) {
+ if (anonymousTypes[i].preserveContent) {
+ fieldDeclaration.initialization =
+ (
+ (AnonymousLocalTypeDeclaration) this
+ .anonymousTypes[i]
+ .updatedTypeDeclaration())
+ .allocation;
+ }
+ }
+ }
+ return fieldDeclaration;
+ }
+
+ /*
+ * A closing brace got consumed, might have closed the current element,
+ * in which case both the currentElement is exited.
+ *
+ * Fields have no associated braces, thus if matches, then update parent.
+ */
+ public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd) {
+ if (bracketBalance > 0) { // was an array initializer
+ bracketBalance--;
+ if (bracketBalance == 0)
+ alreadyCompletedFieldInitialization = true;
+ return this;
+ }
+ if (parent != null) {
+ return parent.updateOnClosingBrace(braceStart, braceEnd);
+ }
+ return this;
+ }
+
+ /*
+ * An opening brace got consumed, might be the expected opening one of the current element,
+ * in which case the bodyStart is updated.
+ */
+ public RecoveredElement updateOnOpeningBrace(int currentPosition) {
+ if (fieldDeclaration.declarationSourceEnd == 0
+ && fieldDeclaration.type instanceof ArrayTypeReference
+ && !alreadyCompletedFieldInitialization) {
+ bracketBalance++;
+ return null; // no update is necessary (array initializer)
+ }
+ // might be an array initializer
+ this.updateSourceEndIfNecessary(currentPosition - 1);
+ return this.parent.updateOnOpeningBrace(currentPosition);
+ }
+
+ public void updateParseTree() {
+ this.updatedFieldDeclaration();
+ }
+
+ /*
+ * Update the declarationSourceEnd of the corresponding parse node
+ */
+ public void updateSourceEndIfNecessary(int sourceEnd) {
+ if (this.fieldDeclaration.declarationSourceEnd == 0)
+ this.fieldDeclaration.declarationSourceEnd = sourceEnd;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredImport.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredImport.java
new file mode 100644
index 0000000000..2a4020855b
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredImport.java
@@ -0,0 +1,58 @@
+package org.eclipse.jdt.internal.compiler.parser;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/**
+ * Internal import structure for parsing recovery
+ */
+import org.eclipse.jdt.internal.compiler.ast.*;
+
+public class RecoveredImport extends RecoveredElement {
+
+ public ImportReference importReference;
+ public RecoveredImport(
+ ImportReference importReference,
+ RecoveredElement parent,
+ int bracketBalance) {
+ super(parent, bracketBalance);
+ this.importReference = importReference;
+ }
+
+ /*
+ * Answer the associated parsed structure
+ */
+ public AstNode parseTree() {
+ return importReference;
+ }
+
+ /*
+ * Answer the very source end of the corresponding parse node
+ */
+ public int sourceEnd() {
+ return this.importReference.declarationSourceEnd;
+ }
+
+ public String toString(int tab) {
+ return tabString(tab) + "Recovered import: " + importReference.toString();
+ }
+
+ public ImportReference updatedImportReference() {
+
+ return importReference;
+ }
+
+ public void updateParseTree() {
+ this.updatedImportReference();
+ }
+
+ /*
+ * Update the declarationSourceEnd of the corresponding parse node
+ */
+ public void updateSourceEndIfNecessary(int sourceEnd) {
+ if (this.importReference.declarationSourceEnd == 0)
+ this.importReference.declarationSourceEnd = sourceEnd;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredInitializer.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredInitializer.java
new file mode 100644
index 0000000000..ffdc149669
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredInitializer.java
@@ -0,0 +1,243 @@
+package org.eclipse.jdt.internal.compiler.parser;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/**
+ * Internal initializer structure for parsing recovery
+ */
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class RecoveredInitializer
+ extends RecoveredField
+ implements CompilerModifiers, TerminalSymbols, BaseTypes {
+
+ public RecoveredType[] localTypes;
+ public int localTypeCount;
+
+ public RecoveredBlock initializerBody;
+ public RecoveredInitializer(
+ FieldDeclaration fieldDeclaration,
+ RecoveredElement parent,
+ int bracketBalance) {
+ this(fieldDeclaration, parent, bracketBalance, null);
+ }
+
+ public RecoveredInitializer(
+ FieldDeclaration fieldDeclaration,
+ RecoveredElement parent,
+ int bracketBalance,
+ Parser parser) {
+ super(fieldDeclaration, parent, bracketBalance, parser);
+ this.foundOpeningBrace = true;
+ }
+
+ /*
+ * Record a nested block declaration
+ */
+ public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalance) {
+
+ /* default behavior is to delegate recording to parent if any,
+ do not consider elements passed the known end (if set)
+ it must be belonging to an enclosing element
+ */
+ if (fieldDeclaration.declarationSourceEnd > 0
+ && nestedBlockDeclaration.sourceStart > fieldDeclaration.declarationSourceEnd) {
+ return this.parent.add(nestedBlockDeclaration, bracketBalance);
+ }
+ /* consider that if the opening brace was not found, it is there */
+ if (!foundOpeningBrace) {
+ foundOpeningBrace = true;
+ this.bracketBalance++;
+ }
+
+ initializerBody =
+ new RecoveredBlock(nestedBlockDeclaration, this, bracketBalance);
+ if (nestedBlockDeclaration.sourceEnd == 0)
+ return initializerBody;
+ return this;
+ }
+
+ /*
+ * Record a field declaration (act like inside method body)
+ */
+ public RecoveredElement add(
+ FieldDeclaration newFieldDeclaration,
+ int bracketBalance) {
+
+ /* local variables inside initializer can only be final and non void */
+ char[][] fieldTypeName;
+ if ((newFieldDeclaration.modifiers & ~AccFinal) != 0
+ /* local var can only be final */
+ || (newFieldDeclaration.type == null) // initializer
+ || ((fieldTypeName = newFieldDeclaration.type.getTypeName()).length == 1
+ // non void
+ && CharOperation.equals(fieldTypeName[0], VoidBinding.sourceName()))) {
+ this.updateSourceEndIfNecessary(
+ this.previousAvailableLineEnd(newFieldDeclaration.declarationSourceStart - 1));
+ return this.parent.add(newFieldDeclaration, bracketBalance);
+ }
+
+ /* default behavior is to delegate recording to parent if any,
+ do not consider elements passed the known end (if set)
+ it must be belonging to an enclosing element
+ */
+ if (this.fieldDeclaration.declarationSourceEnd > 0
+ && newFieldDeclaration.declarationSourceStart
+ > this.fieldDeclaration.declarationSourceEnd) {
+ return this.parent.add(newFieldDeclaration, bracketBalance);
+ }
+ // still inside initializer, treat as local variable
+ return this; // ignore
+ }
+
+ /*
+ * Record a local declaration - regular method should have been created a block body
+ */
+ public RecoveredElement add(
+ LocalDeclaration localDeclaration,
+ int bracketBalance) {
+
+ /* do not consider a type starting passed the type end (if set)
+ it must be belonging to an enclosing type */
+ if (fieldDeclaration.declarationSourceEnd != 0
+ && localDeclaration.declarationSourceStart
+ > fieldDeclaration.declarationSourceEnd) {
+ if (parent == null) {
+ return this; // ignore
+ } else {
+ return this.parent.add(localDeclaration, bracketBalance);
+ }
+ }
+ /* method body should have been created */
+ Block block = new Block(0);
+ block.sourceStart = ((Initializer) fieldDeclaration).bodyStart;
+ RecoveredElement element = this.add(block, 1);
+ return element.add(localDeclaration, bracketBalance);
+ }
+
+ /*
+ * Record a statement - regular method should have been created a block body
+ */
+ public RecoveredElement add(Statement statement, int bracketBalance) {
+
+ /* do not consider a statement starting passed the initializer end (if set)
+ it must be belonging to an enclosing type */
+ if (fieldDeclaration.declarationSourceEnd != 0
+ && statement.sourceStart > fieldDeclaration.declarationSourceEnd) {
+ if (parent == null) {
+ return this; // ignore
+ } else {
+ return this.parent.add(statement, bracketBalance);
+ }
+ }
+ /* initializer body should have been created */
+ Block block = new Block(0);
+ block.sourceStart = ((Initializer) fieldDeclaration).bodyStart;
+ RecoveredElement element = this.add(block, 1);
+ return element.add(statement, bracketBalance);
+ }
+
+ public RecoveredElement add(
+ TypeDeclaration typeDeclaration,
+ int bracketBalance) {
+
+ /* do not consider a type starting passed the type end (if set)
+ it must be belonging to an enclosing type */
+ if (fieldDeclaration.declarationSourceEnd != 0
+ && typeDeclaration.declarationSourceStart
+ > fieldDeclaration.declarationSourceEnd) {
+ if (parent == null) {
+ return this; // ignore
+ } else {
+ return this.parent.add(typeDeclaration, bracketBalance);
+ }
+ }
+ if (typeDeclaration instanceof LocalTypeDeclaration) {
+ /* method body should have been created */
+ Block block = new Block(0);
+ block.sourceStart = ((Initializer) fieldDeclaration).bodyStart;
+ RecoveredElement element = this.add(block, 1);
+ return element.add(typeDeclaration, bracketBalance);
+ }
+ if (localTypes == null) {
+ localTypes = new RecoveredType[5];
+ localTypeCount = 0;
+ } else {
+ if (localTypeCount == localTypes.length) {
+ System.arraycopy(
+ localTypes,
+ 0,
+ (localTypes = new RecoveredType[2 * localTypeCount]),
+ 0,
+ localTypeCount);
+ }
+ }
+ RecoveredType element =
+ new RecoveredType(typeDeclaration, this, bracketBalance);
+ localTypes[localTypeCount++] = element;
+
+ /* consider that if the opening brace was not found, it is there */
+ if (!foundOpeningBrace) {
+ foundOpeningBrace = true;
+ this.bracketBalance++;
+ }
+ return element;
+ }
+
+ public String toString(int tab) {
+ StringBuffer result = new StringBuffer(tabString(tab));
+ result.append("Recovered initializer:\n");
+ result.append(this.fieldDeclaration.toString(tab + 1));
+ if (this.initializerBody != null) {
+ result.append("\n");
+ result.append(this.initializerBody.toString(tab + 1));
+ }
+ return result.toString();
+ }
+
+ public FieldDeclaration updatedFieldDeclaration() {
+
+ if (initializerBody != null) {
+ Block block = initializerBody.updatedBlock();
+ if (block != null) {
+ ((Initializer) fieldDeclaration).block = block;
+ }
+ }
+ return fieldDeclaration;
+ }
+
+ /*
+ * A closing brace got consumed, might have closed the current element,
+ * in which case both the currentElement is exited
+ */
+ public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd) {
+ if ((--bracketBalance <= 0) && (parent != null)) {
+ this.updateSourceEndIfNecessary(braceEnd);
+ return parent;
+ }
+ return this;
+ }
+
+ /*
+ * An opening brace got consumed, might be the expected opening one of the current element,
+ * in which case the bodyStart is updated.
+ */
+ public RecoveredElement updateOnOpeningBrace(int currentPosition) {
+ bracketBalance++;
+ return this; // request to restart
+ }
+
+ /*
+ * Update the declarationSourceEnd of the corresponding parse node
+ */
+ public void updateSourceEndIfNecessary(int sourceEnd) {
+ if (this.fieldDeclaration.declarationSourceEnd == 0)
+ this.fieldDeclaration.sourceEnd = sourceEnd;
+ this.fieldDeclaration.declarationSourceEnd = sourceEnd;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredLocalVariable.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredLocalVariable.java
new file mode 100644
index 0000000000..5e63b9c632
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredLocalVariable.java
@@ -0,0 +1,97 @@
+package org.eclipse.jdt.internal.compiler.parser;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/**
+ * Internal local variable structure for parsing recovery
+ */
+import org.eclipse.jdt.internal.compiler.ast.*;
+
+public class RecoveredLocalVariable extends RecoveredStatement {
+
+ public LocalDeclaration localDeclaration;
+ boolean alreadyCompletedLocalInitialization;
+ public RecoveredLocalVariable(
+ LocalDeclaration localDeclaration,
+ RecoveredElement parent,
+ int bracketBalance) {
+ super(localDeclaration, parent, bracketBalance);
+ this.localDeclaration = localDeclaration;
+ this.alreadyCompletedLocalInitialization =
+ localDeclaration.initialization != null;
+ }
+
+ /*
+ * Answer the associated parsed structure
+ */
+ public AstNode parseTree() {
+ return localDeclaration;
+ }
+
+ /*
+ * Answer the very source end of the corresponding parse node
+ */
+ public int sourceEnd() {
+ return this.localDeclaration.declarationSourceEnd;
+ }
+
+ public String toString(int tab) {
+ return tabString(tab)
+ + "Recovered local variable:\n"
+ + localDeclaration.toString(tab + 1);
+ }
+
+ public Statement updatedStatement() {
+ return localDeclaration;
+ }
+
+ /*
+ * A closing brace got consumed, might have closed the current element,
+ * in which case both the currentElement is exited.
+ *
+ * Fields have no associated braces, thus if matches, then update parent.
+ */
+ public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd) {
+ if (bracketBalance > 0) { // was an array initializer
+ bracketBalance--;
+ if (bracketBalance == 0)
+ alreadyCompletedLocalInitialization = true;
+ return this;
+ }
+ if (parent != null) {
+ return parent.updateOnClosingBrace(braceStart, braceEnd);
+ }
+ return this;
+ }
+
+ /*
+ * An opening brace got consumed, might be the expected opening one of the current element,
+ * in which case the bodyStart is updated.
+ */
+ public RecoveredElement updateOnOpeningBrace(int currentPosition) {
+ if (localDeclaration.declarationSourceEnd == 0
+ && localDeclaration.type instanceof ArrayTypeReference
+ && !alreadyCompletedLocalInitialization) {
+ bracketBalance++;
+ return null; // no update is necessary (array initializer)
+ }
+ // might be an array initializer
+ this.updateSourceEndIfNecessary(currentPosition - 1);
+ return this.parent.updateOnOpeningBrace(currentPosition);
+ }
+
+ public void updateParseTree() {
+ this.updatedStatement();
+ }
+
+ /*
+ * Update the declarationSourceEnd of the corresponding parse node
+ */
+ public void updateSourceEndIfNecessary(int sourceEnd) {
+ if (this.localDeclaration.declarationSourceEnd == 0)
+ this.localDeclaration.declarationSourceEnd = sourceEnd;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredMethod.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredMethod.java
new file mode 100644
index 0000000000..bc83e61338
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredMethod.java
@@ -0,0 +1,368 @@
+package org.eclipse.jdt.internal.compiler.parser;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+/**
+ * Internal method structure for parsing recovery
+ */
+
+public class RecoveredMethod
+ extends RecoveredElement
+ implements CompilerModifiers, TerminalSymbols, BaseTypes {
+
+ public AbstractMethodDeclaration methodDeclaration;
+
+ public RecoveredType[] localTypes;
+ public int localTypeCount;
+
+ public RecoveredBlock methodBody;
+ public boolean discardBody = true;
+ public RecoveredMethod(
+ AbstractMethodDeclaration methodDeclaration,
+ RecoveredElement parent,
+ int bracketBalance) {
+ this(methodDeclaration, parent, bracketBalance, null);
+ }
+
+ public RecoveredMethod(
+ AbstractMethodDeclaration methodDeclaration,
+ RecoveredElement parent,
+ int bracketBalance,
+ Parser parser) {
+ super(parent, bracketBalance, parser);
+ this.methodDeclaration = methodDeclaration;
+ this.foundOpeningBrace = !bodyStartsAtHeaderEnd();
+ if (this.foundOpeningBrace) {
+ this.bracketBalance++;
+ }
+ }
+
+ /*
+ * Record a nested block declaration
+ */
+ public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalance) {
+
+ /* default behavior is to delegate recording to parent if any,
+ do not consider elements passed the known end (if set)
+ it must be belonging to an enclosing element
+ */
+ if (methodDeclaration.declarationSourceEnd > 0
+ && nestedBlockDeclaration.sourceStart > methodDeclaration.declarationSourceEnd) {
+ return this.parent.add(nestedBlockDeclaration, bracketBalance);
+ }
+ /* consider that if the opening brace was not found, it is there */
+ if (!foundOpeningBrace) {
+ foundOpeningBrace = true;
+ this.bracketBalance++;
+ }
+
+ methodBody = new RecoveredBlock(nestedBlockDeclaration, this, bracketBalance);
+ if (nestedBlockDeclaration.sourceEnd == 0)
+ return methodBody;
+ return this;
+ }
+
+ /*
+ * Record a field declaration
+ */
+ public RecoveredElement add(
+ FieldDeclaration fieldDeclaration,
+ int bracketBalance) {
+
+ /* local variables inside method can only be final and non void */
+ char[][] fieldTypeName;
+ if ((fieldDeclaration.modifiers & ~AccFinal) != 0
+ /* local var can only be final */
+ || (fieldDeclaration.type == null) // initializer
+ || ((fieldTypeName = fieldDeclaration.type.getTypeName()).length == 1
+ // non void
+ && CharOperation.equals(fieldTypeName[0], VoidBinding.sourceName()))) {
+ this.updateSourceEndIfNecessary(
+ this.previousAvailableLineEnd(fieldDeclaration.declarationSourceStart - 1));
+ return this.parent.add(fieldDeclaration, bracketBalance);
+ }
+ /* default behavior is to delegate recording to parent if any,
+ do not consider elements passed the known end (if set)
+ it must be belonging to an enclosing element
+ */
+ if (methodDeclaration.declarationSourceEnd > 0
+ && fieldDeclaration.declarationSourceStart
+ > methodDeclaration.declarationSourceEnd) {
+ return this.parent.add(fieldDeclaration, bracketBalance);
+ }
+ /* consider that if the opening brace was not found, it is there */
+ if (!foundOpeningBrace) {
+ foundOpeningBrace = true;
+ this.bracketBalance++;
+ }
+ // still inside method, treat as local variable
+ return this; // ignore
+ }
+
+ /*
+ * Record a local declaration - regular method should have been created a block body
+ */
+ public RecoveredElement add(
+ LocalDeclaration localDeclaration,
+ int bracketBalance) {
+
+ /* do not consider a type starting passed the type end (if set)
+ it must be belonging to an enclosing type */
+ if (methodDeclaration.declarationSourceEnd != 0
+ && localDeclaration.declarationSourceStart
+ > methodDeclaration.declarationSourceEnd) {
+ if (parent == null) {
+ return this; // ignore
+ } else {
+ return this.parent.add(localDeclaration, bracketBalance);
+ }
+ }
+ /* method body should have been created */
+ Block block = new Block(0);
+ block.sourceStart = methodDeclaration.bodyStart;
+ RecoveredElement element = this.add(block, 1);
+ return element.add(localDeclaration, bracketBalance);
+ }
+
+ /*
+ * Record a statement - regular method should have been created a block body
+ */
+ public RecoveredElement add(Statement statement, int bracketBalance) {
+
+ /* do not consider a type starting passed the type end (if set)
+ it must be belonging to an enclosing type */
+ if (methodDeclaration.declarationSourceEnd != 0
+ && statement.sourceStart > methodDeclaration.declarationSourceEnd) {
+ if (parent == null) {
+ return this; // ignore
+ } else {
+ return this.parent.add(statement, bracketBalance);
+ }
+ }
+ /* method body should have been created */
+ Block block = new Block(0);
+ block.sourceStart = methodDeclaration.bodyStart;
+ RecoveredElement element = this.add(block, 1);
+ return element.add(statement, bracketBalance);
+ }
+
+ public RecoveredElement add(
+ TypeDeclaration typeDeclaration,
+ int bracketBalance) {
+
+ /* do not consider a type starting passed the type end (if set)
+ it must be belonging to an enclosing type */
+ if (methodDeclaration.declarationSourceEnd != 0
+ && typeDeclaration.declarationSourceStart
+ > methodDeclaration.declarationSourceEnd) {
+ if (parent == null) {
+ return this; // ignore
+ } else {
+ return this.parent.add(typeDeclaration, bracketBalance);
+ }
+ }
+ if (typeDeclaration instanceof LocalTypeDeclaration) {
+ /* method body should have been created */
+ Block block = new Block(0);
+ block.sourceStart = methodDeclaration.bodyStart;
+ RecoveredElement element = this.add(block, 1);
+ return element.add(typeDeclaration, bracketBalance);
+ }
+ if (localTypes == null) {
+ localTypes = new RecoveredType[5];
+ localTypeCount = 0;
+ } else {
+ if (localTypeCount == localTypes.length) {
+ System.arraycopy(
+ localTypes,
+ 0,
+ (localTypes = new RecoveredType[2 * localTypeCount]),
+ 0,
+ localTypeCount);
+ }
+ }
+ RecoveredType element =
+ new RecoveredType(typeDeclaration, this, bracketBalance);
+ localTypes[localTypeCount++] = element;
+
+ /* consider that if the opening brace was not found, it is there */
+ if (!foundOpeningBrace) {
+ foundOpeningBrace = true;
+ this.bracketBalance++;
+ }
+ return element;
+ }
+
+ public boolean bodyStartsAtHeaderEnd() {
+ return methodDeclaration.bodyStart == methodDeclaration.sourceEnd + 1;
+ }
+
+ /*
+ * Answer the associated parsed structure
+ */
+ public AstNode parseTree() {
+ return methodDeclaration;
+ }
+
+ /*
+ * Answer the very source end of the corresponding parse node
+ */
+ public int sourceEnd() {
+ return this.methodDeclaration.declarationSourceEnd;
+ }
+
+ public String toString(int tab) {
+ StringBuffer result = new StringBuffer(tabString(tab));
+ result.append("Recovered method:\n");
+ result.append(this.methodDeclaration.toString(tab + 1));
+ if (this.localTypes != null) {
+ for (int i = 0; i < this.localTypeCount; i++) {
+ result.append("\n");
+ result.append(this.localTypes[i].toString(tab + 1));
+ }
+ }
+ if (this.methodBody != null) {
+ result.append("\n");
+ result.append(this.methodBody.toString(tab + 1));
+ }
+ return result.toString();
+ }
+
+ /*
+ * Update the bodyStart of the corresponding parse node
+ */
+ public void updateBodyStart(int bodyStart) {
+ this.foundOpeningBrace = true;
+ this.methodDeclaration.bodyStart = bodyStart;
+ }
+
+ public AbstractMethodDeclaration updatedMethodDeclaration() {
+
+ if (methodBody != null) {
+ Block block = methodBody.updatedBlock();
+ if (block != null) {
+ methodDeclaration.statements = block.statements;
+
+ /* first statement might be an explict constructor call destinated to a special slot */
+ if (methodDeclaration.isConstructor()
+ && methodDeclaration.statements != null
+ && methodDeclaration.statements[0] instanceof ExplicitConstructorCall) {
+ ((ConstructorDeclaration) methodDeclaration).constructorCall =
+ (ExplicitConstructorCall) methodDeclaration.statements[0];
+ int length = methodDeclaration.statements.length;
+ System.arraycopy(
+ methodDeclaration.statements,
+ 1,
+ (methodDeclaration.statements = new Statement[length - 1]),
+ 0,
+ length - 1);
+ }
+ }
+ }
+ return methodDeclaration;
+ }
+
+ /*
+ * Update the corresponding parse node from parser state which
+ * is about to disappear because of restarting recovery
+ */
+ public void updateFromParserState() {
+
+ if (this.bodyStartsAtHeaderEnd()) {
+ Parser parser = this.parser();
+ /* might want to recover arguments or thrown exceptions */
+ if (parser.listLength > 0) { // awaiting interface type references
+ /* has consumed the arguments - listed elements must be thrown exceptions */
+ if (methodDeclaration.sourceEnd == parser.rParenPos) {
+ parser.consumeMethodHeaderThrowsClause();
+ // will reset typeListLength to zero
+ // thus this check will only be performed on first errorCheck after void foo() throws X, Y,
+ } else {
+ /* has not consumed arguments yet, listed elements must be arguments */
+ if (parser.currentToken == TokenNameLPAREN
+ || parser.currentToken == TokenNameSEMICOLON) {
+ /* if currentToken is parenthesis this last argument is a method/field signature */
+ parser.astLengthStack[parser.astLengthPtr]--;
+ parser.astPtr--;
+ parser.listLength--;
+ parser.currentToken = 0;
+ }
+ int argLength = parser.astLengthStack[parser.astLengthPtr];
+ int argStart = parser.astPtr - argLength + 1;
+ int count;
+ for (count = 0; count < argLength; count++) {
+ Argument argument = (Argument) parser.astStack[argStart + count];
+ /* cannot be an argument if non final */
+ char[][] argTypeName = argument.type.getTypeName();
+ if ((argument.modifiers & ~AccFinal) != 0
+ || (argTypeName.length == 1
+ && CharOperation.equals(argTypeName[0], VoidBinding.sourceName()))) {
+ parser.astLengthStack[parser.astLengthPtr] = count - 1;
+ parser.astPtr = argStart + count - 1;
+ parser.listLength = count - 1;
+ parser.currentToken = 0;
+ break;
+ }
+ count++;
+ }
+ if (parser.listLength > 0) {
+ parser.consumeMethodHeaderParameters();
+ /* fix-up positions, given they were updated against rParenPos, which did not get set */
+ if (parser.currentElement == this) {
+ // parameter addition might have added an awaiting (no return type) method - see 1FVXQZ4 */
+ methodDeclaration.sourceEnd =
+ methodDeclaration.arguments[methodDeclaration.arguments.length - 1].sourceEnd;
+ methodDeclaration.bodyStart = methodDeclaration.sourceEnd + 1;
+ parser.lastCheckPoint = methodDeclaration.bodyStart;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * An opening brace got consumed, might be the expected opening one of the current element,
+ * in which case the bodyStart is updated.
+ */
+ public RecoveredElement updateOnOpeningBrace(int braceEnd) {
+
+ /* in case the opening brace is close enough to the signature */
+ if (bracketBalance == 0) {
+ /*
+ if (parser.scanner.searchLineNumber(methodDeclaration.sourceEnd)
+ != parser.scanner.searchLineNumber(braceEnd)){
+ */
+ switch (parser().lastIgnoredToken) {
+ case -1 :
+ case TokenNamethrows :
+ break;
+ default :
+ this.foundOpeningBrace = true;
+ bracketBalance = 1; // pretend the brace was already there
+ }
+ }
+ return super.updateOnOpeningBrace(braceEnd);
+ }
+
+ public void updateParseTree() {
+ this.updatedMethodDeclaration();
+ }
+
+ /*
+ * Update the declarationSourceEnd of the corresponding parse node
+ */
+ public void updateSourceEndIfNecessary(int sourceEnd) {
+ if (this.methodDeclaration.declarationSourceEnd == 0) {
+ this.methodDeclaration.declarationSourceEnd = sourceEnd;
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredStatement.java
new file mode 100644
index 0000000000..23c8143821
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredStatement.java
@@ -0,0 +1,58 @@
+package org.eclipse.jdt.internal.compiler.parser;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/**
+ * Internal statement structure for parsing recovery
+ */
+import org.eclipse.jdt.internal.compiler.ast.*;
+
+public class RecoveredStatement extends RecoveredElement {
+
+ public Statement statement;
+ boolean alreadyCompletedLocalInitialization;
+ public RecoveredStatement(
+ Statement statement,
+ RecoveredElement parent,
+ int bracketBalance) {
+ super(parent, bracketBalance);
+ this.statement = statement;
+ }
+
+ /*
+ * Answer the associated parsed structure
+ */
+ public AstNode parseTree() {
+ return statement;
+ }
+
+ /*
+ * Answer the very source end of the corresponding parse node
+ */
+ public int sourceEnd() {
+ return this.statement.sourceEnd;
+ }
+
+ public String toString(int tab) {
+ return tabString(tab) + "Recovered statement:\n" + statement.toString(tab + 1);
+ }
+
+ public Statement updatedStatement() {
+ return statement;
+ }
+
+ public void updateParseTree() {
+ this.updatedStatement();
+ }
+
+ /*
+ * Update the declarationSourceEnd of the corresponding parse node
+ */
+ public void updateSourceEndIfNecessary(int sourceEnd) {
+ if (this.statement.sourceEnd == 0)
+ this.statement.sourceEnd = sourceEnd;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredType.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredType.java
new file mode 100644
index 0000000000..1275337cbd
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredType.java
@@ -0,0 +1,511 @@
+package org.eclipse.jdt.internal.compiler.parser;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+/**
+ * Internal type structure for parsing recovery
+ */
+
+public class RecoveredType
+ extends RecoveredStatement
+ implements TerminalSymbols, CompilerModifiers {
+ public TypeDeclaration typeDeclaration;
+
+ public RecoveredType[] memberTypes;
+ public int memberTypeCount;
+ public RecoveredField[] fields;
+ public int fieldCount;
+ public RecoveredMethod[] methods;
+ public int methodCount;
+
+ public boolean preserveContent = false; // only used for anonymous types
+ public int bodyEnd;
+ public RecoveredType(
+ TypeDeclaration typeDeclaration,
+ RecoveredElement parent,
+ int bracketBalance) {
+ super(typeDeclaration, parent, bracketBalance);
+ this.typeDeclaration = typeDeclaration;
+ this.foundOpeningBrace = !bodyStartsAtHeaderEnd();
+ if (this.foundOpeningBrace) {
+ this.bracketBalance++;
+ }
+ }
+
+ public RecoveredElement add(
+ AbstractMethodDeclaration methodDeclaration,
+ int bracketBalance) {
+
+ /* do not consider a method starting passed the type end (if set)
+ it must be belonging to an enclosing type */
+ if (typeDeclaration.declarationSourceEnd != 0
+ && methodDeclaration.declarationSourceStart
+ > typeDeclaration.declarationSourceEnd) {
+ return this.parent.add(methodDeclaration, bracketBalance);
+ }
+
+ if (methods == null) {
+ methods = new RecoveredMethod[5];
+ methodCount = 0;
+ } else {
+ if (methodCount == methods.length) {
+ System.arraycopy(
+ methods,
+ 0,
+ (methods = new RecoveredMethod[2 * methodCount]),
+ 0,
+ methodCount);
+ }
+ }
+ RecoveredMethod element =
+ new RecoveredMethod(methodDeclaration, this, bracketBalance);
+ methods[methodCount++] = element;
+
+ /* consider that if the opening brace was not found, it is there */
+ if (!foundOpeningBrace) {
+ foundOpeningBrace = true;
+ this.bracketBalance++;
+ }
+ /* if method not finished, then method becomes current */
+ if (methodDeclaration.declarationSourceEnd == 0)
+ return element;
+ return this;
+ }
+
+ public RecoveredElement add(
+ FieldDeclaration fieldDeclaration,
+ int bracketBalance) {
+
+ /* do not consider a field starting passed the type end (if set)
+ it must be belonging to an enclosing type */
+ if (typeDeclaration.declarationSourceEnd != 0
+ && fieldDeclaration.declarationSourceStart
+ > typeDeclaration.declarationSourceEnd) {
+ return this.parent.add(fieldDeclaration, bracketBalance);
+ }
+ if (fields == null) {
+ fields = new RecoveredField[5];
+ fieldCount = 0;
+ } else {
+ if (fieldCount == fields.length) {
+ System.arraycopy(
+ fields,
+ 0,
+ (fields = new RecoveredField[2 * fieldCount]),
+ 0,
+ fieldCount);
+ }
+ }
+ RecoveredField element =
+ fieldDeclaration.isField()
+ ? new RecoveredField(fieldDeclaration, this, bracketBalance)
+ : new RecoveredInitializer(fieldDeclaration, this, bracketBalance);
+ fields[fieldCount++] = element;
+
+ /* consider that if the opening brace was not found, it is there */
+ if (!foundOpeningBrace) {
+ foundOpeningBrace = true;
+ this.bracketBalance++;
+ }
+ /* if field not finished, then field becomes current */
+ if (fieldDeclaration.declarationSourceEnd == 0)
+ return element;
+ return this;
+ }
+
+ public RecoveredElement add(
+ TypeDeclaration memberTypeDeclaration,
+ int bracketBalance) {
+
+ /* do not consider a type starting passed the type end (if set)
+ it must be belonging to an enclosing type */
+ if (typeDeclaration.declarationSourceEnd != 0
+ && memberTypeDeclaration.declarationSourceStart
+ > typeDeclaration.declarationSourceEnd) {
+ return this.parent.add(memberTypeDeclaration, bracketBalance);
+ }
+
+ if (memberTypes == null) {
+ memberTypes = new RecoveredType[5];
+ memberTypeCount = 0;
+ } else {
+ if (memberTypeCount == memberTypes.length) {
+ System.arraycopy(
+ memberTypes,
+ 0,
+ (memberTypes = new RecoveredType[2 * memberTypeCount]),
+ 0,
+ memberTypeCount);
+ }
+ }
+ RecoveredType element =
+ new RecoveredType(memberTypeDeclaration, this, bracketBalance);
+ memberTypes[memberTypeCount++] = element;
+
+ /* consider that if the opening brace was not found, it is there */
+ if (!foundOpeningBrace) {
+ foundOpeningBrace = true;
+ this.bracketBalance++;
+ }
+ /* if member type not finished, then member type becomes current */
+ if (memberTypeDeclaration.declarationSourceEnd == 0)
+ return element;
+ return this;
+ }
+
+ /*
+ * Answer the body end of the corresponding parse node
+ */
+ public int bodyEnd() {
+ if (bodyEnd == 0)
+ return typeDeclaration.declarationSourceEnd;
+ return bodyEnd;
+ }
+
+ public boolean bodyStartsAtHeaderEnd() {
+ if (typeDeclaration.superInterfaces == null) {
+ if (typeDeclaration.superclass == null) {
+ return typeDeclaration.bodyStart == typeDeclaration.sourceEnd + 1;
+ } else {
+ return typeDeclaration.bodyStart == typeDeclaration.superclass.sourceEnd + 1;
+ }
+ } else {
+ return typeDeclaration.bodyStart
+ == typeDeclaration.superInterfaces[typeDeclaration.superInterfaces.length
+ - 1].sourceEnd
+ + 1;
+ }
+ }
+
+ /*
+ * Answer the enclosing type node, or null if none
+ */
+ public RecoveredType enclosingType() {
+ RecoveredElement current = parent;
+ while (current != null) {
+ if (current instanceof RecoveredType) {
+ return (RecoveredType) current;
+ }
+ current = current.parent;
+ }
+ return null;
+ }
+
+ public char[] name() {
+ return typeDeclaration.name;
+ }
+
+ /*
+ * Answer the associated parsed structure
+ */
+ public AstNode parseTree() {
+ return typeDeclaration;
+ }
+
+ /*
+ * Answer the very source end of the corresponding parse node
+ */
+ public int sourceEnd() {
+ return this.typeDeclaration.declarationSourceEnd;
+ }
+
+ public String toString(int tab) {
+ StringBuffer result = new StringBuffer(tabString(tab));
+ result.append("Recovered type:\n");
+ if (typeDeclaration instanceof AnonymousLocalTypeDeclaration) {
+ result.append(tabString(tab));
+ result.append(" ");
+ }
+ result.append(typeDeclaration.toString(tab + 1));
+ if (this.memberTypes != null) {
+ for (int i = 0; i < this.memberTypeCount; i++) {
+ result.append("\n");
+ result.append(this.memberTypes[i].toString(tab + 1));
+ }
+ }
+ if (this.fields != null) {
+ for (int i = 0; i < this.fieldCount; i++) {
+ result.append("\n");
+ result.append(this.fields[i].toString(tab + 1));
+ }
+ }
+ if (this.methods != null) {
+ for (int i = 0; i < this.methodCount; i++) {
+ result.append("\n");
+ result.append(this.methods[i].toString(tab + 1));
+ }
+ }
+ return result.toString();
+ }
+
+ /*
+ * Update the bodyStart of the corresponding parse node
+ */
+ public void updateBodyStart(int bodyStart) {
+ this.foundOpeningBrace = true;
+ this.typeDeclaration.bodyStart = bodyStart;
+ }
+
+ public Statement updatedStatement() {
+
+ // ignore closed anonymous type
+ if (typeDeclaration instanceof AnonymousLocalTypeDeclaration
+ && !this.preserveContent) {
+ return null;
+ }
+
+ TypeDeclaration updatedType = this.updatedTypeDeclaration();
+ if (updatedType instanceof AnonymousLocalTypeDeclaration) {
+ /* in presence of an anonymous type, we want the full allocation expression */
+ return ((AnonymousLocalTypeDeclaration) updatedType).allocation;
+ }
+ return updatedType;
+ }
+
+ public TypeDeclaration updatedTypeDeclaration() {
+
+ /* update member types */
+ if (memberTypeCount > 0) {
+ int existingCount =
+ typeDeclaration.memberTypes == null ? 0 : typeDeclaration.memberTypes.length;
+ MemberTypeDeclaration[] memberTypeDeclarations =
+ new MemberTypeDeclaration[existingCount + memberTypeCount];
+ if (existingCount > 0) {
+ System.arraycopy(
+ typeDeclaration.memberTypes,
+ 0,
+ memberTypeDeclarations,
+ 0,
+ existingCount);
+ }
+ // may need to update the declarationSourceEnd of the last type
+ if (memberTypes[memberTypeCount - 1].typeDeclaration.declarationSourceEnd
+ == 0) {
+ memberTypes[memberTypeCount - 1].typeDeclaration.declarationSourceEnd =
+ bodyEnd();
+ }
+ for (int i = 0; i < memberTypeCount; i++) {
+ memberTypeDeclarations[existingCount + i] =
+ (MemberTypeDeclaration) memberTypes[i].updatedTypeDeclaration();
+ }
+ typeDeclaration.memberTypes = memberTypeDeclarations;
+ }
+ /* update fields */
+ if (fieldCount > 0) {
+ int existingCount =
+ typeDeclaration.fields == null ? 0 : typeDeclaration.fields.length;
+ FieldDeclaration[] fieldDeclarations =
+ new FieldDeclaration[existingCount + fieldCount];
+ if (existingCount > 0) {
+ System.arraycopy(
+ typeDeclaration.fields,
+ 0,
+ fieldDeclarations,
+ 0,
+ existingCount);
+ }
+ // may need to update the declarationSourceEnd of the last field
+ if (fields[fieldCount - 1].fieldDeclaration.declarationSourceEnd == 0) {
+ fields[fieldCount - 1].fieldDeclaration.declarationSourceEnd = bodyEnd();
+ }
+ for (int i = 0; i < fieldCount; i++) {
+ fieldDeclarations[existingCount + i] = fields[i].updatedFieldDeclaration();
+ }
+ typeDeclaration.fields = fieldDeclarations;
+ }
+ /* update methods */
+ int existingCount =
+ typeDeclaration.methods == null ? 0 : typeDeclaration.methods.length;
+ boolean hasConstructor = false, hasRecoveredConstructor = false;
+ int defaultConstructorIndex = -1;
+ if (methodCount > 0) {
+ AbstractMethodDeclaration[] methodDeclarations =
+ new AbstractMethodDeclaration[existingCount + methodCount];
+ for (int i = 0; i < existingCount; i++) {
+ AbstractMethodDeclaration m = typeDeclaration.methods[i];
+ if (m.isDefaultConstructor())
+ defaultConstructorIndex = i;
+ methodDeclarations[i] = m;
+ }
+ // may need to update the declarationSourceEnd of the last method
+ if (methods[methodCount - 1].methodDeclaration.declarationSourceEnd == 0) {
+ methods[methodCount - 1].methodDeclaration.declarationSourceEnd = bodyEnd();
+ }
+ for (int i = 0; i < methodCount; i++) {
+ AbstractMethodDeclaration updatedMethod = methods[i].updatedMethodDeclaration();
+ if (updatedMethod.isConstructor())
+ hasRecoveredConstructor = true;
+ methodDeclarations[existingCount + i] = updatedMethod;
+ }
+ typeDeclaration.methods = methodDeclarations;
+ hasConstructor = typeDeclaration.checkConstructors(this.parser());
+ } else {
+ for (int i = 0; i < existingCount; i++) {
+ if (typeDeclaration.methods[i].isConstructor())
+ hasConstructor = true;
+ }
+ }
+ /* add clinit ? */
+ if (typeDeclaration.needClassInitMethod()) {
+ boolean alreadyHasClinit = false;
+ for (int i = 0; i < existingCount; i++) {
+ if (typeDeclaration.methods[i].isClinit()) {
+ alreadyHasClinit = true;
+ break;
+ }
+ }
+ if (!alreadyHasClinit)
+ typeDeclaration.addClinit();
+ }
+ /* add default constructor ? */
+ if (defaultConstructorIndex >= 0 && hasRecoveredConstructor) {
+ /* should discard previous default construtor */
+ AbstractMethodDeclaration[] methodDeclarations =
+ new AbstractMethodDeclaration[typeDeclaration.methods.length - 1];
+ if (defaultConstructorIndex != 0) {
+ System.arraycopy(
+ typeDeclaration.methods,
+ 0,
+ methodDeclarations,
+ 0,
+ defaultConstructorIndex);
+ }
+ if (defaultConstructorIndex != typeDeclaration.methods.length - 1) {
+ System.arraycopy(
+ typeDeclaration.methods,
+ defaultConstructorIndex + 1,
+ methodDeclarations,
+ defaultConstructorIndex,
+ typeDeclaration.methods.length - defaultConstructorIndex - 1);
+ }
+ typeDeclaration.methods = methodDeclarations;
+ } else {
+ if (!hasConstructor) { // if was already reduced, then constructor
+ typeDeclaration.createsInternalConstructor(true, true);
+ }
+ }
+ /* might need to cast itself into a MemberTypeDeclaration or a LocalTypeDeclaration */
+ TypeDeclaration newTypeDeclaration = null;
+ if ((typeDeclaration instanceof TypeDeclaration)
+ && (parent instanceof RecoveredType)) {
+ newTypeDeclaration = new MemberTypeDeclaration();
+ } else {
+ if ((typeDeclaration instanceof TypeDeclaration)
+ && (parent instanceof RecoveredMethod)) {
+ newTypeDeclaration = new LocalTypeDeclaration();
+ }
+ }
+ /* copy slots into new type */
+ if (newTypeDeclaration != null) {
+ newTypeDeclaration.modifiers = typeDeclaration.modifiers;
+ newTypeDeclaration.modifiersSourceStart = typeDeclaration.modifiersSourceStart;
+ newTypeDeclaration.name = typeDeclaration.name;
+ newTypeDeclaration.superclass = typeDeclaration.superclass;
+ newTypeDeclaration.superInterfaces = typeDeclaration.superInterfaces;
+ newTypeDeclaration.fields = typeDeclaration.fields;
+ newTypeDeclaration.methods = typeDeclaration.methods;
+ newTypeDeclaration.memberTypes = typeDeclaration.memberTypes;
+ newTypeDeclaration.ignoreFurtherInvestigation =
+ typeDeclaration.ignoreFurtherInvestigation;
+ newTypeDeclaration.maxFieldCount = typeDeclaration.maxFieldCount;
+ newTypeDeclaration.declarationSourceStart =
+ typeDeclaration.declarationSourceStart;
+ newTypeDeclaration.declarationSourceEnd = typeDeclaration.declarationSourceEnd;
+ newTypeDeclaration.bodyStart = typeDeclaration.bodyStart;
+ typeDeclaration = newTypeDeclaration;
+ }
+ return typeDeclaration;
+ }
+
+ /*
+ * Update the corresponding parse node from parser state which
+ * is about to disappear because of restarting recovery
+ */
+ public void updateFromParserState() {
+
+ if (this.bodyStartsAtHeaderEnd()) {
+ Parser parser = this.parser();
+ /* might want to recover implemented interfaces */
+ if (parser.listLength > 0) { // awaiting interface type references
+ parser.consumeClassHeaderImplements();
+ // will reset typeListLength to zero
+ // thus this check will only be performed on first errorCheck after class X implements Y,Z,
+ }
+ }
+ }
+
+ /*
+ * A closing brace got consumed, might have closed the current element,
+ * in which case both the currentElement is exited
+ */
+ public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd) {
+ if ((--bracketBalance <= 0) && (parent != null)) {
+ this.updateSourceEndIfNecessary(braceEnd);
+ this.bodyEnd = braceStart - 1;
+ return parent;
+ }
+ return this;
+ }
+
+ /*
+ * An opening brace got consumed, might be the expected opening one of the current element,
+ * in which case the bodyStart is updated.
+ */
+ public RecoveredElement updateOnOpeningBrace(int braceEnd) {
+ /* in case the opening brace is not close enough to the signature, ignore it */
+ if (bracketBalance == 0) {
+ /*
+ if (parser.scanner.searchLineNumber(typeDeclaration.sourceEnd)
+ != parser.scanner.searchLineNumber(braceEnd)){
+ */
+ Parser parser = this.parser();
+ switch (parser.lastIgnoredToken) {
+ case -1 :
+ case TokenNameextends :
+ case TokenNameimplements :
+ if (parser.recoveredStaticInitializerStart == 0)
+ break;
+ default :
+ this.foundOpeningBrace = true;
+ bracketBalance = 1; // pretend the brace was already there
+ }
+ }
+ // might be an initializer
+ if (this.bracketBalance == 1) {
+ Block block = new Block(0);
+ Parser parser = this.parser();
+ block.sourceStart = parser.scanner.startPosition;
+ Initializer init;
+ if (parser.recoveredStaticInitializerStart == 0) {
+ init = new Initializer(block, AccDefault);
+ } else {
+ init = new Initializer(block, AccStatic);
+ init.declarationSourceStart = parser.recoveredStaticInitializerStart;
+ }
+ return this.add(init, 1);
+ }
+ return super.updateOnOpeningBrace(braceEnd);
+ }
+
+ public void updateParseTree() {
+ this.updatedTypeDeclaration();
+ }
+
+ /*
+ * Update the declarationSourceEnd of the corresponding parse node
+ */
+ public void updateSourceEndIfNecessary(int sourceEnd) {
+ if (this.typeDeclaration.declarationSourceEnd == 0) {
+ this.bodyEnd = 0;
+ this.typeDeclaration.declarationSourceEnd = sourceEnd;
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredUnit.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredUnit.java
new file mode 100644
index 0000000000..4f21d7c1e7
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredUnit.java
@@ -0,0 +1,194 @@
+package org.eclipse.jdt.internal.compiler.parser;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/**
+ * Internal field structure for parsing recovery
+ */
+import org.eclipse.jdt.internal.compiler.ast.*;
+
+public class RecoveredUnit extends RecoveredElement {
+
+ public CompilationUnitDeclaration unitDeclaration;
+
+ public RecoveredImport[] imports;
+ public int importCount;
+ public RecoveredType[] types;
+ public int typeCount;
+ public RecoveredUnit(
+ CompilationUnitDeclaration unitDeclaration,
+ int bracketBalance,
+ Parser parser) {
+ super(null, bracketBalance, parser);
+ this.unitDeclaration = unitDeclaration;
+ }
+
+ /*
+ * Record a method declaration: should be attached to last type
+ */
+ public RecoveredElement add(
+ AbstractMethodDeclaration methodDeclaration,
+ int bracketBalance) {
+
+ /* attach it to last type - if any */
+ if (typeCount > 0) {
+ RecoveredType type = this.types[typeCount - 1];
+ type.bodyEnd = 0; // reset position
+ type.typeDeclaration.declarationSourceEnd = 0; // reset position
+ return type.add(methodDeclaration, bracketBalance);
+ }
+ return this; // ignore
+ }
+
+ /*
+ * Record a field declaration: should be attached to last type
+ */
+ public RecoveredElement add(
+ FieldDeclaration fieldDeclaration,
+ int bracketBalance) {
+
+ /* attach it to last type - if any */
+ if (typeCount > 0) {
+ RecoveredType type = this.types[typeCount - 1];
+ type.bodyEnd = 0; // reset position
+ type.typeDeclaration.declarationSourceEnd = 0; // reset position
+ return type.add(fieldDeclaration, bracketBalance);
+ }
+ return this; // ignore
+ }
+
+ public RecoveredElement add(
+ ImportReference importReference,
+ int bracketBalance) {
+ if (imports == null) {
+ imports = new RecoveredImport[5];
+ importCount = 0;
+ } else {
+ if (importCount == imports.length) {
+ System.arraycopy(
+ imports,
+ 0,
+ (imports = new RecoveredImport[2 * importCount]),
+ 0,
+ importCount);
+ }
+ }
+ RecoveredImport element =
+ new RecoveredImport(importReference, this, bracketBalance);
+ imports[importCount++] = element;
+
+ /* if import not finished, then import becomes current */
+ if (importReference.declarationSourceEnd == 0)
+ return element;
+ return this;
+ }
+
+ public RecoveredElement add(
+ TypeDeclaration typeDeclaration,
+ int bracketBalance) {
+
+ if (types == null) {
+ types = new RecoveredType[5];
+ typeCount = 0;
+ } else {
+ if (typeCount == types.length) {
+ System.arraycopy(
+ types,
+ 0,
+ (types = new RecoveredType[2 * typeCount]),
+ 0,
+ typeCount);
+ }
+ }
+ RecoveredType element =
+ new RecoveredType(typeDeclaration, this, bracketBalance);
+ types[typeCount++] = element;
+
+ /* if type not finished, then type becomes current */
+ if (typeDeclaration.declarationSourceEnd == 0)
+ return element;
+ return this;
+ }
+
+ /*
+ * Answer the associated parsed structure
+ */
+ public AstNode parseTree() {
+ return unitDeclaration;
+ }
+
+ /*
+ * Answer the very source end of the corresponding parse node
+ */
+ public int sourceEnd() {
+ return this.unitDeclaration.sourceEnd;
+ }
+
+ public String toString(int tab) {
+ StringBuffer result = new StringBuffer(tabString(tab));
+ result.append("Recovered unit: [\n");
+ result.append(unitDeclaration.toString(tab + 1));
+ result.append(tabString(tab + 1));
+ result.append("]");
+ if (this.imports != null) {
+ for (int i = 0; i < this.importCount; i++) {
+ result.append("\n");
+ result.append(this.imports[i].toString(tab + 1));
+ }
+ }
+ if (this.types != null) {
+ for (int i = 0; i < this.typeCount; i++) {
+ result.append("\n");
+ result.append(this.types[i].toString(tab + 1));
+ }
+ }
+ return result.toString();
+ }
+
+ public CompilationUnitDeclaration updatedCompilationUnitDeclaration() {
+
+ /* update imports */
+ if (importCount > 0) {
+ ImportReference[] importRefences = new ImportReference[importCount];
+ for (int i = 0; i < importCount; i++) {
+ importRefences[i] = imports[i].updatedImportReference();
+ }
+ unitDeclaration.imports = importRefences;
+ }
+ /* update types */
+ if (typeCount > 0) {
+ int existingCount =
+ unitDeclaration.types == null ? 0 : unitDeclaration.types.length;
+ TypeDeclaration[] typeDeclarations =
+ new TypeDeclaration[existingCount + typeCount];
+ if (existingCount > 0) {
+ System.arraycopy(unitDeclaration.types, 0, typeDeclarations, 0, existingCount);
+ }
+ // may need to update the declarationSourceEnd of the last type
+ if (types[typeCount - 1].typeDeclaration.declarationSourceEnd == 0) {
+ types[typeCount - 1].typeDeclaration.declarationSourceEnd =
+ unitDeclaration.sourceEnd;
+ }
+ for (int i = 0; i < typeCount; i++) {
+ typeDeclarations[existingCount + i] = types[i].updatedTypeDeclaration();
+ }
+ unitDeclaration.types = typeDeclarations;
+ }
+ return unitDeclaration;
+ }
+
+ public void updateParseTree() {
+ this.updatedCompilationUnitDeclaration();
+ }
+
+ /*
+ * Update the sourceEnd of the corresponding parse node
+ */
+ public void updateSourceEndIfNecessary(int sourceEnd) {
+ if (this.unitDeclaration.sourceEnd == 0)
+ this.unitDeclaration.sourceEnd = sourceEnd;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java
new file mode 100644
index 0000000000..90bf111f9a
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java
@@ -0,0 +1,2948 @@
+package org.eclipse.jdt.internal.compiler.parser;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import java.io.*;
+
+public class Scanner implements TerminalSymbols {
+
+ /* APIs ares
+ - getNextToken() which return the current type of the token
+ (this value is not memorized by the scanner)
+ - getCurrentTokenSource() which provides with the token "REAL" source
+ (aka all unicode have been transformed into a correct char)
+ - sourceStart gives the position into the stream
+ - currentPosition-1 gives the sourceEnd position into the stream
+ */
+
+ public boolean recordLineSeparator;
+ public char currentCharacter;
+ public int startPosition;
+ public int currentPosition;
+ public int initialPosition, eofPosition;
+ // after this position eof are generated instead of real token from the source
+
+ public boolean tokenizeComments;
+ public boolean tokenizeWhiteSpace;
+ public final static int TokenNameWHITESPACE = 1000;
+ // special tokens not part of grammar - not autogenerated
+ public final static int TokenNameCOMMENT_LINE = 1001;
+ // special tokens not part of grammar - not autogenerated
+ public final static int TokenNameCOMMENT_BLOCK = 1002;
+ // special tokens not part of grammar - not autogenerated
+ public final static int TokenNameCOMMENT_JAVADOC = 1003;
+ // special tokens not part of grammar - not autogenerated
+
+ //source should be viewed as a window (aka a part)
+ //of a entire very large stream
+ public char source[];
+
+ //unicode support
+ public char[] withoutUnicodeBuffer;
+ public int withoutUnicodePtr; //when == 0 ==> no unicode in the current token
+ public boolean unicodeAsBackSlash = false;
+
+ public boolean scanningFloatLiteral = false;
+
+ //support for /** comments
+ //public char[][] comments = new char[10][];
+ public int[] commentStops = new int[10];
+ public int[] commentStarts = new int[10];
+ public int commentPtr = -1; // no comment test with commentPtr value -1
+
+ //diet parsing support - jump over some method body when requested
+ public boolean diet = false;
+
+ //support for the poor-line-debuggers ....
+ //remember the position of the cr/lf
+ public int[] lineEnds = new int[250];
+ public int linePtr = -1;
+ public boolean wasAcr = false;
+
+ public static final String END_OF_SOURCE = "End_Of_Source";
+
+ public static final String INVALID_HEXA = "Invalid_Hexa_Literal";
+ public static final String INVALID_OCTAL = "Invalid_Octal_Literal";
+ public static final String INVALID_CHARACTER_CONSTANT =
+ "Invalid_Character_Constant";
+ public static final String INVALID_ESCAPE = "Invalid_Escape";
+ public static final String INVALID_INPUT = "Invalid_Input";
+ public static final String INVALID_UNICODE_ESCAPE = "Invalid_Unicode_Escape";
+ public static final String INVALID_FLOAT = "Invalid_Float_Literal";
+
+ public static final String NULL_SOURCE_STRING = "Null_Source_String";
+ public static final String UNTERMINATED_STRING = "Unterminated_String";
+ public static final String UNTERMINATED_COMMENT = "Unterminated_Comment";
+ public static final String INVALID_CHAR_IN_STRING = "Invalid_Char_In_String";
+
+ //----------------optimized identifier managment------------------
+ static final char[] charArray_a = new char[] { 'a' },
+ charArray_b = new char[] { 'b' },
+ charArray_c = new char[] { 'c' },
+ charArray_d = new char[] { 'd' },
+ charArray_e = new char[] { 'e' },
+ charArray_f = new char[] { 'f' },
+ charArray_g = new char[] { 'g' },
+ charArray_h = new char[] { 'h' },
+ charArray_i = new char[] { 'i' },
+ charArray_j = new char[] { 'j' },
+ charArray_k = new char[] { 'k' },
+ charArray_l = new char[] { 'l' },
+ charArray_m = new char[] { 'm' },
+ charArray_n = new char[] { 'n' },
+ charArray_o = new char[] { 'o' },
+ charArray_p = new char[] { 'p' },
+ charArray_q = new char[] { 'q' },
+ charArray_r = new char[] { 'r' },
+ charArray_s = new char[] { 's' },
+ charArray_t = new char[] { 't' },
+ charArray_u = new char[] { 'u' },
+ charArray_v = new char[] { 'v' },
+ charArray_w = new char[] { 'w' },
+ charArray_x = new char[] { 'x' },
+ charArray_y = new char[] { 'y' },
+ charArray_z = new char[] { 'z' };
+
+ static final char[] initCharArray =
+ new char[] { '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000' };
+ static final int TableSize = 30, InternalTableSize = 6; //30*6 = 180 entries
+ public static final int OptimizedLength = 6;
+ public /*static*/
+ final char[][][][] charArray_length =
+ new char[OptimizedLength][TableSize][InternalTableSize][];
+ /*static*/ {
+ for (int i = 0; i < 6; i++) {
+ for (int j = 0; j < TableSize; j++) {
+ for (int k = 0; k < InternalTableSize; k++) {
+ charArray_length[i][j][k] = initCharArray;
+ }
+ }
+ }
+ }
+
+ static int newEntry2 = 0,
+ newEntry3 = 0,
+ newEntry4 = 0,
+ newEntry5 = 0,
+ newEntry6 = 0;
+
+ public static final int RoundBracket = 0;
+ public static final int SquareBracket = 1;
+ public static final int CurlyBracket = 2;
+ public static final int BracketKinds = 3;
+ public Scanner() {
+ this(false, false);
+ }
+
+ public Scanner(boolean tokenizeComments, boolean tokenizeWhiteSpace) {
+ this.eofPosition = Integer.MAX_VALUE;
+ this.tokenizeComments = tokenizeComments;
+ this.tokenizeWhiteSpace = tokenizeWhiteSpace;
+ }
+
+ public final boolean atEnd() {
+ // This code is not relevant if source is
+ // Only a part of the real stream input
+
+ return source.length == currentPosition;
+ }
+
+ public char[] getCurrentIdentifierSource() {
+ //return the token REAL source (aka unicodes are precomputed)
+
+ char[] result;
+ if (withoutUnicodePtr != 0)
+ //0 is used as a fast test flag so the real first char is in position 1
+ System.arraycopy(
+ withoutUnicodeBuffer,
+ 1,
+ result = new char[withoutUnicodePtr],
+ 0,
+ withoutUnicodePtr);
+ else {
+ int length = currentPosition - startPosition;
+ switch (length) { // see OptimizedLength
+ case 1 :
+ return optimizedCurrentTokenSource1();
+ case 2 :
+ return optimizedCurrentTokenSource2();
+ case 3 :
+ return optimizedCurrentTokenSource3();
+ case 4 :
+ return optimizedCurrentTokenSource4();
+ case 5 :
+ return optimizedCurrentTokenSource5();
+ case 6 :
+ return optimizedCurrentTokenSource6();
+ }
+ //no optimization
+ System.arraycopy(source, startPosition, result = new char[length], 0, length);
+ }
+ return result;
+ }
+
+ public final char[] getCurrentTokenSource() {
+ // Return the token REAL source (aka unicodes are precomputed)
+
+ char[] result;
+ if (withoutUnicodePtr != 0)
+ // 0 is used as a fast test flag so the real first char is in position 1
+ System.arraycopy(
+ withoutUnicodeBuffer,
+ 1,
+ result = new char[withoutUnicodePtr],
+ 0,
+ withoutUnicodePtr);
+ else {
+ int length;
+ System.arraycopy(
+ source,
+ startPosition,
+ result = new char[length = currentPosition - startPosition],
+ 0,
+ length);
+ }
+ return result;
+ }
+
+ public final char[] getCurrentTokenSourceString() {
+ //return the token REAL source (aka unicodes are precomputed).
+ //REMOVE the two " that are at the beginning and the end.
+
+ char[] result;
+ if (withoutUnicodePtr != 0)
+ //0 is used as a fast test flag so the real first char is in position 1
+ System.arraycopy(withoutUnicodeBuffer, 2,
+ //2 is 1 (real start) + 1 (to jump over the ")
+ result = new char[withoutUnicodePtr - 2], 0, withoutUnicodePtr - 2);
+ else {
+ int length;
+ System.arraycopy(
+ source,
+ startPosition + 1,
+ result = new char[length = currentPosition - startPosition - 2],
+ 0,
+ length);
+ }
+ return result;
+ }
+
+ /*
+ * Search the source position corresponding to the end of a given line number
+ *
+ * Line numbers are 1-based, and relative to the scanner initialPosition.
+ * Character positions are 0-based.
+ *
+ * In case the given line number is inconsistent, answers -1.
+ */
+ public final int getLineEnd(int lineNumber) {
+
+ if (lineEnds == null)
+ return -1;
+ if (lineNumber >= lineEnds.length)
+ return -1;
+ if (lineNumber <= 0)
+ return -1;
+
+ if (lineNumber == lineEnds.length - 1)
+ return eofPosition;
+ return lineEnds[lineNumber - 1];
+ // next line start one character behind the lineEnd of the previous line
+ }
+
+ /**
+ * Search the source position corresponding to the beginning of a given line number
+ *
+ * Line numbers are 1-based, and relative to the scanner initialPosition.
+ * Character positions are 0-based.
+ *
+ * e.g. getLineStart(1) --> 0 i.e. first line starts at character 0.
+ *
+ * In case the given line number is inconsistent, answers -1.
+ */
+ public final int getLineStart(int lineNumber) {
+
+ if (lineEnds == null)
+ return -1;
+ if (lineNumber >= lineEnds.length)
+ return -1;
+ if (lineNumber <= 0)
+ return -1;
+
+ if (lineNumber == 1)
+ return initialPosition;
+ return lineEnds[lineNumber - 2] + 1;
+ // next line start one character behind the lineEnd of the previous line
+ }
+
+ public final boolean getNextChar(char testedChar) {
+ //BOOLEAN
+ //handle the case of unicode.
+ //when a unicode appears then we must use a buffer that holds char internal values
+ //At the end of this method currentCharacter holds the new visited char
+ //and currentPosition points right next after it
+ //Both previous lines are true if the currentCharacter is == to the testedChar
+ //On false, no side effect has occured.
+
+ //ALL getNextChar.... ARE OPTIMIZED COPIES
+
+ int temp = currentPosition;
+ try {
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ //-------------unicode traitement ------------
+ int c1, c2, c3, c4;
+ int unicodeSize = 6;
+ currentPosition++;
+ while (source[currentPosition] == 'u') {
+ currentPosition++;
+ unicodeSize++;
+ }
+
+ if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c1 < 0)
+ || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15 || c2 < 0)
+ || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15 || c3 < 0)
+ || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15 || c4 < 0)) {
+ currentPosition = temp;
+ return false;
+ }
+
+ currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+ if (currentCharacter != testedChar) {
+ currentPosition = temp;
+ return false;
+ }
+ unicodeAsBackSlash = currentCharacter == '\\';
+
+ //need the unicode buffer
+ if (withoutUnicodePtr == 0) {
+ //buffer all the entries that have been left aside....
+ withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
+ System.arraycopy(
+ source,
+ startPosition,
+ withoutUnicodeBuffer,
+ 1,
+ withoutUnicodePtr);
+ }
+ //fill the buffer with the char
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ return true;
+
+ } //-------------end unicode traitement--------------
+ else {
+ if (currentCharacter != testedChar) {
+ currentPosition = temp;
+ return false;
+ }
+ unicodeAsBackSlash = false;
+ if (withoutUnicodePtr != 0)
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ return true;
+ }
+ } catch (IndexOutOfBoundsException e) {
+ unicodeAsBackSlash = false;
+ currentPosition = temp;
+ return false;
+ }
+ }
+
+ public final int getNextChar(char testedChar1, char testedChar2) {
+ //INT 0 : testChar1 \\\\///\\\\ 1 : testedChar2 \\\\///\\\\ -1 : others
+ //test can be done with (x==0) for the first and (x>0) for the second
+ //handle the case of unicode.
+ //when a unicode appears then we must use a buffer that holds char internal values
+ //At the end of this method currentCharacter holds the new visited char
+ //and currentPosition points right next after it
+ //Both previous lines are true if the currentCharacter is == to the testedChar1/2
+ //On false, no side effect has occured.
+
+ //ALL getNextChar.... ARE OPTIMIZED COPIES
+
+ int temp = currentPosition;
+ try {
+ int result;
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ //-------------unicode traitement ------------
+ int c1, c2, c3, c4;
+ int unicodeSize = 6;
+ currentPosition++;
+ while (source[currentPosition] == 'u') {
+ currentPosition++;
+ unicodeSize++;
+ }
+
+ if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c1 < 0)
+ || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15 || c2 < 0)
+ || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15 || c3 < 0)
+ || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15 || c4 < 0)) {
+ currentPosition = temp;
+ return 2;
+ }
+
+ currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+ if (currentCharacter == testedChar1)
+ result = 0;
+ else
+ if (currentCharacter == testedChar2)
+ result = 1;
+ else {
+ currentPosition = temp;
+ return -1;
+ }
+
+ //need the unicode buffer
+ if (withoutUnicodePtr == 0) {
+ //buffer all the entries that have been left aside....
+ withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
+ System.arraycopy(
+ source,
+ startPosition,
+ withoutUnicodeBuffer,
+ 1,
+ withoutUnicodePtr);
+ }
+ //fill the buffer with the char
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ return result;
+ } //-------------end unicode traitement--------------
+ else {
+ if (currentCharacter == testedChar1)
+ result = 0;
+ else
+ if (currentCharacter == testedChar2)
+ result = 1;
+ else {
+ currentPosition = temp;
+ return -1;
+ }
+
+ if (withoutUnicodePtr != 0)
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ return result;
+ }
+ } catch (IndexOutOfBoundsException e) {
+ currentPosition = temp;
+ return -1;
+ }
+ }
+
+ public final boolean getNextCharAsDigit() {
+ //BOOLEAN
+ //handle the case of unicode.
+ //when a unicode appears then we must use a buffer that holds char internal values
+ //At the end of this method currentCharacter holds the new visited char
+ //and currentPosition points right next after it
+ //Both previous lines are true if the currentCharacter is a digit
+ //On false, no side effect has occured.
+
+ //ALL getNextChar.... ARE OPTIMIZED COPIES
+
+ int temp = currentPosition;
+ try {
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ //-------------unicode traitement ------------
+ int c1, c2, c3, c4;
+ int unicodeSize = 6;
+ currentPosition++;
+ while (source[currentPosition] == 'u') {
+ currentPosition++;
+ unicodeSize++;
+ }
+
+ if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c1 < 0)
+ || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15 || c2 < 0)
+ || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15 || c3 < 0)
+ || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15 || c4 < 0)) {
+ currentPosition = temp;
+ return false;
+ }
+
+ currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+ if (!Character.isDigit(currentCharacter)) {
+ currentPosition = temp;
+ return false;
+ }
+
+ //need the unicode buffer
+ if (withoutUnicodePtr == 0) {
+ //buffer all the entries that have been left aside....
+ withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
+ System.arraycopy(
+ source,
+ startPosition,
+ withoutUnicodeBuffer,
+ 1,
+ withoutUnicodePtr);
+ }
+ //fill the buffer with the char
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ return true;
+ } //-------------end unicode traitement--------------
+ else {
+ if (!Character.isDigit(currentCharacter)) {
+ currentPosition = temp;
+ return false;
+ }
+ if (withoutUnicodePtr != 0)
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ return true;
+ }
+ } catch (IndexOutOfBoundsException e) {
+ currentPosition = temp;
+ return false;
+ }
+ }
+
+ public final boolean getNextCharAsDigit(int radix) {
+ //BOOLEAN
+ //handle the case of unicode.
+ //when a unicode appears then we must use a buffer that holds char internal values
+ //At the end of this method currentCharacter holds the new visited char
+ //and currentPosition points right next after it
+ //Both previous lines are true if the currentCharacter is a digit base on radix
+ //On false, no side effect has occured.
+
+ //ALL getNextChar.... ARE OPTIMIZED COPIES
+
+ int temp = currentPosition;
+ try {
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ //-------------unicode traitement ------------
+ int c1, c2, c3, c4;
+ int unicodeSize = 6;
+ currentPosition++;
+ while (source[currentPosition] == 'u') {
+ currentPosition++;
+ unicodeSize++;
+ }
+
+ if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c1 < 0)
+ || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15 || c2 < 0)
+ || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15 || c3 < 0)
+ || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15 || c4 < 0)) {
+ currentPosition = temp;
+ return false;
+ }
+
+ currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+ if (Character.digit(currentCharacter, radix) == -1) {
+ currentPosition = temp;
+ return false;
+ }
+
+ //need the unicode buffer
+ if (withoutUnicodePtr == 0) {
+ //buffer all the entries that have been left aside....
+ withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
+ System.arraycopy(
+ source,
+ startPosition,
+ withoutUnicodeBuffer,
+ 1,
+ withoutUnicodePtr);
+ }
+ //fill the buffer with the char
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ return true;
+ } //-------------end unicode traitement--------------
+ else {
+ if (Character.digit(currentCharacter, radix) == -1) {
+ currentPosition = temp;
+ return false;
+ }
+ if (withoutUnicodePtr != 0)
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ return true;
+ }
+ } catch (IndexOutOfBoundsException e) {
+ currentPosition = temp;
+ return false;
+ }
+ }
+
+ public boolean getNextCharAsJavaIdentifierPart() {
+ //BOOLEAN
+ //handle the case of unicode.
+ //when a unicode appears then we must use a buffer that holds char internal values
+ //At the end of this method currentCharacter holds the new visited char
+ //and currentPosition points right next after it
+ //Both previous lines are true if the currentCharacter is a JavaIdentifierPart
+ //On false, no side effect has occured.
+
+ //ALL getNextChar.... ARE OPTIMIZED COPIES
+
+ int temp = currentPosition;
+ try {
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ //-------------unicode traitement ------------
+ int c1, c2, c3, c4;
+ int unicodeSize = 6;
+ currentPosition++;
+ while (source[currentPosition] == 'u') {
+ currentPosition++;
+ unicodeSize++;
+ }
+
+ if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c1 < 0)
+ || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15 || c2 < 0)
+ || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15 || c3 < 0)
+ || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15 || c4 < 0)) {
+ currentPosition = temp;
+ return false;
+ }
+
+ currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+ if (!Character.isJavaIdentifierPart(currentCharacter)) {
+ currentPosition = temp;
+ return false;
+ }
+
+ //need the unicode buffer
+ if (withoutUnicodePtr == 0) {
+ //buffer all the entries that have been left aside....
+ withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
+ System.arraycopy(
+ source,
+ startPosition,
+ withoutUnicodeBuffer,
+ 1,
+ withoutUnicodePtr);
+ }
+ //fill the buffer with the char
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ return true;
+ } //-------------end unicode traitement--------------
+ else {
+ if (!Character.isJavaIdentifierPart(currentCharacter)) {
+ currentPosition = temp;
+ return false;
+ }
+
+ if (withoutUnicodePtr != 0)
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ return true;
+ }
+ } catch (IndexOutOfBoundsException e) {
+ currentPosition = temp;
+ return false;
+ }
+ }
+
+ public int getNextToken() throws InvalidInputException {
+
+ if (diet) {
+ jumpOverMethodBody();
+ diet = false;
+ return currentPosition > source.length ? TokenNameEOF : TokenNameRBRACE;
+ }
+ try {
+ while (true) { //loop for jumping over comments
+ withoutUnicodePtr = 0;
+ //start with a new token (even comment written with unicode )
+
+ // ---------Consume white space and handles startPosition---------
+ int whiteStart = currentPosition;
+ boolean isWhiteSpace, foundWhiteSpaces;
+ do {
+ startPosition = currentPosition;
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ isWhiteSpace = jumpOverUnicodeWhiteSpace();
+ } else {
+ if (recordLineSeparator
+ && ((currentCharacter == '\r') || (currentCharacter == '\n')))
+ pushLineSeparator();
+ isWhiteSpace =
+ (currentCharacter == ' ') || Character.isWhitespace(currentCharacter);
+ }
+ } while (isWhiteSpace);
+ if (tokenizeWhiteSpace && (whiteStart != currentPosition - 1)) {
+ // reposition scanner in case we are interested by spaces as tokens
+ currentPosition--;
+ startPosition = whiteStart;
+ return TokenNameWHITESPACE;
+ }
+ //little trick to get out in the middle of a source compuation
+ if (currentPosition > eofPosition)
+ return TokenNameEOF;
+
+ // ---------Identify the next token-------------
+
+ switch (currentCharacter) {
+ case '(' :
+ return TokenNameLPAREN;
+ case ')' :
+ return TokenNameRPAREN;
+ case '{' :
+ return TokenNameLBRACE;
+ case '}' :
+ return TokenNameRBRACE;
+ case '[' :
+ return TokenNameLBRACKET;
+ case ']' :
+ return TokenNameRBRACKET;
+ case ';' :
+ return TokenNameSEMICOLON;
+ case ',' :
+ return TokenNameCOMMA;
+ case '.' :
+ if (getNextCharAsDigit())
+ return scanNumber(true);
+ return TokenNameDOT;
+ case '+' :
+ {
+ int test;
+ if ((test = getNextChar('+', '=')) == 0)
+ return TokenNamePLUS_PLUS;
+ if (test > 0)
+ return TokenNamePLUS_EQUAL;
+ return TokenNamePLUS;
+ }
+ case '-' :
+ {
+ int test;
+ if ((test = getNextChar('-', '=')) == 0)
+ return TokenNameMINUS_MINUS;
+ if (test > 0)
+ return TokenNameMINUS_EQUAL;
+ return TokenNameMINUS;
+ }
+ case '~' :
+ return TokenNameTWIDDLE;
+ case '!' :
+ if (getNextChar('='))
+ return TokenNameNOT_EQUAL;
+ return TokenNameNOT;
+ case '*' :
+ if (getNextChar('='))
+ return TokenNameMULTIPLY_EQUAL;
+ return TokenNameMULTIPLY;
+ case '%' :
+ if (getNextChar('='))
+ return TokenNameREMAINDER_EQUAL;
+ return TokenNameREMAINDER;
+ case '<' :
+ {
+ int test;
+ if ((test = getNextChar('=', '<')) == 0)
+ return TokenNameLESS_EQUAL;
+ if (test > 0) {
+ if (getNextChar('='))
+ return TokenNameLEFT_SHIFT_EQUAL;
+ return TokenNameLEFT_SHIFT;
+ }
+ return TokenNameLESS;
+ }
+ case '>' :
+ {
+ int test;
+ if ((test = getNextChar('=', '>')) == 0)
+ return TokenNameGREATER_EQUAL;
+ if (test > 0) {
+ if ((test = getNextChar('=', '>')) == 0)
+ return TokenNameRIGHT_SHIFT_EQUAL;
+ if (test > 0) {
+ if (getNextChar('='))
+ return TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL;
+ return TokenNameUNSIGNED_RIGHT_SHIFT;
+ }
+ return TokenNameRIGHT_SHIFT;
+ }
+ return TokenNameGREATER;
+ }
+ case '=' :
+ if (getNextChar('='))
+ return TokenNameEQUAL_EQUAL;
+ return TokenNameEQUAL;
+ case '&' :
+ {
+ int test;
+ if ((test = getNextChar('&', '=')) == 0)
+ return TokenNameAND_AND;
+ if (test > 0)
+ return TokenNameAND_EQUAL;
+ return TokenNameAND;
+ }
+ case '|' :
+ {
+ int test;
+ if ((test = getNextChar('|', '=')) == 0)
+ return TokenNameOR_OR;
+ if (test > 0)
+ return TokenNameOR_EQUAL;
+ return TokenNameOR;
+ }
+ case '^' :
+ if (getNextChar('='))
+ return TokenNameXOR_EQUAL;
+ return TokenNameXOR;
+ case '?' :
+ return TokenNameQUESTION;
+ case ':' :
+ return TokenNameCOLON;
+ case '\'' :
+ {
+ int test;
+ if ((test = getNextChar('\n', '\r')) == 0) {
+ throw new InvalidInputException(INVALID_CHARACTER_CONSTANT);
+ }
+ if (test > 0) {
+ // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
+ for (int lookAhead = 0; lookAhead < 3; lookAhead++) {
+ if (currentPosition + lookAhead == source.length)
+ break;
+ if (source[currentPosition + lookAhead] == '\n')
+ break;
+ if (source[currentPosition + lookAhead] == '\'') {
+ currentPosition += lookAhead + 1;
+ break;
+ }
+ }
+ throw new InvalidInputException(INVALID_CHARACTER_CONSTANT);
+ }
+ }
+ if (getNextChar('\'')) {
+ // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
+ for (int lookAhead = 0; lookAhead < 3; lookAhead++) {
+ if (currentPosition + lookAhead == source.length)
+ break;
+ if (source[currentPosition + lookAhead] == '\n')
+ break;
+ if (source[currentPosition + lookAhead] == '\'') {
+ currentPosition += lookAhead + 1;
+ break;
+ }
+ }
+ throw new InvalidInputException(INVALID_CHARACTER_CONSTANT);
+ }
+ if (getNextChar('\\'))
+ scanEscapeCharacter();
+ else { // consume next character
+ unicodeAsBackSlash = false;
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ getNextUnicodeChar();
+ } else {
+ if (withoutUnicodePtr != 0) {
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ }
+ }
+ }
+ if (getNextChar('\''))
+ return TokenNameCharacterLiteral;
+ // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
+ for (int lookAhead = 0; lookAhead < 20; lookAhead++) {
+ if (currentPosition + lookAhead == source.length)
+ break;
+ if (source[currentPosition + lookAhead] == '\n')
+ break;
+ if (source[currentPosition + lookAhead] == '\'') {
+ currentPosition += lookAhead + 1;
+ break;
+ }
+ }
+ throw new InvalidInputException(INVALID_CHARACTER_CONSTANT);
+ case '"' :
+ try {
+ // consume next character
+ unicodeAsBackSlash = false;
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ getNextUnicodeChar();
+ } else {
+ if (withoutUnicodePtr != 0) {
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ }
+ }
+
+ while (currentCharacter != '"') {
+ /**** \r and \n are not valid in string literals ****/
+ if ((currentCharacter == '\n') || (currentCharacter == '\r')) {
+ // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
+ for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
+ if (currentPosition + lookAhead == source.length)
+ break;
+ if (source[currentPosition + lookAhead] == '\n')
+ break;
+ if (source[currentPosition + lookAhead] == '\"') {
+ currentPosition += lookAhead + 1;
+ break;
+ }
+ }
+ throw new InvalidInputException(INVALID_CHAR_IN_STRING);
+ }
+ if (currentCharacter == '\\') {
+ int escapeSize = currentPosition;
+ boolean backSlashAsUnicodeInString = unicodeAsBackSlash;
+ //scanEscapeCharacter make a side effect on this value and we need the previous value few lines down this one
+ scanEscapeCharacter();
+ escapeSize = currentPosition - escapeSize;
+ if (withoutUnicodePtr == 0) {
+ //buffer all the entries that have been left aside....
+ withoutUnicodePtr = currentPosition - escapeSize - 1 - startPosition;
+ System.arraycopy(
+ source,
+ startPosition,
+ withoutUnicodeBuffer,
+ 1,
+ withoutUnicodePtr);
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ } else { //overwrite the / in the buffer
+ withoutUnicodeBuffer[withoutUnicodePtr] = currentCharacter;
+ if (backSlashAsUnicodeInString) { //there are TWO \ in the stream where only one is correct
+ withoutUnicodePtr--;
+ }
+ }
+ }
+ // consume next character
+ unicodeAsBackSlash = false;
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ getNextUnicodeChar();
+ } else {
+ if (withoutUnicodePtr != 0) {
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ }
+ }
+
+ }
+ } catch (IndexOutOfBoundsException e) {
+ throw new InvalidInputException(UNTERMINATED_STRING);
+ } catch (InvalidInputException e) {
+ if (e.getMessage().equals(INVALID_ESCAPE)) {
+ // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
+ for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
+ if (currentPosition + lookAhead == source.length)
+ break;
+ if (source[currentPosition + lookAhead] == '\n')
+ break;
+ if (source[currentPosition + lookAhead] == '\"') {
+ currentPosition += lookAhead + 1;
+ break;
+ }
+ }
+
+ }
+ throw e; // rethrow
+ }
+ return TokenNameStringLiteral;
+ case '/' :
+ {
+ int test;
+ if ((test = getNextChar('/', '*')) == 0) { //line comment
+ try { //get the next char
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ //-------------unicode traitement ------------
+ int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
+ currentPosition++;
+ while (source[currentPosition] == 'u') {
+ currentPosition++;
+ }
+ if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c1 < 0
+ || (c2 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c2 < 0
+ || (c3 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c3 < 0
+ || (c4 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c4 < 0) {
+ throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
+ } else {
+ currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+ }
+ }
+
+ //handle the \\u case manually into comment
+ if (currentCharacter == '\\') {
+ if (source[currentPosition] == '\\')
+ currentPosition++;
+ } //jump over the \\
+ boolean isUnicode = false;
+ while (currentCharacter != '\r' && currentCharacter != '\n') {
+ //get the next char
+ isUnicode = false;
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ isUnicode = true;
+ //-------------unicode traitement ------------
+ int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
+ currentPosition++;
+ while (source[currentPosition] == 'u') {
+ currentPosition++;
+ }
+ if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c1 < 0
+ || (c2 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c2 < 0
+ || (c3 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c3 < 0
+ || (c4 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c4 < 0) {
+ throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
+ } else {
+ currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+ }
+ }
+ //handle the \\u case manually into comment
+ if (currentCharacter == '\\') {
+ if (source[currentPosition] == '\\')
+ currentPosition++;
+ } //jump over the \\
+ }
+ recordComment(false);
+ if (recordLineSeparator
+ && ((currentCharacter == '\r') || (currentCharacter == '\n')))
+ if (isUnicode) {
+ pushUnicodeLineSeparator();
+ } else {
+ pushLineSeparator();
+ }
+ if (tokenizeComments) {
+ if (!isUnicode) {
+ currentPosition--; // reset one character behind
+ }
+ return TokenNameCOMMENT_LINE;
+ }
+ } catch (IndexOutOfBoundsException e) { //an eof will them be generated
+ if (tokenizeComments) {
+ currentPosition--; // reset one character behind
+ return TokenNameCOMMENT_LINE;
+ }
+ }
+ break;
+ }
+ if (test > 0) { //traditional and annotation comment
+ boolean isJavadoc = false, star = false;
+ // consume next character
+ unicodeAsBackSlash = false;
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ getNextUnicodeChar();
+ } else {
+ if (withoutUnicodePtr != 0) {
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ }
+ }
+
+ if (currentCharacter == '*') {
+ isJavadoc = true;
+ star = true;
+ }
+ if (recordLineSeparator
+ && ((currentCharacter == '\r') || (currentCharacter == '\n')))
+ pushLineSeparator();
+ try { //get the next char
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ //-------------unicode traitement ------------
+ getNextUnicodeChar();
+ }
+ //handle the \\u case manually into comment
+ if (currentCharacter == '\\') {
+ if (source[currentPosition] == '\\')
+ currentPosition++; //jump over the \\
+ }
+ // empty comment is not a javadoc /**/
+ if (currentCharacter == '/') {
+ isJavadoc = false;
+ }
+ //loop until end of comment */
+ while ((currentCharacter != '/') || (!star)) {
+ if (recordLineSeparator
+ && ((currentCharacter == '\r') || (currentCharacter == '\n')))
+ pushLineSeparator();
+ star = currentCharacter == '*';
+ //get next char
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ //-------------unicode traitement ------------
+ getNextUnicodeChar();
+ }
+ //handle the \\u case manually into comment
+ if (currentCharacter == '\\') {
+ if (source[currentPosition] == '\\')
+ currentPosition++;
+ } //jump over the \\
+ }
+ recordComment(isJavadoc);
+ if (tokenizeComments) {
+ if (isJavadoc)
+ return TokenNameCOMMENT_JAVADOC;
+ return TokenNameCOMMENT_BLOCK;
+ }
+ } catch (IndexOutOfBoundsException e) {
+ throw new InvalidInputException(UNTERMINATED_COMMENT);
+ }
+ break;
+ }
+ if (getNextChar('='))
+ return TokenNameDIVIDE_EQUAL;
+ return TokenNameDIVIDE;
+ }
+ case '\u001a' :
+ if (atEnd())
+ return TokenNameEOF;
+ //the atEnd may not be <currentPosition == source.length> if source is only some part of a real (external) stream
+ throw new InvalidInputException("Ctrl-Z");
+
+ default :
+ if (Character.isJavaIdentifierStart(currentCharacter))
+ return scanIdentifierOrKeyword();
+ if (Character.isDigit(currentCharacter))
+ return scanNumber(false);
+ return TokenNameERROR;
+ }
+ }
+ } //-----------------end switch while try--------------------
+ catch (IndexOutOfBoundsException e) {
+ }
+ return TokenNameEOF;
+ }
+
+ public final void getNextUnicodeChar()
+ throws IndexOutOfBoundsException, InvalidInputException {
+ //VOID
+ //handle the case of unicode.
+ //when a unicode appears then we must use a buffer that holds char internal values
+ //At the end of this method currentCharacter holds the new visited char
+ //and currentPosition points right next after it
+
+ //ALL getNextChar.... ARE OPTIMIZED COPIES
+
+ int c1 = 0, c2 = 0, c3 = 0, c4 = 0, unicodeSize = 6;
+ currentPosition++;
+ while (source[currentPosition] == 'u') {
+ currentPosition++;
+ unicodeSize++;
+ }
+
+ if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c1 < 0
+ || (c2 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c2 < 0
+ || (c3 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c3 < 0
+ || (c4 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c4 < 0) {
+ throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
+ } else {
+ currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+ //need the unicode buffer
+ if (withoutUnicodePtr == 0) {
+ //buffer all the entries that have been left aside....
+ withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
+ System.arraycopy(
+ source,
+ startPosition,
+ withoutUnicodeBuffer,
+ 1,
+ withoutUnicodePtr);
+ }
+ //fill the buffer with the char
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ }
+ unicodeAsBackSlash = currentCharacter == '\\';
+ }
+
+ /* Tokenize a method body, assuming that curly brackets are properly balanced.
+ */
+ public final void jumpOverMethodBody() {
+
+ int found = 1;
+ try {
+ while (true) { //loop for jumping over comments
+ // ---------Consume white space and handles startPosition---------
+ boolean isWhiteSpace;
+ do {
+ startPosition = currentPosition;
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ isWhiteSpace = jumpOverUnicodeWhiteSpace();
+ } else {
+ if (recordLineSeparator
+ && ((currentCharacter == '\r') || (currentCharacter == '\n')))
+ pushLineSeparator();
+ isWhiteSpace = Character.isWhitespace(currentCharacter);
+ }
+ } while (isWhiteSpace);
+
+ // -------consume token until } is found---------
+ switch (currentCharacter) {
+ case '{' :
+ found++;
+ break;
+ case '}' :
+ found--;
+ if (found == 0)
+ return;
+ break;
+ case '\'' :
+ {
+ boolean test;
+ test = getNextChar('\\');
+ if (test) {
+ try {
+ scanEscapeCharacter();
+ } catch (InvalidInputException ex) {
+ };
+ } else {
+ try { // consume next character
+ unicodeAsBackSlash = false;
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ getNextUnicodeChar();
+ } else {
+ if (withoutUnicodePtr != 0) {
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ }
+ }
+ } catch (InvalidInputException ex) {
+ };
+ }
+ getNextChar('\'');
+ break;
+ }
+ case '"' :
+ try {
+ try { // consume next character
+ unicodeAsBackSlash = false;
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ getNextUnicodeChar();
+ } else {
+ if (withoutUnicodePtr != 0) {
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ }
+ }
+ } catch (InvalidInputException ex) {
+ };
+ while (currentCharacter != '"') {
+ if (currentCharacter == '\r') {
+ if (source[currentPosition] == '\n')
+ currentPosition++;
+ break; // the string cannot go further that the line
+ }
+ if (currentCharacter == '\n') {
+ break; // the string cannot go further that the line
+ }
+ if (currentCharacter == '\\') {
+ try {
+ scanEscapeCharacter();
+ } catch (InvalidInputException ex) {
+ };
+ }
+ try { // consume next character
+ unicodeAsBackSlash = false;
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ getNextUnicodeChar();
+ } else {
+ if (withoutUnicodePtr != 0) {
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ }
+ }
+ } catch (InvalidInputException ex) {
+ };
+ }
+ } catch (IndexOutOfBoundsException e) {
+ return;
+ }
+ break;
+ case '/' :
+ {
+ int test;
+ if ((test = getNextChar('/', '*')) == 0) { //line comment
+ try {
+ //get the next char
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ //-------------unicode traitement ------------
+ int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
+ currentPosition++;
+ while (source[currentPosition] == 'u') {
+ currentPosition++;
+ }
+ if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c1 < 0
+ || (c2 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c2 < 0
+ || (c3 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c3 < 0
+ || (c4 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c4 < 0) { //error don't care of the value
+ currentCharacter = 'A';
+ } //something different from \n and \r
+ else {
+ currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+ }
+ }
+
+ while (currentCharacter != '\r' && currentCharacter != '\n') {
+ //get the next char
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ //-------------unicode traitement ------------
+ int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
+ currentPosition++;
+ while (source[currentPosition] == 'u') {
+ currentPosition++;
+ }
+ if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c1 < 0
+ || (c2 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c2 < 0
+ || (c3 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c3 < 0
+ || (c4 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c4 < 0) { //error don't care of the value
+ currentCharacter = 'A';
+ } //something different from \n and \r
+ else {
+ currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+ }
+ }
+ }
+ if (recordLineSeparator
+ && ((currentCharacter == '\r') || (currentCharacter == '\n')))
+ pushLineSeparator();
+ } catch (IndexOutOfBoundsException e) {
+ } //an eof will them be generated
+ break;
+ }
+ if (test > 0) { //traditional and annotation comment
+ boolean star = false;
+ try { // consume next character
+ unicodeAsBackSlash = false;
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ getNextUnicodeChar();
+ } else {
+ if (withoutUnicodePtr != 0) {
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ }
+ };
+ } catch (InvalidInputException ex) {
+ };
+ if (currentCharacter == '*') {
+ star = true;
+ }
+ if (recordLineSeparator
+ && ((currentCharacter == '\r') || (currentCharacter == '\n')))
+ pushLineSeparator();
+ try { //get the next char
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ //-------------unicode traitement ------------
+ int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
+ currentPosition++;
+ while (source[currentPosition] == 'u') {
+ currentPosition++;
+ }
+ if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c1 < 0
+ || (c2 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c2 < 0
+ || (c3 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c3 < 0
+ || (c4 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c4 < 0) { //error don't care of the value
+ currentCharacter = 'A';
+ } //something different from * and /
+ else {
+ currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+ }
+ }
+ //loop until end of comment */
+ while ((currentCharacter != '/') || (!star)) {
+ if (recordLineSeparator
+ && ((currentCharacter == '\r') || (currentCharacter == '\n')))
+ pushLineSeparator();
+ star = currentCharacter == '*';
+ //get next char
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ //-------------unicode traitement ------------
+ int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
+ currentPosition++;
+ while (source[currentPosition] == 'u') {
+ currentPosition++;
+ }
+ if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c1 < 0
+ || (c2 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c2 < 0
+ || (c3 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c3 < 0
+ || (c4 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c4 < 0) { //error don't care of the value
+ currentCharacter = 'A';
+ } //something different from * and /
+ else {
+ currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+ }
+ }
+ }
+ } catch (IndexOutOfBoundsException e) {
+ return;
+ }
+ break;
+ }
+ break;
+ }
+
+ default :
+ if (Character.isJavaIdentifierStart(currentCharacter)) {
+ try {
+ scanIdentifierOrKeyword();
+ } catch (InvalidInputException ex) {
+ };
+ break;
+ }
+ if (Character.isDigit(currentCharacter)) {
+ try {
+ scanNumber(false);
+ } catch (InvalidInputException ex) {
+ };
+ break;
+ }
+ }
+ }
+ //-----------------end switch while try--------------------
+ } catch (IndexOutOfBoundsException e) {
+ } catch (InvalidInputException e) {
+ }
+ return;
+ }
+
+ public final boolean jumpOverUnicodeWhiteSpace() throws InvalidInputException {
+ //BOOLEAN
+ //handle the case of unicode. Jump over the next whiteSpace
+ //making startPosition pointing on the next available char
+ //On false, the currentCharacter is filled up with a potential
+ //correct char
+
+ int c1, c2, c3, c4;
+ int unicodeSize = 6;
+ currentPosition++;
+ while (source[currentPosition] == 'u') {
+ currentPosition++;
+ unicodeSize++;
+ }
+
+ if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+ || c1 < 0)
+ || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15 || c2 < 0)
+ || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15 || c3 < 0)
+ || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15 || c4 < 0)) {
+ throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
+ }
+
+ currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+ if (recordLineSeparator
+ && ((currentCharacter == '\r') || (currentCharacter == '\n')))
+ pushLineSeparator();
+ if (Character.isWhitespace(currentCharacter))
+ return true;
+
+ //buffer the new char which is not a white space
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ //withoutUnicodePtr == 1 is true here
+ return false;
+ }
+
+ public final int[] lineEnds() {
+ //return a bounded copy of this.lineEnds
+
+ int[] copy;
+ System.arraycopy(lineEnds, 0, copy = new int[linePtr + 1], 0, linePtr + 1);
+ return copy;
+ }
+
+ final char[] optimizedCurrentTokenSource1() {
+ //return always the same char[] build only once
+
+ //optimization at no speed cost of 99.5 % of the singleCharIdentifier
+ char charOne = source[startPosition];
+ switch (charOne) {
+ case 'a' :
+ return charArray_a;
+ case 'b' :
+ return charArray_b;
+ case 'c' :
+ return charArray_c;
+ case 'd' :
+ return charArray_d;
+ case 'e' :
+ return charArray_e;
+ case 'f' :
+ return charArray_f;
+ case 'g' :
+ return charArray_g;
+ case 'h' :
+ return charArray_h;
+ case 'i' :
+ return charArray_i;
+ case 'j' :
+ return charArray_j;
+ case 'k' :
+ return charArray_k;
+ case 'l' :
+ return charArray_l;
+ case 'm' :
+ return charArray_m;
+ case 'n' :
+ return charArray_n;
+ case 'o' :
+ return charArray_o;
+ case 'p' :
+ return charArray_p;
+ case 'q' :
+ return charArray_q;
+ case 'r' :
+ return charArray_r;
+ case 's' :
+ return charArray_s;
+ case 't' :
+ return charArray_t;
+ case 'u' :
+ return charArray_u;
+ case 'v' :
+ return charArray_v;
+ case 'w' :
+ return charArray_w;
+ case 'x' :
+ return charArray_x;
+ case 'y' :
+ return charArray_y;
+ case 'z' :
+ return charArray_z;
+ default :
+ return new char[] { charOne };
+ }
+ }
+
+ final char[] optimizedCurrentTokenSource2() {
+ //try to return the same char[] build only once
+
+ char c0, c1;
+ int hash =
+ (((c0 = source[startPosition]) << 6) + (c1 = source[startPosition + 1]))
+ % TableSize;
+ char[][] table = charArray_length[0][hash];
+ int i = newEntry2;
+ while (++i < InternalTableSize) {
+ char[] charArray = table[i];
+ if ((c0 == charArray[0]) && (c1 == charArray[1]))
+ return charArray;
+ }
+ //---------other side---------
+ i = -1;
+ int max = newEntry2;
+ while (++i <= max) {
+ char[] charArray = table[i];
+ if ((c0 == charArray[0]) && (c1 == charArray[1]))
+ return charArray;
+ }
+ //--------add the entry-------
+ if (++max >= InternalTableSize)
+ max = 0;
+ char[] r;
+ table[max] = (r = new char[] { c0, c1 });
+ newEntry2 = max;
+ return r;
+ }
+
+ final char[] optimizedCurrentTokenSource3() {
+ //try to return the same char[] build only once
+
+ char c0, c1, c2;
+ int hash =
+ (((c0 = source[startPosition]) << 12)
+ + ((c1 = source[startPosition + 1]) << 6)
+ + (c2 = source[startPosition + 2]))
+ % TableSize;
+ char[][] table = charArray_length[1][hash];
+ int i = newEntry3;
+ while (++i < InternalTableSize) {
+ char[] charArray = table[i];
+ if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]))
+ return charArray;
+ }
+ //---------other side---------
+ i = -1;
+ int max = newEntry3;
+ while (++i <= max) {
+ char[] charArray = table[i];
+ if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]))
+ return charArray;
+ }
+ //--------add the entry-------
+ if (++max >= InternalTableSize)
+ max = 0;
+ char[] r;
+ table[max] = (r = new char[] { c0, c1, c2 });
+ newEntry3 = max;
+ return r;
+ }
+
+ final char[] optimizedCurrentTokenSource4() {
+ //try to return the same char[] build only once
+
+ char c0, c1, c2, c3;
+ long hash =
+ ((((long) (c0 = source[startPosition])) << 18)
+ + ((c1 = source[startPosition + 1]) << 12)
+ + ((c2 = source[startPosition + 2]) << 6)
+ + (c3 = source[startPosition + 3]))
+ % TableSize;
+ char[][] table = charArray_length[2][(int) hash];
+ int i = newEntry4;
+ while (++i < InternalTableSize) {
+ char[] charArray = table[i];
+ if ((c0 == charArray[0])
+ && (c1 == charArray[1])
+ && (c2 == charArray[2])
+ && (c3 == charArray[3]))
+ return charArray;
+ }
+ //---------other side---------
+ i = -1;
+ int max = newEntry4;
+ while (++i <= max) {
+ char[] charArray = table[i];
+ if ((c0 == charArray[0])
+ && (c1 == charArray[1])
+ && (c2 == charArray[2])
+ && (c3 == charArray[3]))
+ return charArray;
+ }
+ //--------add the entry-------
+ if (++max >= InternalTableSize)
+ max = 0;
+ char[] r;
+ table[max] = (r = new char[] { c0, c1, c2, c3 });
+ newEntry4 = max;
+ return r;
+
+ }
+
+ final char[] optimizedCurrentTokenSource5() {
+ //try to return the same char[] build only once
+
+ char c0, c1, c2, c3, c4;
+ long hash =
+ ((((long) (c0 = source[startPosition])) << 24)
+ + (((long) (c1 = source[startPosition + 1])) << 18)
+ + ((c2 = source[startPosition + 2]) << 12)
+ + ((c3 = source[startPosition + 3]) << 6)
+ + (c4 = source[startPosition + 4]))
+ % TableSize;
+ char[][] table = charArray_length[3][(int) hash];
+ int i = newEntry5;
+ while (++i < InternalTableSize) {
+ char[] charArray = table[i];
+ if ((c0 == charArray[0])
+ && (c1 == charArray[1])
+ && (c2 == charArray[2])
+ && (c3 == charArray[3])
+ && (c4 == charArray[4]))
+ return charArray;
+ }
+ //---------other side---------
+ i = -1;
+ int max = newEntry5;
+ while (++i <= max) {
+ char[] charArray = table[i];
+ if ((c0 == charArray[0])
+ && (c1 == charArray[1])
+ && (c2 == charArray[2])
+ && (c3 == charArray[3])
+ && (c4 == charArray[4]))
+ return charArray;
+ }
+ //--------add the entry-------
+ if (++max >= InternalTableSize)
+ max = 0;
+ char[] r;
+ table[max] = (r = new char[] { c0, c1, c2, c3, c4 });
+ newEntry5 = max;
+ return r;
+
+ }
+
+ final char[] optimizedCurrentTokenSource6() {
+ //try to return the same char[] build only once
+
+ char c0, c1, c2, c3, c4, c5;
+ long hash =
+ ((((long) (c0 = source[startPosition])) << 32)
+ + (((long) (c1 = source[startPosition + 1])) << 24)
+ + (((long) (c2 = source[startPosition + 2])) << 18)
+ + ((c3 = source[startPosition + 3]) << 12)
+ + ((c4 = source[startPosition + 4]) << 6)
+ + (c5 = source[startPosition + 5]))
+ % TableSize;
+ char[][] table = charArray_length[4][(int) hash];
+ int i = newEntry6;
+ while (++i < InternalTableSize) {
+ char[] charArray = table[i];
+ if ((c0 == charArray[0])
+ && (c1 == charArray[1])
+ && (c2 == charArray[2])
+ && (c3 == charArray[3])
+ && (c4 == charArray[4])
+ && (c5 == charArray[5]))
+ return charArray;
+ }
+ //---------other side---------
+ i = -1;
+ int max = newEntry6;
+ while (++i <= max) {
+ char[] charArray = table[i];
+ if ((c0 == charArray[0])
+ && (c1 == charArray[1])
+ && (c2 == charArray[2])
+ && (c3 == charArray[3])
+ && (c4 == charArray[4])
+ && (c5 == charArray[5]))
+ return charArray;
+ }
+ //--------add the entry-------
+ if (++max >= InternalTableSize)
+ max = 0;
+ char[] r;
+ table[max] = (r = new char[] { c0, c1, c2, c3, c4, c5 });
+ newEntry6 = max;
+ return r;
+ }
+
+ public final void pushLineSeparator() {
+ //see comment on isLineDelimiter(char) for the use of '\n' and '\r'
+
+ final int INCREMENT = 250;
+
+ //currentCharacter is at position currentPosition-1
+
+ // cr 000D
+ if (currentCharacter == '\r') {
+ int separatorPos = currentPosition - 1;
+ if ((linePtr > 0) && (lineEnds[linePtr] >= separatorPos))
+ return;
+ //System.out.println("CR-" + separatorPos);
+ try {
+ lineEnds[++linePtr] = separatorPos;
+ } catch (IndexOutOfBoundsException e) {
+ //linePtr value is correct
+ int oldLength = lineEnds.length;
+ int[] old = lineEnds;
+ lineEnds = new int[oldLength + INCREMENT];
+ System.arraycopy(old, 0, lineEnds, 0, oldLength);
+ lineEnds[linePtr] = separatorPos;
+ }
+ // look-ahead for merged cr+lf
+ if (source[currentPosition] == '\n') {
+ //System.out.println("look-ahead LF-" + currentPosition);
+ lineEnds[linePtr] = currentPosition;
+ currentPosition++;
+ wasAcr = false;
+ } else {
+ wasAcr = true;
+ }
+ } else {
+ // lf 000A
+ if (currentCharacter == '\n') { //must merge eventual cr followed by lf
+ if (wasAcr && (lineEnds[linePtr] == (currentPosition - 2))) {
+ //System.out.println("merge LF-" + (currentPosition - 1));
+ lineEnds[linePtr] = currentPosition - 1;
+ } else {
+ int separatorPos = currentPosition - 1;
+ if ((linePtr > 0) && (lineEnds[linePtr] >= separatorPos))
+ return;
+ // System.out.println("LF-" + separatorPos);
+ try {
+ lineEnds[++linePtr] = separatorPos;
+ } catch (IndexOutOfBoundsException e) {
+ //linePtr value is correct
+ int oldLength = lineEnds.length;
+ int[] old = lineEnds;
+ lineEnds = new int[oldLength + INCREMENT];
+ System.arraycopy(old, 0, lineEnds, 0, oldLength);
+ lineEnds[linePtr] = separatorPos;
+ }
+ }
+ wasAcr = false;
+ }
+ }
+ }
+
+ public final void pushUnicodeLineSeparator() {
+ // isUnicode means that the \r or \n has been read as a unicode character
+
+ //see comment on isLineDelimiter(char) for the use of '\n' and '\r'
+
+ final int INCREMENT = 250;
+ //currentCharacter is at position currentPosition-1
+
+ // cr 000D
+ if (currentCharacter == '\r') {
+ int separatorPos = currentPosition - 6;
+ if ((linePtr > 0) && (lineEnds[linePtr] >= separatorPos))
+ return;
+ //System.out.println("CR-" + separatorPos);
+ try {
+ lineEnds[++linePtr] = separatorPos;
+ } catch (IndexOutOfBoundsException e) {
+ //linePtr value is correct
+ int oldLength = lineEnds.length;
+ int[] old = lineEnds;
+ lineEnds = new int[oldLength + INCREMENT];
+ System.arraycopy(old, 0, lineEnds, 0, oldLength);
+ lineEnds[linePtr] = separatorPos;
+ }
+ // look-ahead for merged cr+lf
+ if (source[currentPosition] == '\n') {
+ //System.out.println("look-ahead LF-" + currentPosition);
+ lineEnds[linePtr] = currentPosition;
+ currentPosition++;
+ wasAcr = false;
+ } else {
+ wasAcr = true;
+ }
+ } else {
+ // lf 000A
+ if (currentCharacter == '\n') { //must merge eventual cr followed by lf
+ if (wasAcr && (lineEnds[linePtr] == (currentPosition - 7))) {
+ //System.out.println("merge LF-" + (currentPosition - 1));
+ lineEnds[linePtr] = currentPosition - 6;
+ } else {
+ int separatorPos = currentPosition - 6;
+ if ((linePtr > 0) && (lineEnds[linePtr] >= separatorPos))
+ return;
+ // System.out.println("LF-" + separatorPos);
+ try {
+ lineEnds[++linePtr] = separatorPos;
+ } catch (IndexOutOfBoundsException e) {
+ //linePtr value is correct
+ int oldLength = lineEnds.length;
+ int[] old = lineEnds;
+ lineEnds = new int[oldLength + INCREMENT];
+ System.arraycopy(old, 0, lineEnds, 0, oldLength);
+ lineEnds[linePtr] = separatorPos;
+ }
+ }
+ wasAcr = false;
+ }
+ }
+ }
+
+ public final void recordComment(boolean isJavadoc) {
+
+ // a new annotation comment is recorded
+ try {
+ commentStops[++commentPtr] = isJavadoc ? currentPosition : -currentPosition;
+ } catch (IndexOutOfBoundsException e) {
+ int oldStackLength = commentStops.length;
+ int[] oldStack = commentStops;
+ commentStops = new int[oldStackLength + 30];
+ System.arraycopy(oldStack, 0, commentStops, 0, oldStackLength);
+ commentStops[commentPtr] = isJavadoc ? currentPosition : -currentPosition;
+ //grows the positions buffers too
+ int[] old = commentStarts;
+ commentStarts = new int[oldStackLength + 30];
+ System.arraycopy(old, 0, commentStarts, 0, oldStackLength);
+ }
+
+ //the buffer is of a correct size here
+ commentStarts[commentPtr] = startPosition;
+ }
+
+ public void resetTo(int begin, int end) {
+ //reset the scanner to a given position where it may rescan again
+
+ diet = false;
+ initialPosition = startPosition = currentPosition = begin;
+ eofPosition = end + 1;
+ commentPtr = -1; // reset comment stack
+ }
+
+ public final void scanEscapeCharacter() throws InvalidInputException {
+ // the string with "\\u" is a legal string of two chars \ and u
+ //thus we use a direct access to the source (for regular cases).
+
+ if (unicodeAsBackSlash) {
+ // consume next character
+ unicodeAsBackSlash = false;
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ getNextUnicodeChar();
+ } else {
+ if (withoutUnicodePtr != 0) {
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ }
+ }
+ } else
+ currentCharacter = source[currentPosition++];
+ switch (currentCharacter) {
+ case 'b' :
+ currentCharacter = '\b';
+ break;
+ case 't' :
+ currentCharacter = '\t';
+ break;
+ case 'n' :
+ currentCharacter = '\n';
+ break;
+ case 'f' :
+ currentCharacter = '\f';
+ break;
+ case 'r' :
+ currentCharacter = '\r';
+ break;
+ case '\"' :
+ currentCharacter = '\"';
+ break;
+ case '\'' :
+ currentCharacter = '\'';
+ break;
+ case '\\' :
+ currentCharacter = '\\';
+ break;
+ default :
+ // -----------octal escape--------------
+ // OctalDigit
+ // OctalDigit OctalDigit
+ // ZeroToThree OctalDigit OctalDigit
+
+ int number = Character.getNumericValue(currentCharacter);
+ if (number >= 0 && number <= 7) {
+ boolean zeroToThreeNot = number > 3;
+ if (Character.isDigit(currentCharacter = source[currentPosition++])) {
+ int digit = Character.getNumericValue(currentCharacter);
+ if (digit >= 0 && digit <= 7) {
+ number = (number * 8) + digit;
+ if (Character.isDigit(currentCharacter = source[currentPosition++])) {
+ if (zeroToThreeNot) { // has read \NotZeroToThree OctalDigit Digit --> ignore last character
+ currentPosition--;
+ } else {
+ digit = Character.getNumericValue(currentCharacter);
+ if (digit >= 0 && digit <= 7) { // has read \ZeroToThree OctalDigit OctalDigit
+ number = (number * 8) + digit;
+ } else { // has read \ZeroToThree OctalDigit NonOctalDigit --> ignore last character
+ currentPosition--;
+ }
+ }
+ } else { // has read \OctalDigit NonDigit--> ignore last character
+ currentPosition--;
+ }
+ } else { // has read \OctalDigit NonOctalDigit--> ignore last character
+ currentPosition--;
+ }
+ } else { // has read \OctalDigit --> ignore last character
+ currentPosition--;
+ }
+ if (number > 255)
+ throw new InvalidInputException(INVALID_ESCAPE);
+ currentCharacter = (char) number;
+ } else
+ throw new InvalidInputException(INVALID_ESCAPE);
+ }
+ }
+
+ public int scanIdentifierOrKeyword() throws InvalidInputException {
+ //test keywords
+
+ //first dispatch on the first char.
+ //then the length. If there are several
+ //keywors with the same length AND the same first char, then do another
+ //disptach on the second char :-)...cool....but fast !
+
+ while (getNextCharAsJavaIdentifierPart()) {
+ };
+
+ int index, length;
+ char[] data;
+ char firstLetter;
+ if (withoutUnicodePtr == 0)
+
+ //quick test on length == 1 but not on length > 12 while most identifier
+ //have a length which is <= 12...but there are lots of identifier with
+ //only one char....
+
+ {
+ if ((length = currentPosition - startPosition) == 1)
+ return TokenNameIdentifier;
+ data = source;
+ index = startPosition;
+ } else {
+ if ((length = withoutUnicodePtr) == 1)
+ return TokenNameIdentifier;
+ data = withoutUnicodeBuffer;
+ index = 1;
+ }
+
+ firstLetter = data[index];
+ switch (firstLetter) {
+
+ case 'a' : //abstract
+ if (length == 8) {
+ if ((data[++index] == 'b')
+ && (data[++index] == 's')
+ && (data[++index] == 't')
+ && (data[++index] == 'r')
+ && (data[++index] == 'a')
+ && (data[++index] == 'c')
+ && (data[++index] == 't')) {
+ return TokenNameabstract;
+ }
+ }
+ return TokenNameIdentifier;
+
+ case 'b' : //boolean break byte
+ switch (length) {
+ case 4 :
+ if ((data[++index] == 'y') && (data[++index] == 't') && (data[++index] == 'e'))
+ return TokenNamebyte;
+ else
+ return TokenNameIdentifier;
+ case 5 :
+ if ((data[++index] == 'r')
+ && (data[++index] == 'e')
+ && (data[++index] == 'a')
+ && (data[++index] == 'k'))
+ return TokenNamebreak;
+ else
+ return TokenNameIdentifier;
+ case 7 :
+ if ((data[++index] == 'o')
+ && (data[++index] == 'o')
+ && (data[++index] == 'l')
+ && (data[++index] == 'e')
+ && (data[++index] == 'a')
+ && (data[++index] == 'n'))
+ return TokenNameboolean;
+ else
+ return TokenNameIdentifier;
+ default :
+ return TokenNameIdentifier;
+ }
+
+ case 'c' : //case char catch const class continue
+ switch (length) {
+ case 4 :
+ if (data[++index] == 'a')
+ if ((data[++index] == 's') && (data[++index] == 'e'))
+ return TokenNamecase;
+ else
+ return TokenNameIdentifier;
+ else
+ if ((data[index] == 'h') && (data[++index] == 'a') && (data[++index] == 'r'))
+ return TokenNamechar;
+ else
+ return TokenNameIdentifier;
+ case 5 :
+ if (data[++index] == 'a')
+ if ((data[++index] == 't') && (data[++index] == 'c') && (data[++index] == 'h'))
+ return TokenNamecatch;
+ else
+ return TokenNameIdentifier;
+ else
+ if ((data[index] == 'l')
+ && (data[++index] == 'a')
+ && (data[++index] == 's')
+ && (data[++index] == 's'))
+ return TokenNameclass;
+ else
+ if ((data[index] == 'o')
+ && (data[++index] == 'n')
+ && (data[++index] == 's')
+ && (data[++index] == 't'))
+ return TokenNameERROR; //const is not used in java ???????
+ else
+ return TokenNameIdentifier;
+ case 8 :
+ if ((data[++index] == 'o')
+ && (data[++index] == 'n')
+ && (data[++index] == 't')
+ && (data[++index] == 'i')
+ && (data[++index] == 'n')
+ && (data[++index] == 'u')
+ && (data[++index] == 'e'))
+ return TokenNamecontinue;
+ else
+ return TokenNameIdentifier;
+ default :
+ return TokenNameIdentifier;
+ }
+
+ case 'd' : //default do double
+ switch (length) {
+ case 2 :
+ if ((data[++index] == 'o'))
+ return TokenNamedo;
+ else
+ return TokenNameIdentifier;
+ case 6 :
+ if ((data[++index] == 'o')
+ && (data[++index] == 'u')
+ && (data[++index] == 'b')
+ && (data[++index] == 'l')
+ && (data[++index] == 'e'))
+ return TokenNamedouble;
+ else
+ return TokenNameIdentifier;
+ case 7 :
+ if ((data[++index] == 'e')
+ && (data[++index] == 'f')
+ && (data[++index] == 'a')
+ && (data[++index] == 'u')
+ && (data[++index] == 'l')
+ && (data[++index] == 't'))
+ return TokenNamedefault;
+ else
+ return TokenNameIdentifier;
+ default :
+ return TokenNameIdentifier;
+ }
+ case 'e' : //else extends
+ switch (length) {
+ case 4 :
+ if ((data[++index] == 'l') && (data[++index] == 's') && (data[++index] == 'e'))
+ return TokenNameelse;
+ else
+ return TokenNameIdentifier;
+ case 7 :
+ if ((data[++index] == 'x')
+ && (data[++index] == 't')
+ && (data[++index] == 'e')
+ && (data[++index] == 'n')
+ && (data[++index] == 'd')
+ && (data[++index] == 's'))
+ return TokenNameextends;
+ else
+ return TokenNameIdentifier;
+ default :
+ return TokenNameIdentifier;
+ }
+
+ case 'f' : //final finally float for false
+ switch (length) {
+ case 3 :
+ if ((data[++index] == 'o') && (data[++index] == 'r'))
+ return TokenNamefor;
+ else
+ return TokenNameIdentifier;
+ case 5 :
+ if (data[++index] == 'i')
+ if ((data[++index] == 'n')
+ && (data[++index] == 'a')
+ && (data[++index] == 'l')) {
+ return TokenNamefinal;
+ } else
+ return TokenNameIdentifier;
+ else
+ if ((data[index] == 'l')
+ && (data[++index] == 'o')
+ && (data[++index] == 'a')
+ && (data[++index] == 't'))
+ return TokenNamefloat;
+ else
+ if ((data[index] == 'a')
+ && (data[++index] == 'l')
+ && (data[++index] == 's')
+ && (data[++index] == 'e'))
+ return TokenNamefalse;
+ else
+ return TokenNameIdentifier;
+ case 7 :
+ if ((data[++index] == 'i')
+ && (data[++index] == 'n')
+ && (data[++index] == 'a')
+ && (data[++index] == 'l')
+ && (data[++index] == 'l')
+ && (data[++index] == 'y'))
+ return TokenNamefinally;
+ else
+ return TokenNameIdentifier;
+
+ default :
+ return TokenNameIdentifier;
+ }
+ case 'g' : //goto
+ if (length == 4) {
+ if ((data[++index] == 'o')
+ && (data[++index] == 't')
+ && (data[++index] == 'o')) {
+ return TokenNameERROR;
+ }
+ } //no goto in java are allowed, so why java removes this keyword ???
+ return TokenNameIdentifier;
+
+ case 'i' : //if implements import instanceof int interface
+ switch (length) {
+ case 2 :
+ if (data[++index] == 'f')
+ return TokenNameif;
+ else
+ return TokenNameIdentifier;
+ case 3 :
+ if ((data[++index] == 'n') && (data[++index] == 't'))
+ return TokenNameint;
+ else
+ return TokenNameIdentifier;
+ case 6 :
+ if ((data[++index] == 'm')
+ && (data[++index] == 'p')
+ && (data[++index] == 'o')
+ && (data[++index] == 'r')
+ && (data[++index] == 't'))
+ return TokenNameimport;
+ else
+ return TokenNameIdentifier;
+ case 9 :
+ if ((data[++index] == 'n')
+ && (data[++index] == 't')
+ && (data[++index] == 'e')
+ && (data[++index] == 'r')
+ && (data[++index] == 'f')
+ && (data[++index] == 'a')
+ && (data[++index] == 'c')
+ && (data[++index] == 'e'))
+ return TokenNameinterface;
+ else
+ return TokenNameIdentifier;
+ case 10 :
+ if (data[++index] == 'm')
+ if ((data[++index] == 'p')
+ && (data[++index] == 'l')
+ && (data[++index] == 'e')
+ && (data[++index] == 'm')
+ && (data[++index] == 'e')
+ && (data[++index] == 'n')
+ && (data[++index] == 't')
+ && (data[++index] == 's'))
+ return TokenNameimplements;
+ else
+ return TokenNameIdentifier;
+ else
+ if ((data[index] == 'n')
+ && (data[++index] == 's')
+ && (data[++index] == 't')
+ && (data[++index] == 'a')
+ && (data[++index] == 'n')
+ && (data[++index] == 'c')
+ && (data[++index] == 'e')
+ && (data[++index] == 'o')
+ && (data[++index] == 'f'))
+ return TokenNameinstanceof;
+ else
+ return TokenNameIdentifier;
+
+ default :
+ return TokenNameIdentifier;
+ }
+
+ case 'l' : //long
+ if (length == 4) {
+ if ((data[++index] == 'o')
+ && (data[++index] == 'n')
+ && (data[++index] == 'g')) {
+ return TokenNamelong;
+ }
+ }
+ return TokenNameIdentifier;
+
+ case 'n' : //native new null
+ switch (length) {
+ case 3 :
+ if ((data[++index] == 'e') && (data[++index] == 'w'))
+ return TokenNamenew;
+ else
+ return TokenNameIdentifier;
+ case 4 :
+ if ((data[++index] == 'u') && (data[++index] == 'l') && (data[++index] == 'l'))
+ return TokenNamenull;
+ else
+ return TokenNameIdentifier;
+ case 6 :
+ if ((data[++index] == 'a')
+ && (data[++index] == 't')
+ && (data[++index] == 'i')
+ && (data[++index] == 'v')
+ && (data[++index] == 'e')) {
+ return TokenNamenative;
+ } else
+ return TokenNameIdentifier;
+ default :
+ return TokenNameIdentifier;
+ }
+
+ case 'p' : //package private protected public
+ switch (length) {
+ case 6 :
+ if ((data[++index] == 'u')
+ && (data[++index] == 'b')
+ && (data[++index] == 'l')
+ && (data[++index] == 'i')
+ && (data[++index] == 'c')) {
+ return TokenNamepublic;
+ } else
+ return TokenNameIdentifier;
+ case 7 :
+ if (data[++index] == 'a')
+ if ((data[++index] == 'c')
+ && (data[++index] == 'k')
+ && (data[++index] == 'a')
+ && (data[++index] == 'g')
+ && (data[++index] == 'e'))
+ return TokenNamepackage;
+ else
+ return TokenNameIdentifier;
+ else
+ if ((data[index] == 'r')
+ && (data[++index] == 'i')
+ && (data[++index] == 'v')
+ && (data[++index] == 'a')
+ && (data[++index] == 't')
+ && (data[++index] == 'e')) {
+ return TokenNameprivate;
+ } else
+ return TokenNameIdentifier;
+ case 9 :
+ if ((data[++index] == 'r')
+ && (data[++index] == 'o')
+ && (data[++index] == 't')
+ && (data[++index] == 'e')
+ && (data[++index] == 'c')
+ && (data[++index] == 't')
+ && (data[++index] == 'e')
+ && (data[++index] == 'd')) {
+ return TokenNameprotected;
+ } else
+ return TokenNameIdentifier;
+
+ default :
+ return TokenNameIdentifier;
+ }
+
+ case 'r' : //return
+ if (length == 6) {
+ if ((data[++index] == 'e')
+ && (data[++index] == 't')
+ && (data[++index] == 'u')
+ && (data[++index] == 'r')
+ && (data[++index] == 'n')) {
+ return TokenNamereturn;
+ }
+ }
+ return TokenNameIdentifier;
+
+ case 's' : //short static super switch synchronized strictfp
+ switch (length) {
+ case 5 :
+ if (data[++index] == 'h')
+ if ((data[++index] == 'o') && (data[++index] == 'r') && (data[++index] == 't'))
+ return TokenNameshort;
+ else
+ return TokenNameIdentifier;
+ else
+ if ((data[index] == 'u')
+ && (data[++index] == 'p')
+ && (data[++index] == 'e')
+ && (data[++index] == 'r'))
+ return TokenNamesuper;
+ else
+ return TokenNameIdentifier;
+
+ case 6 :
+ if (data[++index] == 't')
+ if ((data[++index] == 'a')
+ && (data[++index] == 't')
+ && (data[++index] == 'i')
+ && (data[++index] == 'c')) {
+ return TokenNamestatic;
+ } else
+ return TokenNameIdentifier;
+ else
+ if ((data[index] == 'w')
+ && (data[++index] == 'i')
+ && (data[++index] == 't')
+ && (data[++index] == 'c')
+ && (data[++index] == 'h'))
+ return TokenNameswitch;
+ else
+ return TokenNameIdentifier;
+ case 8 :
+ if ((data[++index] == 't')
+ && (data[++index] == 'r')
+ && (data[++index] == 'i')
+ && (data[++index] == 'c')
+ && (data[++index] == 't')
+ && (data[++index] == 'f')
+ && (data[++index] == 'p'))
+ return TokenNamestrictfp;
+ else
+ return TokenNameIdentifier;
+ case 12 :
+ if ((data[++index] == 'y')
+ && (data[++index] == 'n')
+ && (data[++index] == 'c')
+ && (data[++index] == 'h')
+ && (data[++index] == 'r')
+ && (data[++index] == 'o')
+ && (data[++index] == 'n')
+ && (data[++index] == 'i')
+ && (data[++index] == 'z')
+ && (data[++index] == 'e')
+ && (data[++index] == 'd')) {
+ return TokenNamesynchronized;
+ } else
+ return TokenNameIdentifier;
+ default :
+ return TokenNameIdentifier;
+ }
+
+ case 't' : //try throw throws transient this true
+ switch (length) {
+ case 3 :
+ if ((data[++index] == 'r') && (data[++index] == 'y'))
+ return TokenNametry;
+ else
+ return TokenNameIdentifier;
+ case 4 :
+ if ((data[++index] == 'h') && (data[++index] == 'i') && (data[++index] == 's'))
+ return TokenNamethis;
+ else
+ if ((data[index] == 'r') && (data[++index] == 'u') && (data[++index] == 'e'))
+ return TokenNametrue;
+ else
+ return TokenNameIdentifier;
+ case 5 :
+ if ((data[++index] == 'h')
+ && (data[++index] == 'r')
+ && (data[++index] == 'o')
+ && (data[++index] == 'w'))
+ return TokenNamethrow;
+ else
+ return TokenNameIdentifier;
+ case 6 :
+ if ((data[++index] == 'h')
+ && (data[++index] == 'r')
+ && (data[++index] == 'o')
+ && (data[++index] == 'w')
+ && (data[++index] == 's'))
+ return TokenNamethrows;
+ else
+ return TokenNameIdentifier;
+ case 9 :
+ if ((data[++index] == 'r')
+ && (data[++index] == 'a')
+ && (data[++index] == 'n')
+ && (data[++index] == 's')
+ && (data[++index] == 'i')
+ && (data[++index] == 'e')
+ && (data[++index] == 'n')
+ && (data[++index] == 't')) {
+ return TokenNametransient;
+ } else
+ return TokenNameIdentifier;
+
+ default :
+ return TokenNameIdentifier;
+ }
+
+ case 'v' : //void volatile
+ switch (length) {
+ case 4 :
+ if ((data[++index] == 'o') && (data[++index] == 'i') && (data[++index] == 'd'))
+ return TokenNamevoid;
+ else
+ return TokenNameIdentifier;
+ case 8 :
+ if ((data[++index] == 'o')
+ && (data[++index] == 'l')
+ && (data[++index] == 'a')
+ && (data[++index] == 't')
+ && (data[++index] == 'i')
+ && (data[++index] == 'l')
+ && (data[++index] == 'e')) {
+ return TokenNamevolatile;
+ } else
+ return TokenNameIdentifier;
+
+ default :
+ return TokenNameIdentifier;
+ }
+
+ case 'w' : //while widefp
+ switch (length) {
+ case 5 :
+ if ((data[++index] == 'h')
+ && (data[++index] == 'i')
+ && (data[++index] == 'l')
+ && (data[++index] == 'e'))
+ return TokenNamewhile;
+ else
+ return TokenNameIdentifier;
+ //case 6:if ( (data[++index] =='i') && (data[++index]=='d') && (data[++index]=='e') && (data[++index]=='f')&& (data[++index]=='p'))
+ //return TokenNamewidefp ;
+ //else
+ //return TokenNameIdentifier;
+ default :
+ return TokenNameIdentifier;
+ }
+
+ default :
+ return TokenNameIdentifier;
+ }
+ }
+
+ public int scanNumber(boolean dotPrefix) throws InvalidInputException {
+
+ //when entering this method the currentCharacter is the firt
+ //digit of the number , i.e. it may be preceeded by a . when
+ //dotPrefix is true
+
+ boolean floating = dotPrefix;
+ if ((!dotPrefix) && (currentCharacter == '0')) {
+ if (getNextChar('x', 'X') >= 0) { //----------hexa-----------------
+ //force the first char of the hexa number do exist...
+ // consume next character
+ unicodeAsBackSlash = false;
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ getNextUnicodeChar();
+ } else {
+ if (withoutUnicodePtr != 0) {
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ }
+ }
+ if (Character.digit(currentCharacter, 16) == -1)
+ throw new InvalidInputException(INVALID_HEXA);
+ //---end forcing--
+ while (getNextCharAsDigit(16)) {
+ };
+ if (getNextChar('l', 'L') >= 0)
+ return TokenNameLongLiteral;
+ else
+ return TokenNameIntegerLiteral;
+ }
+
+ //there is x or X in the number
+ //potential octal ! ... some one may write 000099.0 ! thus 00100 < 00078.0 is true !!!!! crazy language
+ if (getNextCharAsDigit()) { //-------------potential octal-----------------
+ while (getNextCharAsDigit()) {
+ };
+
+ if (getNextChar('l', 'L') >= 0) {
+ return TokenNameLongLiteral;
+ }
+
+ if (getNextChar('f', 'F') >= 0) {
+ return TokenNameFloatingPointLiteral;
+ }
+
+ if (getNextChar('d', 'D') >= 0) {
+ return TokenNameDoubleLiteral;
+ } else { //make the distinction between octal and float ....
+ if (getNextChar('.')) { //bingo ! ....
+ while (getNextCharAsDigit()) {
+ };
+ if (getNextChar('e', 'E') >= 0) { // consume next character
+ unicodeAsBackSlash = false;
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ getNextUnicodeChar();
+ } else {
+ if (withoutUnicodePtr != 0) {
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ }
+ }
+
+ if ((currentCharacter == '-')
+ || (currentCharacter == '+')) { // consume next character
+ unicodeAsBackSlash = false;
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ getNextUnicodeChar();
+ } else {
+ if (withoutUnicodePtr != 0) {
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ }
+ }
+ }
+ if (!Character.isDigit(currentCharacter))
+ throw new InvalidInputException(INVALID_FLOAT);
+ while (getNextCharAsDigit()) {
+ };
+ }
+ if (getNextChar('f', 'F') >= 0)
+ return TokenNameFloatingPointLiteral;
+ getNextChar('d', 'D'); //jump over potential d or D
+ return TokenNameDoubleLiteral;
+ } else {
+ return TokenNameIntegerLiteral;
+ }
+ }
+ } else {
+ /* carry on */
+ }
+ }
+
+ while (getNextCharAsDigit()) {
+ };
+
+ if ((!dotPrefix) && (getNextChar('l', 'L') >= 0))
+ return TokenNameLongLiteral;
+
+ if ((!dotPrefix) && (getNextChar('.'))) { //decimal part that can be empty
+ while (getNextCharAsDigit()) {
+ };
+ floating = true;
+ }
+
+ //if floating is true both exponant and suffix may be optional
+
+ if (getNextChar('e', 'E') >= 0) {
+ floating = true;
+ // consume next character
+ unicodeAsBackSlash = false;
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ getNextUnicodeChar();
+ } else {
+ if (withoutUnicodePtr != 0) {
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ }
+ }
+
+ if ((currentCharacter == '-')
+ || (currentCharacter == '+')) { // consume next character
+ unicodeAsBackSlash = false;
+ if (((currentCharacter = source[currentPosition++]) == '\\')
+ && (source[currentPosition] == 'u')) {
+ getNextUnicodeChar();
+ } else {
+ if (withoutUnicodePtr != 0) {
+ withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+ }
+ }
+ }
+ if (!Character.isDigit(currentCharacter))
+ throw new InvalidInputException(INVALID_FLOAT);
+ while (getNextCharAsDigit()) {
+ };
+ }
+
+ if (getNextChar('d', 'D') >= 0)
+ return TokenNameDoubleLiteral;
+ if (getNextChar('f', 'F') >= 0)
+ return TokenNameFloatingPointLiteral;
+
+ //the long flag has been tested before
+
+ return floating ? TokenNameDoubleLiteral : TokenNameIntegerLiteral;
+ }
+
+ /**
+ * Search the line number corresponding to a specific position
+ *
+ */
+ public final int searchLineNumber(int position) {
+
+ if (lineEnds == null)
+ return 1;
+ int length = linePtr + 1;
+ if (length == 0)
+ return 1;
+ int g = 0, d = length - 1;
+ int m = 0;
+ while (g <= d) {
+ m = (g + d) / 2;
+ if (position < lineEnds[m]) {
+ d = m - 1;
+ } else
+ if (position > lineEnds[m]) {
+ g = m + 1;
+ } else {
+ return m + 1;
+ }
+ }
+ if (position < lineEnds[m]) {
+ return m + 1;
+ }
+ return m + 2;
+ }
+
+ public final void setSourceBuffer(char[] sourceString) {
+ //the source-buffer is set to sourceString
+
+ source = sourceString;
+ startPosition = -1;
+ initialPosition = currentPosition = 0;
+ if (source == null) {
+ source = new char[0];
+ }
+ withoutUnicodeBuffer = new char[source.length];
+ }
+
+ public String toString() {
+ if (startPosition == source.length)
+ return "EOF\n\n" + new String(source);
+ if (currentPosition > source.length)
+ return "behind the EOF :-( ....\n\n" + new String(source);
+
+ char front[] = new char[startPosition];
+ System.arraycopy(source, 0, front, 0, startPosition);
+
+ int middleLength = (currentPosition - 1) - startPosition + 1;
+ char middle[];
+ if (middleLength > -1) {
+ middle = new char[middleLength];
+ System.arraycopy(source, startPosition, middle, 0, middleLength);
+ } else {
+ middle = new char[0];
+ }
+
+ char end[] = new char[source.length - (currentPosition - 1)];
+ System.arraycopy(
+ source,
+ (currentPosition - 1) + 1,
+ end,
+ 0,
+ source.length - (currentPosition - 1) - 1);
+
+ return new String(front)
+ + "\n===============================\nStarts here -->"
+ + new String(middle)
+ + "<-- Ends here\n===============================\n"
+ + new String(end);
+ }
+
+ public final String toStringAction(int act) {
+ switch (act) {
+ case TokenNameIdentifier :
+ return "Identifier(" + new String(getCurrentTokenSource()) + ")";
+ case TokenNameabstract :
+ return "abstract";
+ case TokenNameboolean :
+ return "boolean";
+ case TokenNamebreak :
+ return "break";
+ case TokenNamebyte :
+ return "byte";
+ case TokenNamecase :
+ return "case";
+ case TokenNamecatch :
+ return "catch";
+ case TokenNamechar :
+ return "char";
+ case TokenNameclass :
+ return "class";
+ case TokenNamecontinue :
+ return "continue";
+ case TokenNamedefault :
+ return "default";
+ case TokenNamedo :
+ return "do";
+ case TokenNamedouble :
+ return "double";
+ case TokenNameelse :
+ return "else";
+ case TokenNameextends :
+ return "extends";
+ case TokenNamefalse :
+ return "false";
+ case TokenNamefinal :
+ return "final";
+ case TokenNamefinally :
+ return "finally";
+ case TokenNamefloat :
+ return "float";
+ case TokenNamefor :
+ return "for";
+ case TokenNameif :
+ return "if";
+ case TokenNameimplements :
+ return "implements";
+ case TokenNameimport :
+ return "import";
+ case TokenNameinstanceof :
+ return "instanceof";
+ case TokenNameint :
+ return "int";
+ case TokenNameinterface :
+ return "interface";
+ case TokenNamelong :
+ return "long";
+ case TokenNamenative :
+ return "native";
+ case TokenNamenew :
+ return "new";
+ case TokenNamenull :
+ return "null";
+ case TokenNamepackage :
+ return "package";
+ case TokenNameprivate :
+ return "private";
+ case TokenNameprotected :
+ return "protected";
+ case TokenNamepublic :
+ return "public";
+ case TokenNamereturn :
+ return "return";
+ case TokenNameshort :
+ return "short";
+ case TokenNamestatic :
+ return "static";
+ case TokenNamesuper :
+ return "super";
+ case TokenNameswitch :
+ return "switch";
+ case TokenNamesynchronized :
+ return "synchronized";
+ case TokenNamethis :
+ return "this";
+ case TokenNamethrow :
+ return "throw";
+ case TokenNamethrows :
+ return "throws";
+ case TokenNametransient :
+ return "transient";
+ case TokenNametrue :
+ return "true";
+ case TokenNametry :
+ return "try";
+ case TokenNamevoid :
+ return "void";
+ case TokenNamevolatile :
+ return "volatile";
+ case TokenNamewhile :
+ return "while";
+
+ case TokenNameIntegerLiteral :
+ return "Integer(" + new String(getCurrentTokenSource()) + ")";
+ case TokenNameLongLiteral :
+ return "Long(" + new String(getCurrentTokenSource()) + ")";
+ case TokenNameFloatingPointLiteral :
+ return "Float(" + new String(getCurrentTokenSource()) + ")";
+ case TokenNameDoubleLiteral :
+ return "Double(" + new String(getCurrentTokenSource()) + ")";
+ case TokenNameCharacterLiteral :
+ return "Char(" + new String(getCurrentTokenSource()) + ")";
+ case TokenNameStringLiteral :
+ return "String(" + new String(getCurrentTokenSource()) + ")";
+
+ case TokenNamePLUS_PLUS :
+ return "++";
+ case TokenNameMINUS_MINUS :
+ return "--";
+ case TokenNameEQUAL_EQUAL :
+ return "==";
+ case TokenNameLESS_EQUAL :
+ return "<=";
+ case TokenNameGREATER_EQUAL :
+ return ">=";
+ case TokenNameNOT_EQUAL :
+ return "!=";
+ case TokenNameLEFT_SHIFT :
+ return "<<";
+ case TokenNameRIGHT_SHIFT :
+ return ">>";
+ case TokenNameUNSIGNED_RIGHT_SHIFT :
+ return ">>>";
+ case TokenNamePLUS_EQUAL :
+ return "+=";
+ case TokenNameMINUS_EQUAL :
+ return "-=";
+ case TokenNameMULTIPLY_EQUAL :
+ return "*=";
+ case TokenNameDIVIDE_EQUAL :
+ return "/=";
+ case TokenNameAND_EQUAL :
+ return "&=";
+ case TokenNameOR_EQUAL :
+ return "|=";
+ case TokenNameXOR_EQUAL :
+ return "^=";
+ case TokenNameREMAINDER_EQUAL :
+ return "%=";
+ case TokenNameLEFT_SHIFT_EQUAL :
+ return "<<=";
+ case TokenNameRIGHT_SHIFT_EQUAL :
+ return ">>=";
+ case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL :
+ return ">>>=";
+ case TokenNameOR_OR :
+ return "||";
+ case TokenNameAND_AND :
+ return "&&";
+ case TokenNamePLUS :
+ return "+";
+ case TokenNameMINUS :
+ return "-";
+ case TokenNameNOT :
+ return "!";
+ case TokenNameREMAINDER :
+ return "%";
+ case TokenNameXOR :
+ return "^";
+ case TokenNameAND :
+ return "&";
+ case TokenNameMULTIPLY :
+ return "*";
+ case TokenNameOR :
+ return "|";
+ case TokenNameTWIDDLE :
+ return "~";
+ case TokenNameDIVIDE :
+ return "/";
+ case TokenNameGREATER :
+ return ">";
+ case TokenNameLESS :
+ return "<";
+ case TokenNameLPAREN :
+ return "(";
+ case TokenNameRPAREN :
+ return ")";
+ case TokenNameLBRACE :
+ return "{";
+ case TokenNameRBRACE :
+ return "}";
+ case TokenNameLBRACKET :
+ return "[";
+ case TokenNameRBRACKET :
+ return "]";
+ case TokenNameSEMICOLON :
+ return ";";
+ case TokenNameQUESTION :
+ return "?";
+ case TokenNameCOLON :
+ return ":";
+ case TokenNameCOMMA :
+ return ",";
+ case TokenNameDOT :
+ return ".";
+ case TokenNameEQUAL :
+ return "=";
+ case TokenNameEOF :
+ return "EOF";
+ default :
+ return "not-a-token";
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/SourceConstructorDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/SourceConstructorDeclaration.java
new file mode 100644
index 0000000000..ce7a22ebed
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/SourceConstructorDeclaration.java
@@ -0,0 +1,13 @@
+package org.eclipse.jdt.internal.compiler.parser;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class SourceConstructorDeclaration extends ConstructorDeclaration {
+ public int selectorSourceEnd;
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/SourceFieldDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/SourceFieldDeclaration.java
new file mode 100644
index 0000000000..8836ce7a6a
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/SourceFieldDeclaration.java
@@ -0,0 +1,21 @@
+package org.eclipse.jdt.internal.compiler.parser;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class SourceFieldDeclaration extends FieldDeclaration {
+ public int fieldEndPosition;
+ public SourceFieldDeclaration(
+ Expression initialization,
+ char[] name,
+ int sourceStart,
+ int sourceEnd) {
+ super(initialization, name, sourceStart, sourceEnd);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/SourceMethodDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/SourceMethodDeclaration.java
new file mode 100644
index 0000000000..22cb08bc32
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/SourceMethodDeclaration.java
@@ -0,0 +1,13 @@
+package org.eclipse.jdt.internal.compiler.parser;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class SourceMethodDeclaration extends MethodDeclaration {
+ public int selectorSourceEnd;
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/SourceTypeConverter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/SourceTypeConverter.java
new file mode 100644
index 0000000000..ad0d9dbf53
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/SourceTypeConverter.java
@@ -0,0 +1,340 @@
+package org.eclipse.jdt.internal.compiler.parser;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/**
+ * Converter from source element type to parsed compilation unit.
+ *
+ * Limitation:
+ * | The source element field does not carry any information for its constant part, thus
+ * | the converted parse tree will not include any field initializations.
+ * | Therefore, any binary produced by compiling against converted source elements will
+ * | not take advantage of remote field constant inlining.
+ * | Given the intended purpose of the conversion is to resolve references, this is not
+ * | a problem.
+ *
+ */
+
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class SourceTypeConverter implements CompilerModifiers {
+ /*
+ * Convert a source element type into a parsed type declaration
+ *
+ * Can optionally ignore fields & methods
+ *
+ * @deprecated - should use the other API with one extra boolean
+ */
+ public static CompilationUnitDeclaration buildCompilationUnit(
+ ISourceType sourceType,
+ boolean needFieldsAndMethods,
+ ProblemReporter problemReporter,
+ CompilationResult compilationResult) {
+
+ return buildCompilationUnit(
+ sourceType,
+ needFieldsAndMethods,
+ true,
+ problemReporter,
+ compilationResult);
+ }
+
+ /*
+ * Convert a source element type into a parsed type declaration
+ *
+ * Can optionally ignore fields & methods or member types
+ */
+ public static CompilationUnitDeclaration buildCompilationUnit(
+ ISourceType sourceType,
+ boolean needFieldsAndMethods,
+ boolean needMemberTypes,
+ ProblemReporter problemReporter,
+ CompilationResult compilationResult) {
+
+ if (sourceType.getName() == null)
+ return null; // do a basic test that the sourceType is valid
+
+ CompilationUnitDeclaration compilationUnit =
+ new CompilationUnitDeclaration(problemReporter, compilationResult, 0);
+ // not filled at this point
+
+ /* only positions available */
+ int start = sourceType.getNameSourceStart();
+ int end = sourceType.getNameSourceEnd();
+
+ /* convert package and imports */
+ if (sourceType.getPackageName() != null
+ && sourceType.getPackageName().length > 0)
+ // if its null then it is defined in the default package
+ compilationUnit.currentPackage =
+ createImportReference(sourceType.getPackageName(), start, end);
+ char[][] importNames = sourceType.getImports();
+ int importCount = importNames == null ? 0 : importNames.length;
+ compilationUnit.imports = new ImportReference[importCount];
+ for (int i = 0; i < importCount; i++)
+ compilationUnit.imports[i] = createImportReference(importNames[i], start, end);
+ /* convert type */
+ compilationUnit.types =
+ new TypeDeclaration[] {
+ convert(sourceType, needFieldsAndMethods, needMemberTypes)};
+
+ return compilationUnit;
+ }
+
+ /*
+ * Convert a field source element into a parsed field declaration
+ */
+
+ private static FieldDeclaration convert(ISourceField sourceField) {
+
+ FieldDeclaration field = new FieldDeclaration();
+
+ int start = sourceField.getNameSourceStart();
+ int end = sourceField.getNameSourceEnd();
+
+ field.name = sourceField.getName();
+ field.sourceStart = start;
+ field.sourceEnd = end;
+ field.type = createTypeReference(sourceField.getTypeName(), start, end);
+ field.declarationSourceStart = sourceField.getDeclarationSourceStart();
+ field.declarationSourceEnd = sourceField.getDeclarationSourceEnd();
+ field.modifiers = sourceField.getModifiers();
+
+ /* conversion of field constant: if not present, then cannot generate binary against
+ converted parse nodes */
+ /*
+ if (field.modifiers & AccFinal){
+ char[] initializationSource = sourceField.getInitializationSource();
+ }
+ */
+ return field;
+ }
+
+ /*
+ * Convert a method source element into a parsed method/constructor declaration
+ */
+ private static AbstractMethodDeclaration convert(ISourceMethod sourceMethod) {
+
+ AbstractMethodDeclaration method;
+
+ /* only source positions available */
+ int start = sourceMethod.getNameSourceStart();
+ int end = sourceMethod.getNameSourceEnd();
+
+ if (sourceMethod.isConstructor()) {
+ ConstructorDeclaration decl = new ConstructorDeclaration();
+ decl.isDefaultConstructor = false;
+ method = decl;
+ } else {
+ MethodDeclaration decl = new MethodDeclaration();
+ /* convert return type */
+ decl.returnType =
+ createTypeReference(sourceMethod.getReturnTypeName(), start, end);
+ method = decl;
+ }
+ method.selector = sourceMethod.getSelector();
+ method.modifiers = sourceMethod.getModifiers();
+ method.sourceStart = start;
+ method.sourceEnd = end;
+ method.declarationSourceStart = sourceMethod.getDeclarationSourceStart();
+ method.declarationSourceEnd = sourceMethod.getDeclarationSourceEnd();
+
+ /* convert arguments */
+ char[][] argumentTypeNames = sourceMethod.getArgumentTypeNames();
+ char[][] argumentNames = sourceMethod.getArgumentNames();
+ int argumentCount = argumentTypeNames == null ? 0 : argumentTypeNames.length;
+ long position = (long) start << 32 + end;
+ method.arguments = new Argument[argumentCount];
+ for (int i = 0; i < argumentCount; i++) {
+ method.arguments[i] =
+ new Argument(
+ argumentNames[i],
+ position,
+ createTypeReference(argumentTypeNames[i], start, end),
+ AccDefault);
+ // do not care whether was final or not
+ }
+
+ /* convert thrown exceptions */
+ char[][] exceptionTypeNames = sourceMethod.getExceptionTypeNames();
+ int exceptionCount = exceptionTypeNames == null ? 0 : exceptionTypeNames.length;
+ method.thrownExceptions = new TypeReference[exceptionCount];
+ for (int i = 0; i < exceptionCount; i++) {
+ method.thrownExceptions[i] =
+ createTypeReference(exceptionTypeNames[i], start, end);
+ }
+ return method;
+ }
+
+ /*
+ * Convert a source element type into a parsed type declaration
+ *
+ * Can optionally ignore fields & methods
+ */
+ private static TypeDeclaration convert(
+ ISourceType sourceType,
+ boolean needFieldsAndMethods,
+ boolean needMemberTypes) {
+
+ /* create type declaration - can be member type */
+ TypeDeclaration type;
+ if (sourceType.getEnclosingType() == null) {
+ type = new TypeDeclaration();
+ } else {
+ type = new MemberTypeDeclaration();
+ }
+ type.name = sourceType.getName();
+ int start, end; // only positions available
+ type.sourceStart = start = sourceType.getNameSourceStart();
+ type.sourceEnd = end = sourceType.getNameSourceEnd();
+ type.modifiers = sourceType.getModifiers();
+ type.declarationSourceStart = sourceType.getDeclarationSourceStart();
+ type.declarationSourceEnd = sourceType.getDeclarationSourceEnd();
+
+ /* set superclass and superinterfaces */
+ if (sourceType.getSuperclassName() != null)
+ type.superclass =
+ createTypeReference(sourceType.getSuperclassName(), start, end);
+ char[][] interfaceNames = sourceType.getInterfaceNames();
+ int interfaceCount = interfaceNames == null ? 0 : interfaceNames.length;
+ type.superInterfaces = new TypeReference[interfaceCount];
+ for (int i = 0; i < interfaceCount; i++) {
+ type.superInterfaces[i] = createTypeReference(interfaceNames[i], start, end);
+ }
+ /* convert member types */
+ if (needMemberTypes) {
+ ISourceType[] sourceMemberTypes = sourceType.getMemberTypes();
+ int sourceMemberTypeCount =
+ sourceMemberTypes == null ? 0 : sourceMemberTypes.length;
+ type.memberTypes = new MemberTypeDeclaration[sourceMemberTypeCount];
+ for (int i = 0; i < sourceMemberTypeCount; i++) {
+ type.memberTypes[i] =
+ (MemberTypeDeclaration) convert(sourceMemberTypes[i],
+ needFieldsAndMethods,
+ true);
+ }
+ }
+ /* convert fields and methods */
+ if (needFieldsAndMethods) {
+ /* convert fields */
+ ISourceField[] sourceFields = sourceType.getFields();
+ int sourceFieldCount = sourceFields == null ? 0 : sourceFields.length;
+ type.fields = new FieldDeclaration[sourceFieldCount];
+ for (int i = 0; i < sourceFieldCount; i++) {
+ type.fields[i] = convert(sourceFields[i]);
+ }
+
+ /* convert methods - need to add default constructor if necessary */
+ ISourceMethod[] sourceMethods = sourceType.getMethods();
+ int sourceMethodCount = sourceMethods == null ? 0 : sourceMethods.length;
+
+ /* source type has a constructor ? */
+ /* by default, we assume that one is needed. */
+ int neededCount = 1;
+ for (int i = 0; i < sourceMethodCount; i++) {
+ if (sourceMethods[i].isConstructor()) {
+ neededCount = 0;
+ // Does not need the extra constructor since one constructor already exists.
+ break;
+ }
+ }
+ type.methods = new AbstractMethodDeclaration[sourceMethodCount + neededCount];
+ if (neededCount != 0) { // add default constructor in first position
+ type.methods[0] = type.createsInternalConstructor(false, false);
+ }
+ for (int i = 0; i < sourceMethodCount; i++) {
+ type.methods[neededCount + i] = convert(sourceMethods[i]);
+ }
+ }
+ return type;
+ }
+
+ /*
+ * Build an import reference from an import name, e.g. java.lang.*
+ */
+ private static ImportReference createImportReference(
+ char[] importName,
+ int start,
+ int end) {
+
+ /* count identifiers */
+ int max = importName.length;
+ int identCount = 0;
+ for (int i = 0; i < max; i++) {
+ if (importName[i] == '.')
+ identCount++;
+ }
+ /* import on demand? */
+ boolean onDemand = importName[max - 1] == '*';
+ if (!onDemand)
+ identCount++; // one more ident than dots
+
+ long[] positions = new long[identCount];
+ long position = (long) start << 32 + end;
+ for (int i = 0; i < identCount; i++) {
+ positions[i] = position;
+ }
+ return new ImportReference(
+ CharOperation.splitOn('.', importName, 0, max - (onDemand ? 3 : 1)),
+ positions,
+ onDemand);
+ }
+
+ /*
+ * Build a type reference from a readable name, e.g. java.lang.Object[][]
+ */
+ private static TypeReference createTypeReference(
+ char[] typeSignature,
+ int start,
+ int end) {
+
+ /* count identifiers and dimensions */
+ int max = typeSignature.length;
+ int dimStart = max;
+ int dim = 0;
+ int identCount = 1;
+ for (int i = 0; i < max; i++) {
+ switch (typeSignature[i]) {
+ case '[' :
+ if (dim == 0)
+ dimStart = i;
+ dim++;
+ break;
+ case '.' :
+ identCount++;
+ break;
+ }
+ }
+ /* rebuild identifiers and dimensions */
+ if (identCount == 1) { // simple type reference
+ if (dim == 0) {
+ return new SingleTypeReference(typeSignature, (long) start << 32 + end);
+ } else {
+ char[] identifier = new char[dimStart];
+ System.arraycopy(typeSignature, 0, identifier, 0, dimStart);
+ return new ArrayTypeReference(identifier, dim, (long) start << 32 + end);
+ }
+ } else { // qualified type reference
+ long[] positions = new long[identCount];
+ long pos = (long) start << 32 + end;
+ for (int i = 0; i < identCount; i++) {
+ positions[i] = pos;
+ }
+ char[][] identifiers =
+ CharOperation.splitOn('.', typeSignature, 0, dimStart - 1);
+ if (dim == 0) {
+ return new QualifiedTypeReference(identifiers, positions);
+ } else {
+ return new ArrayQualifiedTypeReference(identifiers, dim, positions);
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/TerminalSymbols.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/TerminalSymbols.java
new file mode 100644
index 0000000000..7bfde7a1ea
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/TerminalSymbols.java
@@ -0,0 +1,109 @@
+package org.eclipse.jdt.internal.compiler.parser;
+
+public interface TerminalSymbols {
+
+ public final static int TokenNameIdentifier = 5,
+ TokenNameabstract = 92,
+ TokenNameboolean = 18,
+ TokenNamebreak = 118,
+ TokenNamebyte = 19,
+ TokenNamecase = 211,
+ TokenNamecatch = 225,
+ TokenNamechar = 20,
+ TokenNameclass = 163,
+ TokenNamecontinue = 119,
+ TokenNamedefault = 212,
+ TokenNamedo = 120,
+ TokenNamedouble = 21,
+ TokenNameelse = 213,
+ TokenNameextends = 241,
+ TokenNamefalse = 37,
+ TokenNamefinal = 93,
+ TokenNamefinally = 226,
+ TokenNamefloat = 22,
+ TokenNamefor = 121,
+ TokenNameif = 122,
+ TokenNameimplements = 265,
+ TokenNameimport = 190,
+ TokenNameinstanceof = 65,
+ TokenNameint = 23,
+ TokenNameinterface = 184,
+ TokenNamelong = 24,
+ TokenNamenative = 94,
+ TokenNamenew = 33,
+ TokenNamenull = 38,
+ TokenNamepackage = 214,
+ TokenNameprivate = 95,
+ TokenNameprotected = 96,
+ TokenNamepublic = 97,
+ TokenNamereturn = 123,
+ TokenNameshort = 25,
+ TokenNamestatic = 98,
+ TokenNamestrictfp = 99,
+ TokenNamesuper = 35,
+ TokenNameswitch = 124,
+ TokenNamesynchronized = 84,
+ TokenNamethis = 36,
+ TokenNamethrow = 125,
+ TokenNamethrows = 227,
+ TokenNametransient = 100,
+ TokenNametrue = 39,
+ TokenNametry = 126,
+ TokenNamevoid = 26,
+ TokenNamevolatile = 101,
+ TokenNamewhile = 117,
+ TokenNameIntegerLiteral = 40,
+ TokenNameLongLiteral = 41,
+ TokenNameFloatingPointLiteral = 42,
+ TokenNameDoubleLiteral = 43,
+ TokenNameCharacterLiteral = 44,
+ TokenNameStringLiteral = 45,
+ TokenNamePLUS_PLUS = 1,
+ TokenNameMINUS_MINUS = 2,
+ TokenNameEQUAL_EQUAL = 32,
+ TokenNameLESS_EQUAL = 66,
+ TokenNameGREATER_EQUAL = 67,
+ TokenNameNOT_EQUAL = 34,
+ TokenNameLEFT_SHIFT = 13,
+ TokenNameRIGHT_SHIFT = 11,
+ TokenNameUNSIGNED_RIGHT_SHIFT = 12,
+ TokenNamePLUS_EQUAL = 166,
+ TokenNameMINUS_EQUAL = 167,
+ TokenNameMULTIPLY_EQUAL = 168,
+ TokenNameDIVIDE_EQUAL = 169,
+ TokenNameAND_EQUAL = 170,
+ TokenNameOR_EQUAL = 171,
+ TokenNameXOR_EQUAL = 172,
+ TokenNameREMAINDER_EQUAL = 173,
+ TokenNameLEFT_SHIFT_EQUAL = 174,
+ TokenNameRIGHT_SHIFT_EQUAL = 175,
+ TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL = 176,
+ TokenNameOR_OR = 79,
+ TokenNameAND_AND = 78,
+ TokenNamePLUS = 3,
+ TokenNameMINUS = 4,
+ TokenNameNOT = 71,
+ TokenNameREMAINDER = 8,
+ TokenNameXOR = 63,
+ TokenNameAND = 62,
+ TokenNameMULTIPLY = 7,
+ TokenNameOR = 70,
+ TokenNameTWIDDLE = 72,
+ TokenNameDIVIDE = 9,
+ TokenNameGREATER = 68,
+ TokenNameLESS = 69,
+ TokenNameLPAREN = 10,
+ TokenNameRPAREN = 86,
+ TokenNameLBRACE = 109,
+ TokenNameRBRACE = 102,
+ TokenNameLBRACKET = 14,
+ TokenNameRBRACKET = 164,
+ TokenNameSEMICOLON = 64,
+ TokenNameQUESTION = 80,
+ TokenNameCOLON = 153,
+ TokenNameCOMMA = 88,
+ TokenNameDOT = 6,
+ TokenNameEQUAL = 165,
+ TokenNameEOF = 156,
+ TokenNameERROR = 304;
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser1.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser1.rsc
new file mode 100644
index 0000000000..48eab10b64
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser1.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser2.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser2.rsc
new file mode 100644
index 0000000000..434680d292
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser2.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser3.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser3.rsc
new file mode 100644
index 0000000000..b9da6ff235
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser3.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser4.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser4.rsc
new file mode 100644
index 0000000000..f60de39fd6
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser4.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser5.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser5.rsc
new file mode 100644
index 0000000000..d180c8d55c
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser5.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/AbortCompilation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/AbortCompilation.java
new file mode 100644
index 0000000000..75ce872a4d
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/AbortCompilation.java
@@ -0,0 +1,52 @@
+package org.eclipse.jdt.internal.compiler.problem;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.*;
+
+/*
+ * Special unchecked exception type used
+ * to abort from the compilation process
+ *
+ * should only be thrown from within problem handlers.
+ */
+public class AbortCompilation extends RuntimeException {
+ public CompilationResult compilationResult;
+ public Throwable exception;
+
+ public int problemId;
+ public String[] problemArguments;
+
+ /* special fields used to abort silently (e.g. when cancelling build process) */
+ public boolean isSilent;
+ public RuntimeException silentException;
+ public AbortCompilation() {
+ this((CompilationResult) null);
+ }
+
+ public AbortCompilation(int problemId, String[] problemArguments) {
+
+ this.problemId = problemId;
+ this.problemArguments = problemArguments;
+ }
+
+ public AbortCompilation(CompilationResult compilationResult) {
+ this(compilationResult, null);
+ }
+
+ public AbortCompilation(
+ CompilationResult compilationResult,
+ Throwable exception) {
+ this.compilationResult = compilationResult;
+ this.exception = exception;
+ }
+
+ public AbortCompilation(boolean isSilent, RuntimeException silentException) {
+ this.isSilent = isSilent;
+ this.silentException = silentException;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/AbortCompilationUnit.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/AbortCompilationUnit.java
new file mode 100644
index 0000000000..160ab72a8a
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/AbortCompilationUnit.java
@@ -0,0 +1,20 @@
+package org.eclipse.jdt.internal.compiler.problem;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+
+/*
+ * Special unchecked exception type used
+ * to abort from the compilation process
+ *
+ * should only be thrown from within problem handlers.
+ */
+public class AbortCompilationUnit extends AbortCompilation {
+ public AbortCompilationUnit(CompilationResult compilationResult) {
+ super(compilationResult);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/AbortMethod.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/AbortMethod.java
new file mode 100644
index 0000000000..a4ad329bff
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/AbortMethod.java
@@ -0,0 +1,20 @@
+package org.eclipse.jdt.internal.compiler.problem;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+
+/*
+ * Special unchecked exception type used
+ * to abort from the compilation process
+ *
+ * should only be thrown from within problem handlers.
+ */
+public class AbortMethod extends AbortType {
+ public AbortMethod(CompilationResult compilationResult) {
+ super(compilationResult);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/AbortType.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/AbortType.java
new file mode 100644
index 0000000000..102d86497b
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/AbortType.java
@@ -0,0 +1,20 @@
+package org.eclipse.jdt.internal.compiler.problem;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+
+/*
+ * Special unchecked exception type used
+ * to abort from the compilation process
+ *
+ * should only be thrown from within problem handlers.
+ */
+public class AbortType extends AbortCompilationUnit {
+ public AbortType(CompilationResult compilationResult) {
+ super(compilationResult);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/DefaultProblem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/DefaultProblem.java
new file mode 100644
index 0000000000..35d679a6db
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/DefaultProblem.java
@@ -0,0 +1,242 @@
+package org.eclipse.jdt.internal.compiler.problem;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.*;
+
+public class DefaultProblem
+ implements IProblem, ProblemSeverities, ProblemIrritants {
+ private char[] fileName;
+ private int id;
+ private int startPosition, endPosition, line;
+ private int severity;
+ private String[] arguments;
+ private String message;
+ public DefaultProblem(
+ char[] originatingFileName,
+ String message,
+ int id,
+ String[] stringArguments,
+ int severity,
+ int startPosition,
+ int endPosition,
+ int line) {
+
+ this.fileName = originatingFileName;
+ this.message = message;
+ this.id = id;
+ this.arguments = stringArguments;
+ this.severity = severity;
+ this.startPosition = startPosition;
+ this.endPosition = endPosition;
+ this.line = line;
+ }
+
+ public String errorReportSource(ICompilationUnit compilationUnit) {
+ //extra from the source the innacurate token
+ //and "highlight" it using some underneath ^^^^^
+ //put some context around too.
+
+ //this code assumes that the font used in the console is fixed size
+
+ //sanity .....
+ if ((startPosition > endPosition)
+ || ((startPosition <= 0) && (endPosition <= 0)))
+ return "\n!! no source information available !!";
+
+ //regular behavior....(slow code)
+
+ final int AROUND = 60; //increase this value to see more ....
+ final char SPACE = '\u0020';
+ final char MARK = '^';
+ final char TAB = '\t';
+ char[] source = compilationUnit.getContents();
+ //the next code tries to underline the token.....
+ //it assumes (for a good display) that token source does not
+ //contain any \r \n. This is false on statements !
+ //(the code still works but the display is not optimal !)
+
+ //compute the how-much-char we are displaying around the inaccurate token
+ int begin = startPosition >= source.length ? source.length - 1 : startPosition;
+ int relativeStart = 0;
+ int end = endPosition >= source.length ? source.length - 1 : endPosition;
+ int relativeEnd = 0;
+ label : for (relativeStart = 0;; relativeStart++) {
+ if (begin == 0)
+ break label;
+ if ((source[begin - 1] == '\n') || (source[begin - 1] == '\r'))
+ break label;
+ begin--;
+ }
+ label : for (relativeEnd = 0;; relativeEnd++) {
+ if ((end + 1) >= source.length)
+ break label;
+ if ((source[end + 1] == '\r') || (source[end + 1] == '\n')) {
+ break label;
+ }
+ end++;
+ }
+ //extract the message form the source
+ char[] extract = new char[end - begin + 1];
+ System.arraycopy(source, begin, extract, 0, extract.length);
+ char c;
+ //remove all SPACE and TAB that begin the error message...
+ int trimLeftIndex = 0;
+ while (((c = extract[trimLeftIndex++]) == TAB) || (c == SPACE)) {
+ };
+ System.arraycopy(
+ extract,
+ trimLeftIndex - 1,
+ extract = new char[extract.length - trimLeftIndex + 1],
+ 0,
+ extract.length);
+ relativeStart -= trimLeftIndex;
+ //buffer spaces and tabs in order to reach the error position
+ int pos = 0;
+ char[] underneath = new char[extract.length]; // can't be bigger
+ for (int i = 0; i <= relativeStart; i++) {
+ if (extract[i] == TAB) {
+ underneath[pos++] = TAB;
+ } else {
+ underneath[pos++] = SPACE;
+ }
+ }
+ //mark the error position
+ for (int i = startPosition;
+ i <= (endPosition >= source.length ? source.length - 1 : endPosition);
+ i++)
+ underneath[pos++] = MARK;
+ //resize underneathto remove 'null' chars
+ System.arraycopy(underneath, 0, underneath = new char[pos], 0, pos);
+
+ return " (at line " + String.valueOf(line) + ")" + //NON NLS
+ "\n\t" + new String(extract) + "\n\t" + new String(underneath);
+ }
+
+ /**
+ * Answer back the original arguments recorded into the problem.
+ * @return java.lang.String[]
+ */
+ public String[] getArguments() {
+ return arguments;
+ }
+
+ /**
+ * Answer the type of problem.
+ * @see com.ibm.compiler.java.problem.ProblemIrritants
+ * @return int
+ */
+ public int getID() {
+ return id;
+ }
+
+ /**
+ * Answer a localized, human-readable message string which describes the problem.
+ * @return java.lang.String
+ */
+ public String getMessage() {
+ return message;
+ }
+
+ /**
+ * Answer the file name in which the problem was found.
+ * @return char[]
+ */
+ public char[] getOriginatingFileName() {
+ return fileName;
+ }
+
+ /**
+ * Answer the severity of the problem.
+ * @return int
+ */
+ public int getSeverity() {
+ return severity;
+ }
+
+ /**
+ * Answer the end position of the problem (inclusive), or -1 if unknown.
+ * @return int
+ */
+ public int getSourceEnd() {
+ return endPosition;
+ }
+
+ /**
+ * Answer the line number in source where the problem begins.
+ * @return int
+ */
+ public int getSourceLineNumber() {
+ return line;
+ }
+
+ /**
+ * Answer the start position of the problem (inclusive), or -1 if unknown.
+ * @return int
+ */
+ public int getSourceStart() {
+ return startPosition;
+ }
+
+ /*
+ * Helper method: checks the severity to see if the Error bit is set.
+ * @return boolean
+ */
+ public boolean isError() {
+ return (severity & ProblemSeverities.Error) != 0;
+ }
+
+ /*
+ * Helper method: checks the severity to see if the Error bit is not set.
+ * @return boolean
+ */
+ public boolean isWarning() {
+ return (severity & ProblemSeverities.Error) == 0;
+ }
+
+ /**
+ * Set the end position of the problem (inclusive), or -1 if unknown.
+ *
+ * Used for shifting problem positions.
+ * @param sourceEnd the new value of the sourceEnd of the receiver
+ */
+ public void setSourceEnd(int sourceEnd) {
+ endPosition = sourceEnd;
+ }
+
+ /**
+ * Set the line number in source where the problem begins.
+ * @param lineNumber the new value of the line number of the receiver
+ */
+ public void setSourceLineNumber(int lineNumber) {
+ line = lineNumber;
+ }
+
+ /**
+ * Set the start position of the problem (inclusive), or -1 if unknown.
+ *
+ * Used for shifting problem positions.
+ * @param sourceStart the new value of the source start position of the receiver
+ */
+ public void setSourceStart(int sourceStart) {
+ startPosition = sourceStart;
+ }
+
+ public String toString() {
+
+ String s = "Pb(" + (id & IgnoreCategoriesMask) + ") ";
+ if (message != null) {
+ s += message;
+ } else {
+ if (arguments != null)
+ for (int i = 0; i < arguments.length; i++)
+ s += " " + arguments[i];
+ }
+ return s;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/DefaultProblemFactory.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/DefaultProblemFactory.java
new file mode 100644
index 0000000000..b421dadb6a
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/DefaultProblemFactory.java
@@ -0,0 +1,134 @@
+package org.eclipse.jdt.internal.compiler.problem;
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.text.*;
+import java.util.*;
+import org.eclipse.jdt.internal.compiler.*;
+
+public class DefaultProblemFactory implements IProblemFactory {
+
+ public String[] messageTemplates;
+ private Locale locale;
+ private static String[] DEFAULT_LOCALE_TEMPLATES;
+
+ /**
+ * @param loc the locale used to get the right message
+ */
+ public DefaultProblemFactory(Locale loc) {
+ this.locale = loc;
+ if (Locale.getDefault().equals(loc)) {
+ if (DEFAULT_LOCALE_TEMPLATES == null) {
+ DEFAULT_LOCALE_TEMPLATES = loadMessageTemplates(loc);
+ }
+ this.messageTemplates = DEFAULT_LOCALE_TEMPLATES;
+ } else {
+ this.messageTemplates = loadMessageTemplates(loc);
+ }
+ }
+
+ /**
+ * Answer a new IProblem created according to the parameters value
+ * @param originatingFileName the name of the file name from which the problem is originated
+ * @param problemId the problem id
+ * @param arguments the arguments needed to set the error message
+ * @param severity the severity of the problem
+ * @param startPosition the starting position of the problem
+ * @param endPosition the end position of the problem
+ * @param lineNumber the line on which the problem occured
+ * @return com.ibm.compiler.java.api.IProblem
+ */
+ public IProblem createProblem(
+ char[] originatingFileName,
+ int problemId,
+ String[] arguments,
+ int severity,
+ int startPosition,
+ int endPosition,
+ int lineNumber) {
+
+ return new DefaultProblem(
+ originatingFileName,
+ this.getLocalizedMessage(problemId, arguments),
+ problemId,
+ arguments,
+ severity,
+ startPosition,
+ endPosition,
+ lineNumber);
+ }
+
+ /**
+ * Answer the locale used to retrieve the error messages
+ * @return java.util.Locale
+ */
+ public Locale getLocale() {
+ return locale;
+ }
+
+ public final String getLocalizedMessage(int id, String[] problemArguments) {
+ StringBuffer output = new StringBuffer(80);
+ String message = messageTemplates[(id & ProblemIrritants.IgnoreCategoriesMask)];
+ if (message == null) {
+ return "Unable to retrieve the error message for problem id: "
+ + id
+ + ". Check compiler resources.";
+ }
+
+ int length = message.length();
+ int start = -1, end = length;
+ while (true) {
+ if ((end = message.indexOf('{', start)) > -1) {
+ output.append(message.substring(start + 1, end));
+ if ((start = message.indexOf('}', end)) > -1) {
+ try {
+ output.append(
+ problemArguments[Integer.parseInt(message.substring(end + 1, start))]);
+ } catch (NumberFormatException nfe) {
+ output.append(message.substring(end + 1, start + 1));
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return "Corrupted compiler resources for problem id: "
+ + (id & ProblemIrritants.IgnoreCategoriesMask)
+ + ". Check compiler resources.";
+ }
+ } else {
+ output.append(message.substring(end, length));
+ break;
+ }
+ } else {
+ output.append(message.substring(start + 1, length));
+ break;
+ }
+ }
+ return output.toString();
+ }
+
+ /**
+ * @return com.ibm.compiler.java.problem.LocalizedProblem
+ * @param problem com.ibm.compiler.java.problem.Problem
+ */
+ public final String localizedMessage(IProblem problem) {
+ return getLocalizedMessage(problem.getID(), problem.getArguments());
+ }
+
+ /**
+ * This method initializes the MessageTemplates class variable according
+ * to the current Locale.
+ */
+ public static String[] loadMessageTemplates(Locale loc) {
+ ResourceBundle bundle =
+ ResourceBundle.getBundle(
+ "org.eclipse.jdt.internal.compiler.problem.Messages",
+ loc);
+ String[] templates = new String[500];
+ for (int i = 0, max = templates.length; i < max; i++) {
+ try {
+ templates[i] = bundle.getString(String.valueOf(i)); //$NON-NLS-1$
+ } catch (MissingResourceException e) {
+ }
+ }
+ return templates;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemHandler.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemHandler.java
new file mode 100644
index 0000000000..5ddb41ba49
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemHandler.java
@@ -0,0 +1,169 @@
+package org.eclipse.jdt.internal.compiler.problem;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.impl.*;
+
+/*
+ * Compiler error handler, responsible to determine whether
+ * a problem is actually a warning or an error; also will
+ * decide whether the compilation task can be processed further or not.
+ *
+ * Behavior : will request its current policy if need to stop on
+ * first error, and if should proceed (persist) with problems.
+ */
+
+public class ProblemHandler implements ProblemSeverities {
+
+ final public IErrorHandlingPolicy policy;
+ public final IProblemFactory problemFactory;
+ public final CompilerOptions options;
+ /*
+ * Problem handler can be supplied with a policy to specify
+ * its behavior in error handling. Also see static methods for
+ * built-in policies.
+ *
+ */
+ public ProblemHandler(
+ IErrorHandlingPolicy policy,
+ CompilerOptions options,
+ IProblemFactory problemFactory) {
+ this.policy = policy;
+ this.problemFactory = problemFactory;
+ this.options = options;
+ }
+
+ /*
+ * Given the current configuration, answers which category the problem
+ * falls into:
+ * Error | Warning | Ignore
+ */
+ public int computeSeverity(int problemId) {
+
+ return Error; // by default all problems are errors
+ }
+
+ public IProblem createProblem(
+ char[] fileName,
+ int problemId,
+ String[] problemArguments,
+ int severity,
+ int problemStartPosition,
+ int problemEndPosition,
+ int lineNumber) {
+
+ return problemFactory.createProblem(
+ fileName,
+ problemId,
+ problemArguments,
+ severity,
+ problemStartPosition,
+ problemEndPosition,
+ lineNumber);
+ }
+
+ public void handle(
+ int problemId,
+ String[] problemArguments,
+ int severity,
+ int problemStartPosition,
+ int problemEndPosition,
+ ReferenceContext referenceContext,
+ CompilationResult unitResult) {
+
+ if (severity == Ignore)
+ return;
+
+ // if no reference context, we need to abort from the current compilation process
+ if (referenceContext == null) {
+ throw new AbortCompilation(problemId, problemArguments);
+ }
+
+ IProblem problem =
+ this.createProblem(
+ unitResult.getFileName(),
+ problemId,
+ problemArguments,
+ severity,
+ problemStartPosition,
+ problemEndPosition,
+ problemStartPosition >= 0
+ ? searchLineNumber(unitResult.lineSeparatorPositions, problemStartPosition)
+ : 0);
+
+ switch (severity & Error) {
+ case Error :
+ referenceContext.tagAsHavingErrors();
+ this.record(problem, unitResult);
+
+ // should abort ?
+ int abortLevel;
+ if ((abortLevel =
+ (policy.stopOnFirstError() ? AbortCompilation : severity & Abort))
+ != 0) {
+ referenceContext.abort(abortLevel);
+ }
+ break;
+ case Warning :
+ this.record(problem, unitResult);
+ break;
+ }
+ }
+
+ /**
+ * Standard problem handling API, the actual severity (warning/error/ignore) is deducted
+ * from the problem ID and the current compiler options.
+ */
+ public void handle(
+ int problemId,
+ String[] problemArguments,
+ int problemStartPosition,
+ int problemEndPosition,
+ ReferenceContext referenceContext,
+ CompilationResult unitResult) {
+
+ this.handle(problemId, problemArguments, this.computeSeverity(problemId),
+ // severity inferred using the ID
+ problemStartPosition, problemEndPosition, referenceContext, unitResult);
+ }
+
+ public void record(IProblem problem, CompilationResult unitResult) {
+ unitResult.record(problem);
+ }
+
+ /**
+ * Search the line number corresponding to a specific position
+ *
+ * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
+ */
+ public static final int searchLineNumber(
+ int[] startLineIndexes,
+ int position) {
+ if (startLineIndexes == null)
+ return 1;
+ int length = startLineIndexes.length;
+ if (length == 0)
+ return 1;
+ int g = 0, d = length - 1;
+ int m = 0;
+ while (g <= d) {
+ m = (g + d) / 2;
+ if (position < startLineIndexes[m]) {
+ d = m - 1;
+ } else
+ if (position > startLineIndexes[m]) {
+ g = m + 1;
+ } else {
+ return m + 1;
+ }
+ }
+ if (position < startLineIndexes[m]) {
+ return m + 1;
+ }
+ return m + 2;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemIrritants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemIrritants.java
new file mode 100644
index 0000000000..ffc9d8dc3c
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemIrritants.java
@@ -0,0 +1,277 @@
+package org.eclipse.jdt.internal.compiler.problem;
+
+public interface ProblemIrritants { // max: 500
+ // categories
+ final int TypeRelated = 0x01000000;
+ final int FieldRelated = 0x02000000;
+ final int MethodRelated = 0x04000000;
+ final int ConstructorRelated = 0x08000000;
+ final int ImportRelated = 0x10000000;
+ final int Internal = 0x20000000;
+ final int IgnoreCategoriesMask = 0xFFFFFF;
+ final int UnclassifiedProblem = 0;
+
+ // types
+ final int ObjectHasNoSuperclass = TypeRelated + 1;
+ final int UndefinedType = TypeRelated + 2;
+ final int NotVisibleType = TypeRelated + 3;
+ final int AmbiguousType = TypeRelated + 4;
+ final int UsingDeprecatedType = TypeRelated + 5;
+ final int InternalTypeNameProvided = TypeRelated + 6;
+ // type compatibilities
+ final int IncompatibleTypesInEqualityOperator = TypeRelated + 15;
+ final int IncompatibleTypesInConditionalOperator = TypeRelated + 16;
+ final int TypeMismatch = TypeRelated + 17;
+
+ // inner classes
+ final int MissingEnclosingInstanceForConstructorCall = TypeRelated + 20;
+ final int MissingEnclosingInstance = TypeRelated + 21;
+ final int IncorrectEnclosingInstanceReference = TypeRelated + 22;
+ final int IllegalEnclosingInstanceSpecification = TypeRelated + 23;
+ final int CannotDefineStaticInitializerInLocalType = Internal + 24;
+ final int OuterLocalMustBeFinal = Internal + 25;
+ final int CannotDefineInterfaceInLocalType = Internal + 26;
+ final int IllegalPrimitiveOrArrayTypeForEnclosingInstance = TypeRelated + 27;
+ final int NoExceptionInAnonymousTypeConstructor = ConstructorRelated + 28;
+ final int AnonymousClassCannotExtendFinalClass = TypeRelated + 29;
+
+ // variables
+ final int UndefinedName = 50;
+ final int UninitializedLocalVariable = Internal + 51;
+ final int VariableTypeCannotBeVoid = Internal + 52;
+ final int VariableTypeCannotBeVoidArray = Internal + 53;
+ final int CannotAllocateVoidArray = Internal + 54;
+ // local variables
+ final int RedefinedLocal = Internal + 55;
+ final int RedefinedArgument = Internal + 56;
+ final int DuplicateFinalLocalInitialization = Internal + 57;
+ // final local variables
+ final int FinalOuterLocalAssignment = Internal + 60;
+ final int LocalVariableIsNeverUsed = Internal + 61;
+ final int ArgumentIsNeverUsed = Internal + 62;
+ final int BytecodeExceeds64KLimit = Internal + 63;
+ final int BytecodeExceeds64KLimitForClinit = Internal + 64;
+ final int TooManyArgumentSlots = Internal + 65;
+ final int TooManyLocalVariableSlots = Internal + 66;
+
+ // fields
+ final int UndefinedField = FieldRelated + 70;
+ final int NotVisibleField = FieldRelated + 71;
+ final int AmbiguousField = FieldRelated + 72;
+ final int UsingDeprecatedField = FieldRelated + 73;
+ final int NonStaticFieldFromStaticInvocation = FieldRelated + 74;
+ final int ReferenceToForwardField = FieldRelated + Internal + 75;
+
+ // blank final fields
+ final int FinalFieldAssignment = FieldRelated + 80;
+ final int UninitializedBlankFinalField = FieldRelated + 81;
+ final int DuplicateBlankFinalFieldInitialization = FieldRelated + 82;
+
+ // methods
+ final int UndefinedMethod = MethodRelated + 100;
+ final int NotVisibleMethod = MethodRelated + 101;
+ final int AmbiguousMethod = MethodRelated + 102;
+ final int UsingDeprecatedMethod = MethodRelated + 103;
+ final int DirectInvocationOfAbstractMethod = MethodRelated + 104;
+ final int VoidMethodReturnsValue = MethodRelated + 105;
+ final int MethodReturnsVoid = MethodRelated + 106;
+ final int MethodRequiresBody = Internal + MethodRelated + 107;
+ final int ShouldReturnValue = Internal + MethodRelated + 108;
+ final int MethodButWithConstructorName = MethodRelated + 110;
+ final int MissingReturnType = TypeRelated + 111;
+ final int BodyForNativeMethod = Internal + MethodRelated + 112;
+ final int BodyForAbstractMethod = Internal + MethodRelated + 113;
+ final int NoMessageSendOnBaseType = MethodRelated + 114;
+ final int ParameterMismatch = MethodRelated + 115;
+ final int NoMessageSendOnArrayType = MethodRelated + 116;
+
+ // constructors
+ final int UndefinedConstructor = ConstructorRelated + 130;
+ final int NotVisibleConstructor = ConstructorRelated + 131;
+ final int AmbiguousConstructor = ConstructorRelated + 132;
+ final int UsingDeprecatedConstructor = ConstructorRelated + 133;
+ // explicit constructor calls
+ final int InstanceFieldDuringConstructorInvocation = ConstructorRelated + 135;
+ final int InstanceMethodDuringConstructorInvocation = ConstructorRelated + 136;
+ final int RecursiveConstructorInvocation = ConstructorRelated + 137;
+ final int ThisSuperDuringConstructorInvocation = ConstructorRelated + 138;
+
+ // expressions
+ final int ArrayReferenceRequired = Internal + 150;
+ final int NoImplicitStringConversionForCharArrayExpression = Internal + 151;
+ // constant expressions
+ final int StringConstantIsExceedingUtf8Limit = Internal + 152;
+ final int NonConstantExpression = 153;
+ final int NumericValueOutOfRange = Internal + 154;
+ // cast expressions
+ final int IllegalCast = TypeRelated + 156;
+ // allocations
+ final int InvalidClassInstantiation = TypeRelated + 157;
+ final int CannotDefineDimensionExpressionsWithInit = Internal + 158;
+ final int MustDefineEitherDimensionExpressionsOrInitializer = Internal + 159;
+ // operators
+ final int InvalidOperator = Internal + 160;
+ // statements
+ final int CodeCannotBeReached = Internal + 161;
+ final int CannotReturnInInitializer = Internal + 162;
+ final int InitializerMustCompleteNormally = Internal + 163;
+ final int CannotThrowCheckedExceptionInInitializer = TypeRelated + 164;
+ // try
+ final int MaskedCatch = TypeRelated + 165;
+ final int DuplicateDefaultCase = 166;
+ final int UnreachableCatch = TypeRelated + MethodRelated + 167;
+ final int UnhandledException = TypeRelated + 168;
+ // switch
+ final int IncorrectSwitchType = TypeRelated + 169;
+ final int DuplicateCase = FieldRelated + 170;
+ // labelled
+ final int DuplicateLabel = Internal + 171;
+ final int InvalidBreak = Internal + 172;
+ final int InvalidContinue = Internal + 173;
+ final int UndefinedLabel = Internal + 174;
+ //synchronized
+ final int InvalidTypeToSynchronized = Internal + 175;
+ final int InvalidNullToSynchronized = Internal + 176;
+ // throw
+ final int CannotThrowNull = Internal + 177;
+
+ // inner emulation
+ final int NeedToEmulateFieldReadAccess = FieldRelated + 190;
+ final int NeedToEmulateFieldWriteAccess = FieldRelated + 191;
+ final int NeedToEmulateMethodAccess = MethodRelated + 192;
+ final int NeedToEmulateConstructorAccess = MethodRelated + 193;
+
+ //inherited name hides enclosing name (sort of ambiguous)
+ final int InheritedMethodHidesEnclosingName = MethodRelated + 195;
+ final int InheritedFieldHidesEnclosingName = FieldRelated + 196;
+ final int InheritedTypeHidesEnclosingName = TypeRelated + 197;
+
+ // miscellaneous
+ final int ThisInStaticContext = Internal + 200;
+ final int StaticMethodRequested = Internal + MethodRelated + 201;
+ final int IllegalDimension = Internal + 202;
+ final int InvalidTypeExpression = Internal + 203;
+ final int ParsingError = Internal + 204;
+ final int ParsingErrorNoSuggestion = Internal + 205;
+ final int InvalidUnaryExpression = Internal + 206;
+
+ // syntax errors
+ final int InterfaceCannotHaveConstructors = Internal + 207;
+ final int ArrayConstantsOnlyInArrayInitializers = Internal + 208;
+
+ final int UnmatchedBracket = Internal + 220;
+ final int NoFieldOnBaseType = FieldRelated + 221;
+ final int InvalidExpressionAsStatement = Internal + 222;
+
+ // constants
+ final int END_OF_SOURCE = Internal + 250;
+ final int INVALID_HEXA = Internal + 251;
+ final int INVALID_OCTAL = Internal + 252;
+ final int INVALID_CHARACTER_CONSTANT = Internal + 253;
+ final int INVALID_ESCAPE = Internal + 254;
+ final int INVALID_INPUT = Internal + 255;
+ final int INVALID_UNICODE_ESCAPE = Internal + 256;
+ final int INVALID_FLOAT = Internal + 257;
+ final int NULL_SOURCE_STRING = Internal + 258;
+ final int UNTERMINATED_STRING = Internal + 259;
+ final int UNTERMINATED_COMMENT = Internal + 260;
+
+ // type related problems
+ final int InterfaceCannotHaveInitializers = TypeRelated + 300;
+ final int DuplicateModifierForType = TypeRelated + 301;
+ final int IllegalModifierForClass = TypeRelated + 302;
+ final int IllegalModifierForInterface = TypeRelated + 303;
+ final int IllegalModifierForMemberClass = TypeRelated + 304;
+ final int IllegalModifierForMemberInterface = TypeRelated + 305;
+ final int IllegalModifierForLocalClass = TypeRelated + 306;
+ // final int IllegalModifierForLocalInterface = TypeRelated + 307;
+ final int IllegalModifierCombinationFinalAbstractForClass = TypeRelated + 308;
+ final int IllegalVisibilityModifierForInterfaceMemberType = TypeRelated + 309;
+ final int IllegalVisibilityModifierCombinationForMemberType = TypeRelated + 310;
+ final int IllegalStaticModifierForMemberType = TypeRelated + 311;
+ final int SuperclassMustBeAClass = TypeRelated + 312;
+ final int ClassExtendFinalClass = TypeRelated + 313;
+ final int DuplicateSuperInterface = TypeRelated + 314;
+ final int SuperInterfaceMustBeAnInterface = TypeRelated + 315;
+ final int HierarchyCircularitySelfReference = TypeRelated + 316;
+ final int HierarchyCircularity = TypeRelated + 317;
+ final int HidingEnclosingType = TypeRelated + 318;
+ final int DuplicateNestedType = TypeRelated + 319;
+ final int CannotThrowType = TypeRelated + 320;
+ final int PackageCollidesWithType = TypeRelated + 321;
+ final int TypeCollidesWithPackage = TypeRelated + 322;
+ final int DuplicateTypes = TypeRelated + 323;
+ final int IsClassPathCorrect = TypeRelated + 324;
+ final int PublicClassMustMatchFileName = TypeRelated + 325;
+ final int MustSpecifyPackage = 326;
+ final int HierarchyHasProblems = TypeRelated + 327;
+ final int InvalidSuperclassBase = TypeRelated + 329;
+ // reserved to 334 included
+
+ final int InvalidInterfaceBase = TypeRelated + 334;
+ // reserved to 339 included
+
+ // field related problems
+ final int DuplicateField = FieldRelated + 340;
+ final int DuplicateModifierForField = FieldRelated + 341;
+ final int IllegalModifierForField = FieldRelated + 342;
+ final int IllegalModifierForInterfaceField = FieldRelated + 343;
+ final int IllegalVisibilityModifierCombinationForField = FieldRelated + 344;
+ final int IllegalModifierCombinationFinalVolatileForField = FieldRelated + 345;
+ final int UnexpectedStaticModifierForField = FieldRelated + 346;
+ final int FieldTypeProblemBase = FieldRelated + 349; //reserved to 354
+
+ // method related problems
+ final int DuplicateMethod = MethodRelated + 355;
+ final int IllegalModifierForArgument = MethodRelated + 356;
+ final int DuplicateModifierForMethod = MethodRelated + 357;
+ final int IllegalModifierForMethod = MethodRelated + 358;
+ final int IllegalModifierForInterfaceMethod = MethodRelated + 359;
+ final int IllegalVisibilityModifierCombinationForMethod = MethodRelated + 360;
+ final int UnexpectedStaticModifierForMethod = MethodRelated + 361;
+ final int IllegalAbstractModifierCombinationForMethod = MethodRelated + 362;
+ final int AbstractMethodInAbstractClass = MethodRelated + 363;
+ final int ArgumentTypeCannotBeVoid = MethodRelated + 364;
+ final int ArgumentTypeCannotBeVoidArray = MethodRelated + 365;
+ final int ReturnTypeCannotBeVoidArray = MethodRelated + 366;
+ final int NativeMethodsCannotBeStrictfp = MethodRelated + 367;
+ final int ArgumentProblemBase = MethodRelated + 369;
+ // reserved to 374 included.
+
+ final int ExceptionTypeProblemBase = MethodRelated + 374;
+ // reserved to 379 included.
+
+ final int ReturnTypeProblemBase = MethodRelated + 379;
+ // reserved to 384 included.
+
+ // import related problems
+ final int ConflictingImport = ImportRelated + 385;
+ final int DuplicateImport = ImportRelated + 386;
+ final int CannotImportPackage = ImportRelated + 387;
+ final int ImportProblemBase = ImportRelated + 389;
+ // reserved to 394 included.
+
+ // local variable related problems
+ final int DuplicateModifierForVariable = MethodRelated + 395;
+ final int IllegalModifierForVariable = MethodRelated + 396;
+
+ // method verifier problems
+ final int AbstractMethodMustBeImplemented = MethodRelated + 400;
+ final int FinalMethodCannotBeOverridden = MethodRelated + 401;
+ final int IncompatibleExceptionInThrowsClause = MethodRelated + 402;
+ final int IncompatibleExceptionInInheritedMethodThrowsClause =
+ MethodRelated + 403;
+ final int IncompatibleReturnType = MethodRelated + 404;
+ final int InheritedMethodReducesVisibility = MethodRelated + 405;
+ final int CannotOverrideAStaticMethodWithAnInstanceMethod = MethodRelated + 406;
+ final int CannotHideAnInstanceMethodWithAStaticMethod = MethodRelated + 407;
+ final int StaticInheritedMethodConflicts = MethodRelated + 408;
+ final int MethodReducesVisibility = MethodRelated + 409;
+ final int OverridingNonVisibleMethod = MethodRelated + 410;
+ final int AbstractMethodCannotBeOverridden = MethodRelated + 411;
+ final int OverridingDeprecatedMethod = MethodRelated + 412;
+
+ // code snippet support
+ final int CodeSnippetMissingClass = Internal + 420;
+ final int CodeSnippetMissingMethod = Internal + 421;
+}
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
new file mode 100644
index 0000000000..276c541a23
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
@@ -0,0 +1,2670 @@
+package org.eclipse.jdt.internal.compiler.problem;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.parser.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+import org.eclipse.jdt.internal.compiler.impl.*;
+
+public class ProblemReporter
+ extends ProblemHandler
+ implements ConfigurableProblems, ProblemIrritants, ProblemReasons {
+ public ReferenceContext referenceContext;
+ public ProblemReporter(
+ IErrorHandlingPolicy policy,
+ CompilerOptions options,
+ IProblemFactory problemFactory) {
+ super(policy, options, problemFactory);
+ }
+
+ public void abortDueToInternalError(String errorMessage) {
+ this.handle(
+ UnclassifiedProblem,
+ new String[] { errorMessage },
+ Error | Abort,
+ 0,
+ 0);
+ }
+
+ public void abortDueToInternalError(String errorMessage, AstNode location) {
+ this.handle(
+ UnclassifiedProblem,
+ new String[] { errorMessage },
+ Error | Abort,
+ location.sourceStart(),
+ location.sourceEnd());
+ }
+
+ public void abstractMethodCannotBeOverridden(
+ SourceTypeBinding type,
+ MethodBinding concreteMethod) {
+
+ this.handle(
+ // %1 must be abstract since it cannot override the inherited package-private abstract method %2
+ AbstractMethodCannotBeOverridden,
+ new String[] {
+ new String(type.sourceName()),
+ new String(concreteMethod.readableName())},
+ type.sourceStart(),
+ type.sourceEnd());
+ }
+
+ public void abstractMethodInAbstractClass(
+ SourceTypeBinding type,
+ AbstractMethodDeclaration methodDecl) {
+ this.handle(
+ AbstractMethodInAbstractClass,
+ new String[] { new String(type.sourceName()), new String(methodDecl.selector)},
+ methodDecl.sourceStart(),
+ methodDecl.sourceEnd());
+ }
+
+ public void abstractMethodMustBeImplemented(
+ SourceTypeBinding type,
+ MethodBinding abstractMethod) {
+ this.handle(
+ // Must implement the inherited abstract method %1
+ // 8.4.3 - Every non-abstract subclass of an abstract type, A, must provide a concrete implementation of all of A's methods.
+ AbstractMethodMustBeImplemented,
+ new String[] {
+ new String(
+ CharOperation.concat(
+ abstractMethod.declaringClass.readableName(),
+ abstractMethod.readableName(),
+ '.'))},
+ type.sourceStart(),
+ type.sourceEnd());
+ }
+
+ public void abstractMethodNeedingNoBody(
+ AbstractMethodDeclaration method,
+ CompilationResult result) {
+ this.handle(
+ BodyForAbstractMethod,
+ new String[0],
+ method.sourceStart,
+ method.sourceEnd,
+ method,
+ result);
+ }
+
+ public void alreadyDefinedLabel(char[] labelName, AstNode location) {
+ this.handle(
+ DuplicateLabel,
+ new String[] { new String(labelName)},
+ location.sourceStart(),
+ location.sourceEnd());
+ }
+
+ public void anonymousClassCannotExtendFinalClass(
+ Expression expression,
+ TypeBinding type) {
+ this.handle(
+ AnonymousClassCannotExtendFinalClass,
+ new String[] { new String(type.readableName())},
+ expression.sourceStart,
+ expression.sourceEnd);
+ }
+
+ public void argumentTypeCannotBeVoid(
+ SourceTypeBinding type,
+ AbstractMethodDeclaration methodDecl,
+ Argument arg) {
+ this.handle(
+ ArgumentTypeCannotBeVoid,
+ new String[] { new String(methodDecl.selector), new String(arg.name)},
+ methodDecl.sourceStart(),
+ methodDecl.sourceEnd());
+ }
+
+ public void argumentTypeCannotBeVoidArray(
+ SourceTypeBinding type,
+ AbstractMethodDeclaration methodDecl,
+ Argument arg) {
+ this.handle(
+ ArgumentTypeCannotBeVoidArray,
+ new String[] { new String(methodDecl.selector), new String(arg.name)},
+ methodDecl.sourceStart(),
+ methodDecl.sourceEnd());
+ }
+
+ public void argumentTypeProblem(
+ SourceTypeBinding type,
+ AbstractMethodDeclaration methodDecl,
+ Argument arg,
+ TypeBinding expectedType) {
+ int problemId = expectedType.problemId();
+ switch (problemId) {
+ case NotFound : // 1
+ case NotVisible : // 2
+ case Ambiguous : // 3
+ case InternalNameProvided : // 4
+ case InheritedNameHidesEnclosingName : // 5
+ this.handle(
+ ArgumentProblemBase + problemId,
+ new String[] {
+ new String(methodDecl.selector),
+ arg.name(),
+ new String(expectedType.readableName())},
+ arg.type.sourceStart(),
+ arg.type.sourceEnd());
+ break;
+ case NoError : // 0
+ default :
+ needImplementation(); // want to fail to see why we were here...
+ break;
+ }
+ }
+
+ public void arrayConstantsOnlyInArrayInitializers(
+ int sourceStart,
+ int sourceEnd) {
+ this.handle(
+ ArrayConstantsOnlyInArrayInitializers,
+ new String[0],
+ sourceStart,
+ sourceEnd);
+ }
+
+ public void attemptToReturnNonVoidExpression(
+ ReturnStatement returnStatement,
+ TypeBinding expectedType) {
+ this.handle(
+ VoidMethodReturnsValue,
+ new String[] { new String(expectedType.readableName())},
+ returnStatement.sourceStart,
+ returnStatement.sourceEnd);
+ }
+
+ public void attemptToReturnVoidValue(ReturnStatement returnStatement) {
+ this.handle(MethodReturnsVoid, new String[] {
+ }, returnStatement.sourceStart, returnStatement.sourceEnd);
+ }
+
+ public void bytecodeExceeds64KLimit(AbstractMethodDeclaration location) {
+ this.handle(
+ BytecodeExceeds64KLimit,
+ new String[] { new String(location.selector)},
+ Error | Abort,
+ location.sourceStart(),
+ location.sourceEnd());
+ }
+
+ public void bytecodeExceeds64KLimit(TypeDeclaration location) {
+ this.handle(
+ BytecodeExceeds64KLimitForClinit,
+ new String[0],
+ Error | Abort,
+ location.sourceStart(),
+ location.sourceEnd());
+ }
+
+ public void cannotAllocateVoidArray(Expression expression) {
+ this.handle(CannotAllocateVoidArray, new String[] {
+ }, expression.sourceStart, expression.sourceEnd);
+ }
+
+ public void cannotAssignToFinalField(FieldBinding field, AstNode location) {
+ this.handle(
+ FinalFieldAssignment,
+ new String[] {
+ (field.declaringClass == null
+ ? "array"
+ : new String(field.declaringClass.readableName())),
+ new String(field.readableName())},
+ location.sourceStart(),
+ location.sourceEnd());
+ }
+
+ public void cannotAssignToFinalOuterLocal(
+ LocalVariableBinding local,
+ AstNode location) {
+ this.handle(
+ FinalOuterLocalAssignment,
+ new String[] { new String(local.readableName())},
+ location.sourceStart(),
+ location.sourceEnd());
+ }
+
+ public void cannotDeclareLocalInterface(
+ char[] interfaceName,
+ int sourceStart,
+ int sourceEnd) {
+ this.handle(
+ CannotDefineInterfaceInLocalType,
+ new String[] { new String(interfaceName)},
+ sourceStart,
+ sourceEnd);
+ }
+
+ public void cannotDefineDimensionsAndInitializer(ArrayAllocationExpression expresssion) {
+ this.handle(
+ CannotDefineDimensionExpressionsWithInit,
+ new String[0],
+ expresssion.sourceStart,
+ expresssion.sourceEnd);
+ }
+
+ public void cannotDireclyInvokeAbstractMethod(
+ MessageSend messageSend,
+ MethodBinding method) {
+ this.handle(
+ DirectInvocationOfAbstractMethod,
+ new String[] {
+ new String(method.declaringClass.readableName()),
+ new String(method.selector),
+ parametersAsString(method)},
+ messageSend.sourceStart,
+ messageSend.sourceEnd);
+ }
+
+ public void cannotImportPackage(ImportReference importRef) {
+ this.handle(
+ CannotImportPackage,
+ new String[] { CharOperation.toString(importRef.tokens)},
+ importRef.sourceStart(),
+ importRef.sourceEnd());
+ }
+
+ public void cannotInstantiate(TypeReference typeRef, TypeBinding type) {
+ this.handle(
+ InvalidClassInstantiation,
+ new String[] { new String(type.readableName())},
+ typeRef.sourceStart,
+ typeRef.sourceEnd);
+ }
+
+ public void cannotReferToNonFinalOuterLocal(
+ LocalVariableBinding local,
+ AstNode location) {
+ this.handle(
+ OuterLocalMustBeFinal,
+ new String[] { new String(local.readableName())},
+ location.sourceStart(),
+ location.sourceEnd());
+ }
+
+ public void cannotReturnInInitializer(AstNode location) {
+ this.handle(
+ CannotReturnInInitializer,
+ new String[0],
+ location.sourceStart(),
+ location.sourceEnd());
+ }
+
+ public void cannotThrowNull(ThrowStatement statement) {
+ this.handle(
+ CannotThrowNull,
+ new String[0],
+ statement.sourceStart,
+ statement.sourceEnd);
+ }
+
+ public void cannotThrowType(
+ SourceTypeBinding type,
+ AbstractMethodDeclaration methodDecl,
+ TypeReference exceptionType,
+ TypeBinding expectedType) {
+ this.handle(
+ CannotThrowType,
+ new String[] { new String(expectedType.readableName())},
+ exceptionType.sourceStart(),
+ exceptionType.sourceEnd());
+ }
+
+ public void cannotUseSuperInJavaLangObject(AstNode reference) {
+ this.handle(
+ ObjectHasNoSuperclass,
+ new String[0],
+ reference.sourceStart,
+ reference.sourceEnd);
+ }
+
+ public void caseExpressionMustBeConstant(Expression expression) {
+ this.handle(
+ NonConstantExpression,
+ new String[0],
+ expression.sourceStart,
+ expression.sourceEnd);
+ }
+
+ public void classExtendFinalClass(
+ SourceTypeBinding type,
+ TypeReference superclass,
+ TypeBinding expectedType) {
+ this.handle(
+ ClassExtendFinalClass,
+ new String[] {
+ new String(expectedType.readableName()),
+ new String(type.sourceName())},
+ superclass.sourceStart(),
+ superclass.sourceEnd());
+ }
+
+ public void codeSnippetMissingClass(String missing, int start, int end) {
+ this.handle(
+ CodeSnippetMissingClass,
+ new String[] { missing },
+ Error | Abort,
+ start,
+ end);
+ }
+
+ public void codeSnippetMissingMethod(
+ String className,
+ String missingMethod,
+ String argumentTypes,
+ int start,
+ int end) {
+ this.handle(
+ CodeSnippetMissingMethod,
+ new String[] { className, missingMethod, argumentTypes },
+ Error | Abort,
+ start,
+ end);
+ }
+
+ /*
+ * Given the current configuration, answers which category the problem
+ * falls into:
+ * Error | Warning | Ignore
+ */
+ public int computeSeverity(int problemId) {
+
+ // severity can have been preset on the problem
+ // if ((problem.severity & Fatal) != 0){
+ // return Error;
+ // }
+
+ // if not then check whether it is a configurable problem
+ int errorThreshold = options.errorThreshold;
+ int warningThreshold = options.warningThreshold;
+
+ switch (problemId) {
+
+ case UnreachableCatch :
+ case CodeCannotBeReached :
+ if ((errorThreshold & UnreachableCode) != 0) {
+ return Error;
+ }
+ if ((warningThreshold & UnreachableCode) != 0) {
+ return Warning;
+ }
+ return Ignore;
+
+ case MaskedCatch :
+ if ((errorThreshold & MaskedCatchBlock) != 0) {
+ return Error;
+ }
+ if ((warningThreshold & MaskedCatchBlock) != 0) {
+ return Warning;
+ }
+ return Ignore;
+
+ /*
+ case Never Used :
+ if ((errorThreshold & ParsingOptionalError) != 0){
+ return Error;
+ }
+ if ((warningThreshold & ParsingOptionalError) != 0){
+ return Warning;
+ }
+ return Ignore;
+ */
+ case ImportProblemBase + NotFound :
+ case ImportProblemBase + NotVisible :
+ case ImportProblemBase + Ambiguous :
+ case ImportProblemBase + InternalNameProvided :
+ case ImportProblemBase + InheritedNameHidesEnclosingName :
+ case DuplicateImport :
+ case ConflictingImport :
+ case CannotImportPackage :
+ if ((errorThreshold & ImportProblem) != 0) {
+ return Error;
+ }
+ if ((warningThreshold & ImportProblem) != 0) {
+ return Warning;
+ }
+ return Ignore;
+ /*
+ case UnnecessaryEnclosingInstanceSpecification :
+ if ((errorThreshold & UnnecessaryEnclosingInstance) != 0){
+ return Error;
+ }
+ if ((warningThreshold & UnnecessaryEnclosingInstance) != 0){
+ return Warning;
+ }
+ return Ignore;
+ */
+ case MethodButWithConstructorName :
+ if ((errorThreshold & MethodWithConstructorName) != 0) {
+ return Error;
+ }
+ if ((warningThreshold & MethodWithConstructorName) != 0) {
+ return Warning;
+ }
+ return Ignore;
+
+ case OverridingNonVisibleMethod :
+ if ((errorThreshold & OverriddenPackageDefaultMethod) != 0) {
+ return Error;
+ }
+ if ((warningThreshold & OverriddenPackageDefaultMethod) != 0) {
+ return Warning;
+ }
+ return Ignore;
+
+ case OverridingDeprecatedMethod :
+ case UsingDeprecatedType :
+ case UsingDeprecatedMethod :
+ case UsingDeprecatedConstructor :
+ case UsingDeprecatedField :
+ if ((errorThreshold & UsingDeprecatedAPI) != 0) {
+ return Error;
+ }
+ if ((warningThreshold & UsingDeprecatedAPI) != 0) {
+ return Warning;
+ }
+ return Ignore;
+
+ case LocalVariableIsNeverUsed :
+ if ((errorThreshold & UnusedLocalVariable) != 0) {
+ return Error;
+ }
+ if ((warningThreshold & UnusedLocalVariable) != 0) {
+ return Warning;
+ }
+ return Ignore;
+
+ case ArgumentIsNeverUsed :
+ if ((errorThreshold & UnusedArgument) != 0) {
+ return Error;
+ }
+ if ((warningThreshold & UnusedArgument) != 0) {
+ return Warning;
+ }
+ return Ignore;
+
+ case NoImplicitStringConversionForCharArrayExpression :
+ if ((errorThreshold & TemporaryWarning) != 0) {
+ return Error;
+ }
+ if ((warningThreshold & TemporaryWarning) != 0) {
+ return Warning;
+ }
+ return Ignore;
+
+ case NeedToEmulateFieldReadAccess :
+ case NeedToEmulateFieldWriteAccess :
+ case NeedToEmulateMethodAccess :
+ case NeedToEmulateConstructorAccess :
+ if ((errorThreshold & AccessEmulation) != 0) {
+ return Error;
+ }
+ if ((warningThreshold & AccessEmulation) != 0) {
+ return Warning;
+ }
+ return Ignore;
+
+ default :
+ return Error;
+ }
+ }
+
+ public void conditionalArgumentsIncompatibleTypes(
+ ConditionalExpression expression,
+ TypeBinding trueType,
+ TypeBinding falseType) {
+ this.handle(
+ IncompatibleTypesInConditionalOperator,
+ new String[] {
+ new String(trueType.readableName()),
+ new String(falseType.readableName())},
+ expression.sourceStart,
+ expression.sourceEnd);
+ }
+
+ public void conflictingImport(ImportReference importRef) {
+ this.handle(
+ ConflictingImport,
+ new String[] { CharOperation.toString(importRef.tokens)},
+ importRef.sourceStart(),
+ importRef.sourceEnd());
+ }
+
+ public void constantOutOfFormat(NumberLiteral lit) {
+ // the literal is not in a correct format
+ // this code is called on IntLiteral and LongLiteral
+ // example 000811 ...the 8 is uncorrect.
+
+ if ((lit instanceof LongLiteral) || (lit instanceof IntLiteral)) {
+ char[] source = lit.source();
+ try {
+ final String Radix;
+ final int radix;
+ if ((source[1] == 'x') || (source[1] == 'X')) {
+ radix = 16;
+ Radix = "Hexa";
+ } else {
+ radix = 8;
+ Radix = "Octal";
+ }
+ //look for the first digit that is incorrect
+ int place = -1;
+ label : for (int i = radix == 8 ? 1 : 2; i < source.length; i++) {
+ if (Character.digit(source[i], radix) == -1) {
+ place = i;
+ break label;
+ }
+ }
+
+ this.handle(
+ NumericValueOutOfRange,
+ new String[] {
+ Radix
+ + " "
+ + new String(source)
+ + " (digit "
+ + new String(new char[] { source[place] })
+ + ")" },
+ lit.sourceStart,
+ lit.sourceEnd);
+ return;
+ } catch (IndexOutOfBoundsException ex) {
+ }
+
+ // just in case .... use a predefined error..
+ // we should never come here...(except if the code changes !)
+ this.constantOutOfRange(lit);
+ }
+ }
+
+ public void constantOutOfRange(Literal lit) {
+ // lit is some how out of range of it declared type
+ // example 9999999999999999999999999999999999999999999999999999999999999999999
+
+ this.handle(
+ NumericValueOutOfRange,
+ new String[] { new String(lit.source())},
+ lit.sourceStart,
+ lit.sourceEnd);
+ }
+
+ public void deprecatedField(FieldBinding field, AstNode location) {
+ this.handle(
+ UsingDeprecatedField,
+ new String[] {
+ new String(field.declaringClass.readableName()),
+ new String(field.name)},
+ location.sourceStart,
+ location.sourceEnd);
+ }
+
+ public void deprecatedMethod(MethodBinding method, AstNode location) {
+ if (method.isConstructor())
+ this.handle(
+ UsingDeprecatedConstructor,
+ new String[] {
+ new String(method.declaringClass.readableName()),
+ parametersAsString(method)},
+ location.sourceStart,
+ location.sourceEnd);
+ else
+ this.handle(
+ UsingDeprecatedMethod,
+ new String[] {
+ new String(method.declaringClass.readableName()),
+ new String(method.selector),
+ parametersAsString(method)},
+ location.sourceStart,
+ location.sourceEnd);
+ }
+
+ public void deprecatedType(TypeBinding type, AstNode location) {
+ if (location == null)
+ return; // 1G828DN - no type ref for synthetic arguments
+ this.handle(
+ UsingDeprecatedType,
+ new String[] { new String(type.readableName())},
+ location.sourceStart,
+ location.sourceEnd);
+ }
+
+ public void duplicateCase(Case statement, Constant constant) {
+ this.handle(
+ DuplicateCase,
+ new String[] { String.valueOf(constant.intValue())},
+ statement.sourceStart,
+ statement.sourceEnd);
+ }
+
+ public void duplicateDefaultCase(DefaultCase statement) {
+ this.handle(
+ DuplicateDefaultCase,
+ new String[0],
+ statement.sourceStart,
+ statement.sourceEnd);
+ }
+
+ public void duplicateFieldInType(
+ SourceTypeBinding type,
+ FieldDeclaration fieldDecl) {
+ this.handle(
+ DuplicateField,
+ new String[] { new String(type.sourceName()), fieldDecl.name()},
+ fieldDecl.sourceStart(),
+ fieldDecl.sourceEnd());
+ }
+
+ public void duplicateImport(ImportReference importRef) {
+ this.handle(
+ DuplicateImport,
+ new String[] { CharOperation.toString(importRef.tokens)},
+ importRef.sourceStart(),
+ importRef.sourceEnd());
+ }
+
+ public void duplicateInitializationOfBlankFinalField(
+ FieldBinding field,
+ Reference reference) {
+ this.handle(
+ DuplicateBlankFinalFieldInitialization,
+ new String[] { new String(field.readableName())},
+ reference.sourceStart(),
+ reference.sourceEnd());
+ }
+
+ public void duplicateInitializationOfFinalLocal(
+ LocalVariableBinding local,
+ NameReference reference) {
+ this.handle(
+ DuplicateFinalLocalInitialization,
+ new String[] { new String(local.readableName())},
+ reference.sourceStart(),
+ reference.sourceEnd());
+ }
+
+ public void duplicateMethodInType(
+ SourceTypeBinding type,
+ AbstractMethodDeclaration methodDecl) {
+ this.handle(
+ DuplicateMethod,
+ new String[] { new String(methodDecl.selector), new String(type.sourceName())},
+ methodDecl.sourceStart(),
+ methodDecl.sourceEnd());
+ }
+
+ public void duplicateModifierForField(
+ ReferenceBinding type,
+ FieldDeclaration fieldDecl) {
+ /* to highlight modifiers use:
+ this.handle(
+ new Problem(
+ DuplicateModifierForField,
+ new String[] {fieldDecl.name()},
+ fieldDecl.modifiers.sourceStart(),
+ fieldDecl.modifiers.sourceEnd()));
+ */
+
+ this.handle(
+ DuplicateModifierForField,
+ new String[] { fieldDecl.name()},
+ fieldDecl.sourceStart(),
+ fieldDecl.sourceEnd());
+ }
+
+ public void duplicateModifierForMethod(
+ ReferenceBinding type,
+ AbstractMethodDeclaration methodDecl) {
+ this.handle(
+ DuplicateModifierForMethod,
+ new String[] { new String(type.sourceName()), new String(methodDecl.selector)},
+ methodDecl.sourceStart(),
+ methodDecl.sourceEnd());
+ }
+
+ public void duplicateModifierForType(SourceTypeBinding type) {
+ this.handle(
+ DuplicateModifierForType,
+ new String[] { new String(type.sourceName())},
+ type.sourceStart(),
+ type.sourceEnd());
+ }
+
+ public void duplicateModifierForVariable(LocalDeclaration localDecl) {
+ this.handle(
+ DuplicateModifierForVariable,
+ new String[] { localDecl.name()},
+ localDecl.sourceStart(),
+ localDecl.sourceEnd());
+ }
+
+ public void duplicateNestedType(TypeDeclaration typeDecl) {
+ this.handle(
+ DuplicateNestedType,
+ new String[] { new String(typeDecl.name)},
+ typeDecl.sourceStart(),
+ typeDecl.sourceEnd());
+ }
+
+ public void duplicateSuperinterface(
+ SourceTypeBinding type,
+ TypeDeclaration typeDecl,
+ ReferenceBinding superType) {
+ this.handle(
+ DuplicateSuperInterface,
+ new String[] {
+ new String(superType.readableName()),
+ new String(type.sourceName())},
+ typeDecl.sourceStart(),
+ typeDecl.sourceEnd());
+ }
+
+ public void duplicateTypes(
+ CompilationUnitDeclaration compUnitDecl,
+ TypeDeclaration typeDecl) {
+ this.referenceContext = typeDecl;
+ // report the problem against the type not the entire compilation unit
+ this.handle(
+ DuplicateTypes,
+ new String[] {
+ new String(compUnitDecl.getFileName()),
+ new String(typeDecl.name)},
+ typeDecl.sourceStart(),
+ typeDecl.sourceEnd(),
+ compUnitDecl.compilationResult);
+ }
+
+ public void errorNoMethodFor(
+ MessageSend messageSend,
+ TypeBinding recType,
+ TypeBinding[] params) {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0, length = params.length; i < length; i++) {
+ if (i != 0)
+ buffer.append(", ");
+ buffer.append(new String(params[i].readableName()));
+ }
+
+ this.handle(
+ recType.isArrayType() ? NoMessageSendOnArrayType : NoMessageSendOnBaseType,
+ new String[] {
+ new String(recType.readableName()),
+ new String(messageSend.selector),
+ buffer.toString()},
+ messageSend.sourceStart,
+ messageSend.sourceEnd);
+ }
+
+ public void errorThisSuperInStatic(AstNode reference) {
+ this.handle(
+ ThisInStaticContext,
+ new String[] { reference.isSuper() ? "super" : "this" },
+ reference.sourceStart,
+ reference.sourceEnd);
+ }
+
+ public void exceptionTypeProblem(
+ SourceTypeBinding type,
+ AbstractMethodDeclaration methodDecl,
+ TypeReference exceptionType,
+ TypeBinding expectedType) {
+ int problemId = expectedType.problemId();
+ switch (problemId) {
+ case NotFound : // 1
+ case NotVisible : // 2
+ case Ambiguous : // 3
+ case InternalNameProvided : // 4
+ case InheritedNameHidesEnclosingName : // 5
+ this.handle(
+ ExceptionTypeProblemBase + problemId,
+ new String[] {
+ new String(methodDecl.selector),
+ new String(expectedType.readableName())},
+ exceptionType.sourceStart(),
+ exceptionType.sourceEnd());
+ break;
+ case NoError : // 0
+ default :
+ needImplementation(); // want to fail to see why we were here...
+ break;
+ }
+ }
+
+ public void fieldsOrThisBeforeConstructorInvocation(ThisReference reference) {
+ this.handle(
+ ThisSuperDuringConstructorInvocation,
+ new String[0],
+ reference.sourceStart,
+ reference.sourceEnd);
+ }
+
+ public void fieldTypeProblem(
+ SourceTypeBinding type,
+ FieldDeclaration fieldDecl,
+ TypeBinding expectedType) {
+ int problemId = expectedType.problemId();
+ switch (problemId) {
+ case NotFound : // 1
+ case NotVisible : // 2
+ case Ambiguous : // 3
+ case InternalNameProvided : // 4
+ case InheritedNameHidesEnclosingName : // 5
+ this.handle(
+ FieldTypeProblemBase + problemId,
+ new String[] {
+ fieldDecl.name(),
+ new String(type.sourceName()),
+ new String(expectedType.readableName())},
+ fieldDecl.type.sourceStart(),
+ fieldDecl.type.sourceEnd());
+ break;
+ case NoError : // 0
+ default :
+ needImplementation(); // want to fail to see why we were here...
+ break;
+ }
+ }
+
+ public void finalMethodCannotBeOverridden(
+ MethodBinding currentMethod,
+ MethodBinding inheritedMethod) {
+ this.handle(
+ // Cannot override the final method from %1
+ // 8.4.3.3 - Final methods cannot be overridden or hidden.
+ FinalMethodCannotBeOverridden,
+ new String[] { new String(inheritedMethod.declaringClass.readableName())},
+ currentMethod.sourceStart(),
+ currentMethod.sourceEnd());
+ }
+
+ public void forwardReference(
+ Reference reference,
+ int indexInQualification,
+ TypeBinding type) {
+ this.handle(ReferenceToForwardField, new String[] {
+ }, reference.sourceStart, reference.sourceEnd);
+ }
+
+ // use this private API when the compilation unit result can be found through the
+ // reference context. Otherwise, use the other API taking a problem and a compilation result
+ // as arguments
+
+ private void handle(
+ int problemId,
+ String[] problemArguments,
+ int problemStartPosition,
+ int problemEndPosition) {
+
+ this.handle(
+ problemId,
+ problemArguments,
+ problemStartPosition,
+ problemEndPosition,
+ referenceContext,
+ referenceContext == null ? null : referenceContext.compilationResult());
+ referenceContext = null;
+ }
+
+ // use this private API when the compilation unit result can be found through the
+ // reference context. Otherwise, use the other API taking a problem and a compilation result
+ // as arguments
+
+ private void handle(
+ int problemId,
+ String[] problemArguments,
+ int severity,
+ int problemStartPosition,
+ int problemEndPosition) {
+
+ this.handle(
+ problemId,
+ problemArguments,
+ severity,
+ problemStartPosition,
+ problemEndPosition,
+ referenceContext,
+ referenceContext == null ? null : referenceContext.compilationResult());
+ referenceContext = null;
+ }
+
+ // use this private API when the compilation unit result cannot be found through the
+ // reference context.
+
+ private void handle(
+ int problemId,
+ String[] problemArguments,
+ int problemStartPosition,
+ int problemEndPosition,
+ CompilationResult unitResult) {
+
+ this.handle(
+ problemId,
+ problemArguments,
+ problemStartPosition,
+ problemEndPosition,
+ referenceContext,
+ unitResult);
+ referenceContext = null;
+ }
+
+ public void hidingEnclosingType(TypeDeclaration typeDecl) {
+ this.handle(
+ HidingEnclosingType,
+ new String[] { new String(typeDecl.name)},
+ typeDecl.sourceStart(),
+ typeDecl.sourceEnd());
+ }
+
+ public void hierarchyCircularity(
+ SourceTypeBinding sourceType,
+ ReferenceBinding superType,
+ TypeReference reference) {
+ int start = 0;
+ int end = 0;
+ String typeName = "";
+
+ if (reference == null) { // can only happen when java.lang.Object is busted
+ start = sourceType.sourceStart();
+ end = sourceType.sourceEnd();
+ typeName = new String(superType.readableName());
+ } else {
+ start = reference.sourceStart();
+ end = reference.sourceEnd();
+ typeName = CharOperation.toString(reference.getTypeName());
+ }
+
+ if (sourceType == superType)
+ this.handle(
+ HierarchyCircularitySelfReference,
+ new String[] { new String(sourceType.sourceName()), typeName },
+ start,
+ end);
+ else
+ this.handle(
+ HierarchyCircularity,
+ new String[] { new String(sourceType.sourceName()), typeName },
+ start,
+ end);
+ }
+
+ public void hierarchyHasProblems(SourceTypeBinding type) {
+ this.handle(
+ HierarchyHasProblems,
+ new String[] { new String(type.sourceName())},
+ type.sourceStart(),
+ type.sourceEnd());
+ }
+
+ public void illegalAbstractModifierCombinationForMethod(
+ ReferenceBinding type,
+ AbstractMethodDeclaration methodDecl) {
+ this.handle(
+ IllegalAbstractModifierCombinationForMethod,
+ new String[] { new String(type.sourceName()), new String(methodDecl.selector)},
+ methodDecl.sourceStart(),
+ methodDecl.sourceEnd());
+ }
+
+ public void illegalModifierCombinationFinalAbstractForClass(SourceTypeBinding type) {
+ this.handle(
+ IllegalModifierCombinationFinalAbstractForClass,
+ new String[] { new String(type.sourceName())},
+ type.sourceStart(),
+ type.sourceEnd());
+ }
+
+ public void illegalModifierCombinationFinalVolatileForField(
+ ReferenceBinding type,
+ FieldDeclaration fieldDecl) {
+ this.handle(
+ IllegalModifierCombinationFinalVolatileForField,
+ new String[] { fieldDecl.name()},
+ fieldDecl.sourceStart(),
+ fieldDecl.sourceEnd());
+ }
+
+ public void illegalModifierForArgument(
+ SourceTypeBinding type,
+ AbstractMethodDeclaration methodDecl,
+ Argument arg) {
+ this.handle(
+ IllegalModifierForArgument,
+ new String[] {
+ new String(type.sourceName()),
+ new String(methodDecl.selector),
+ arg.name()},
+ arg.sourceStart(),
+ arg.sourceEnd());
+ }
+
+ public void illegalModifierForClass(SourceTypeBinding type) {
+ this.handle(
+ IllegalModifierForClass,
+ new String[] { new String(type.sourceName())},
+ type.sourceStart(),
+ type.sourceEnd());
+ }
+
+ public void illegalModifierForField(
+ ReferenceBinding type,
+ FieldDeclaration fieldDecl) {
+ this.handle(
+ IllegalModifierForField,
+ new String[] { fieldDecl.name()},
+ fieldDecl.sourceStart(),
+ fieldDecl.sourceEnd());
+ }
+
+ public void illegalModifierForInterface(SourceTypeBinding type) {
+ this.handle(
+ IllegalModifierForInterface,
+ new String[] { new String(type.sourceName())},
+ type.sourceStart(),
+ type.sourceEnd());
+ }
+
+ public void illegalModifierForInterfaceField(
+ ReferenceBinding type,
+ FieldDeclaration fieldDecl) {
+ this.handle(
+ IllegalModifierForInterfaceField,
+ new String[] { fieldDecl.name()},
+ fieldDecl.sourceStart(),
+ fieldDecl.sourceEnd());
+ }
+
+ public void illegalModifierForInterfaceMethod(
+ ReferenceBinding type,
+ AbstractMethodDeclaration methodDecl) {
+ this.handle(
+ IllegalModifierForInterfaceMethod,
+ new String[] { new String(type.sourceName()), new String(methodDecl.selector)},
+ methodDecl.sourceStart(),
+ methodDecl.sourceEnd());
+ }
+
+ public void illegalModifierForLocalClass(SourceTypeBinding type) {
+ this.handle(
+ IllegalModifierForLocalClass,
+ new String[] { new String(type.sourceName())},
+ type.sourceStart(),
+ type.sourceEnd());
+ }
+
+ public void illegalModifierForMemberClass(SourceTypeBinding type) {
+ this.handle(
+ IllegalModifierForMemberClass,
+ new String[] { new String(type.sourceName())},
+ type.sourceStart(),
+ type.sourceEnd());
+ }
+
+ public void illegalModifierForMemberInterface(SourceTypeBinding type) {
+ this.handle(
+ IllegalModifierForMemberInterface,
+ new String[] { new String(type.sourceName())},
+ type.sourceStart(),
+ type.sourceEnd());
+ }
+
+ public void illegalModifierForMethod(
+ ReferenceBinding type,
+ AbstractMethodDeclaration methodDecl) {
+ this.handle(
+ IllegalModifierForMethod,
+ new String[] { new String(type.sourceName()), new String(methodDecl.selector)},
+ methodDecl.sourceStart(),
+ methodDecl.sourceEnd());
+ }
+
+ public void illegalModifierForVariable(LocalDeclaration localDecl) {
+ this.handle(
+ IllegalModifierForVariable,
+ new String[] { localDecl.name()},
+ localDecl.sourceStart(),
+ localDecl.sourceEnd());
+ }
+
+ public void illegalPrimitiveOrArrayTypeForEnclosingInstance(
+ TypeBinding enclosingType,
+ AstNode location) {
+ this.handle(
+ IllegalPrimitiveOrArrayTypeForEnclosingInstance,
+ new String[] { new String(enclosingType.readableName())},
+ location.sourceStart,
+ location.sourceEnd);
+ }
+
+ public void illegalStaticModifierForMemberType(SourceTypeBinding type) {
+ this.handle(
+ IllegalStaticModifierForMemberType,
+ new String[] { new String(type.sourceName())},
+ type.sourceStart(),
+ type.sourceEnd());
+ }
+
+ public void illegalVisibilityModifierCombinationForField(
+ ReferenceBinding type,
+ FieldDeclaration fieldDecl) {
+ this.handle(
+ IllegalVisibilityModifierCombinationForField,
+ new String[] { new String(fieldDecl.name())},
+ fieldDecl.sourceStart(),
+ fieldDecl.sourceEnd());
+ }
+
+ public void illegalVisibilityModifierCombinationForMemberType(SourceTypeBinding type) {
+ this.handle(
+ IllegalVisibilityModifierCombinationForMemberType,
+ new String[] { new String(type.sourceName())},
+ type.sourceStart(),
+ type.sourceEnd());
+ }
+
+ public void illegalVisibilityModifierCombinationForMethod(
+ ReferenceBinding type,
+ AbstractMethodDeclaration methodDecl) {
+ this.handle(
+ IllegalVisibilityModifierCombinationForMethod,
+ new String[] { new String(type.sourceName()), new String(methodDecl.selector)},
+ methodDecl.sourceStart(),
+ methodDecl.sourceEnd());
+ }
+
+ public void illegalVisibilityModifierForInterfaceMemberType(SourceTypeBinding type) {
+ this.handle(
+ IllegalVisibilityModifierForInterfaceMemberType,
+ new String[] { new String(type.sourceName())},
+ type.sourceStart(),
+ type.sourceEnd());
+ }
+
+ public void importProblem(ImportReference importRef, Binding expectedImport) {
+ int problemId = expectedImport.problemId();
+ switch (problemId) {
+ case NotFound : // 1
+ case NotVisible : // 2
+ case Ambiguous : // 3
+ case InternalNameProvided : // 4
+ case InheritedNameHidesEnclosingName : // 5
+ this.handle(
+ ImportProblemBase + problemId,
+ new String[] { CharOperation.toString(importRef.tokens)},
+ importRef.sourceStart(),
+ importRef.sourceEnd());
+ break;
+ case NoError : // 0
+ default :
+ needImplementation(); // want to fail to see why we were here...
+ break;
+ }
+ }
+
+ public void incompatibleExceptionInThrowsClause(
+ SourceTypeBinding type,
+ MethodBinding currentMethod,
+ MethodBinding inheritedMethod,
+ ReferenceBinding exceptionType) {
+ if (type == currentMethod.declaringClass)
+ this.handle(
+ // Exception %1 is not compatible with throws clause in %2
+ // 9.4.4 - The type of exception in the throws clause is incompatible.
+ IncompatibleExceptionInThrowsClause,
+ new String[] {
+ new String(exceptionType.sourceName()),
+ new String(
+ CharOperation.concat(
+ inheritedMethod.declaringClass.readableName(),
+ inheritedMethod.readableName(),
+ '.'))},
+ currentMethod.sourceStart(),
+ currentMethod.sourceEnd());
+ else
+ this.handle(
+ // Exception %1 in throws clause of %2 is not compatible with %3
+ // 9.4.4 - The type of exception in the throws clause is incompatible.
+ IncompatibleExceptionInInheritedMethodThrowsClause,
+ new String[] {
+ new String(exceptionType.sourceName()),
+ new String(
+ CharOperation.concat(
+ currentMethod.declaringClass.sourceName(),
+ currentMethod.readableName(),
+ '.')),
+ new String(
+ CharOperation.concat(
+ inheritedMethod.declaringClass.readableName(),
+ inheritedMethod.readableName(),
+ '.'))},
+ type.sourceStart(),
+ type.sourceEnd());
+ }
+
+ public void incompatibleReturnType(
+ MethodBinding currentMethod,
+ MethodBinding inheritedMethod) {
+ StringBuffer methodSignature = new StringBuffer();
+ methodSignature
+ .append(inheritedMethod.declaringClass.readableName())
+ .append('.')
+ .append(inheritedMethod.readableName());
+
+ this.handle(
+ // Return type is incompatible with %1
+ // 9.4.2 - The return type from the method is incompatible with the declaration.
+ IncompatibleReturnType,
+ new String[] { methodSignature.toString()},
+ currentMethod.sourceStart(),
+ currentMethod.sourceEnd());
+ }
+
+ public void incorrectEnclosingInstanceReference(
+ QualifiedThisReference reference,
+ TypeBinding qualificationType) {
+
+ this.handle(
+ IncorrectEnclosingInstanceReference,
+ new String[] { new String(qualificationType.readableName())},
+ reference.sourceStart,
+ reference.sourceEnd);
+ }
+
+ public void incorrectLocationForEmptyDimension(
+ ArrayAllocationExpression expression,
+ int index) {
+ this.handle(
+ IllegalDimension,
+ new String[0],
+ expression.dimensions[index + 1].sourceStart,
+ expression.dimensions[index + 1].sourceEnd);
+ }
+
+ public void incorrectSwitchType(Expression expression, TypeBinding testType) {
+ this.handle(
+ IncorrectSwitchType,
+ new String[] { new String(testType.readableName())},
+ expression.sourceStart,
+ expression.sourceEnd);
+ }
+
+ public void inheritedMethodReducesVisibility(
+ SourceTypeBinding type,
+ MethodBinding concreteMethod,
+ MethodBinding[] abstractMethods) {
+ this.handle(
+ // The method %1 cannot hide the public abstract method in %2
+ InheritedMethodReducesVisibility,
+ new String[] {
+ new String(concreteMethod.readableName()),
+ new String(abstractMethods[0].declaringClass.readableName())},
+ type.sourceStart(),
+ type.sourceEnd());
+ }
+
+ public void inheritedMethodsHaveIncompatibleReturnTypes(
+ SourceTypeBinding type,
+ MethodBinding[] inheritedMethods,
+ int length) {
+ StringBuffer methodSignatures = new StringBuffer();
+ for (int i = length; --i >= 0;) {
+ methodSignatures
+ .append(inheritedMethods[i].declaringClass.readableName())
+ .append('.')
+ .append(inheritedMethods[i].readableName());
+ if (i != 0)
+ methodSignatures.append(", ");
+ }
+
+ this.handle(
+ // Return type is incompatible with %1
+ // 9.4.2 - The return type from the method is incompatible with the declaration.
+ IncompatibleReturnType,
+ new String[] { methodSignatures.toString()},
+ type.sourceStart(),
+ type.sourceEnd());
+ }
+
+ public void initializerMustCompleteNormally(FieldDeclaration fieldDecl) {
+ this.handle(
+ InitializerMustCompleteNormally,
+ new String[0],
+ fieldDecl.sourceStart(),
+ fieldDecl.sourceEnd());
+ }
+
+ public void innerTypesCannotDeclareStaticInitializers(
+ ReferenceBinding innerType,
+ AstNode location) {
+ this.handle(
+ CannotDefineStaticInitializerInLocalType,
+ new String[] { new String(innerType.readableName())},
+ location.sourceStart(),
+ location.sourceEnd());
+ }
+
+ public void interfaceCannotHaveConstructors(
+ ConstructorDeclaration constructor,
+ CompilationResult result) {
+ this.handle(
+ InterfaceCannotHaveConstructors,
+ new String[0],
+ constructor.sourceStart,
+ constructor.sourceEnd,
+ constructor,
+ result);
+ }
+
+ public void interfaceCannotHaveInitializers(
+ SourceTypeBinding type,
+ FieldDeclaration fieldDecl) {
+ this.handle(
+ InterfaceCannotHaveInitializers,
+ new String[] { new String(type.sourceName())},
+ fieldDecl.sourceStart(),
+ fieldDecl.sourceEnd());
+ }
+
+ public void invalidBreak(AstNode location) {
+ this.handle(
+ InvalidBreak,
+ new String[0],
+ location.sourceStart(),
+ location.sourceEnd());
+ }
+
+ public void invalidConstructor(Statement statement, MethodBinding method) {
+ // CODE should be UPDATED according to error coding in the different method binding errors
+ // The different targetted errors should be :
+ // UndefinedConstructor
+ // NotVisibleConstructor
+ // AmbiguousConstructor
+
+ int flag = UndefinedConstructor; //default...
+ switch (method.problemId()) {
+ case NotFound :
+ flag = UndefinedConstructor;
+ break;
+ case NotVisible :
+ flag = NotVisibleConstructor;
+ break;
+ case Ambiguous :
+ flag = AmbiguousConstructor;
+ break;
+ case NoError : // 0
+ default :
+ needImplementation(); // want to fail to see why we were here...
+ break;
+ }
+
+ this.handle(
+ flag,
+ new String[] {
+ new String(method.declaringClass.readableName()),
+ parametersAsString(method)},
+ statement.sourceStart,
+ statement.sourceEnd);
+ }
+
+ public void invalidContinue(AstNode location) {
+ this.handle(
+ InvalidContinue,
+ new String[0],
+ location.sourceStart(),
+ location.sourceEnd());
+ }
+
+ public void invalidEnclosingType(
+ Expression expression,
+ TypeBinding type,
+ TypeBinding enclosingType) {
+ //CODE should be UPDATED according to error coding in the different type binding errors
+ //The different targetted errors should be :
+ //UndefinedType
+ //NotVisibleType
+ //AmbiguousType
+ //InternalNameProvided
+
+ int flag = UndefinedType; // default
+ switch (type.problemId()) {
+ case NotFound : // 1
+ flag = UndefinedType;
+ break;
+ case NotVisible : // 2
+ flag = NotVisibleType;
+ break;
+ case Ambiguous : // 3
+ flag = AmbiguousType;
+ break;
+ case InternalNameProvided :
+ flag = InternalTypeNameProvided;
+ break;
+ case NoError : // 0
+ default :
+ needImplementation(); // want to fail to see why we were here...
+ break;
+ }
+
+ this.handle(
+ flag,
+ new String[] {
+ new String(enclosingType.readableName())
+ + "."
+ + new String(type.readableName())},
+ expression.sourceStart,
+ expression.sourceEnd);
+ }
+
+ public void invalidExpressionAsStatement(Expression expression) {
+ this.handle(
+ InvalidExpressionAsStatement,
+ new String[0],
+ expression.sourceStart,
+ expression.sourceEnd);
+ }
+
+ public void invalidField(FieldReference fieldRef, TypeBinding searchedType) {
+ int severity = Error;
+ int flag = UndefinedField;
+ FieldBinding field = fieldRef.binding;
+ switch (field.problemId()) {
+ case NotFound :
+ flag = UndefinedField;
+ /* also need to check that the searchedType is the receiver type
+ if (searchedType.isHierarchyInconsistent())
+ severity = SecondaryError;
+ */
+ break;
+ case NotVisible :
+ flag = NotVisibleField;
+ break;
+ case Ambiguous :
+ flag = AmbiguousField;
+ break;
+ case NonStaticReferenceInStaticContext :
+ flag = NonStaticFieldFromStaticInvocation;
+ break;
+ case NonStaticReferenceInConstructorInvocation :
+ flag = InstanceFieldDuringConstructorInvocation;
+ break;
+ case InheritedNameHidesEnclosingName :
+ flag = InheritedFieldHidesEnclosingName;
+ break;
+ case NoError : // 0
+ default :
+ needImplementation(); // want to fail to see why we were here...
+ break;
+ }
+
+ this.handle(
+ flag,
+ new String[] { new String(field.readableName())},
+ severity,
+ fieldRef.sourceStart,
+ fieldRef.sourceEnd);
+ }
+
+ public void invalidField(NameReference nameRef, FieldBinding field) {
+ int flag = UndefinedField;
+ switch (field.problemId()) {
+ case NotFound :
+ flag = UndefinedField;
+ break;
+ case NotVisible :
+ flag = NotVisibleField;
+ break;
+ case Ambiguous :
+ flag = AmbiguousField;
+ break;
+ case NonStaticReferenceInStaticContext :
+ flag = NonStaticFieldFromStaticInvocation;
+ break;
+ case NonStaticReferenceInConstructorInvocation :
+ flag = InstanceFieldDuringConstructorInvocation;
+ break;
+ case InheritedNameHidesEnclosingName :
+ flag = InheritedFieldHidesEnclosingName;
+ break;
+ case NoError : // 0
+ default :
+ needImplementation(); // want to fail to see why we were here...
+ break;
+ }
+ this.handle(
+ flag,
+ new String[] { new String(field.readableName())},
+ nameRef.sourceStart,
+ nameRef.sourceEnd);
+ }
+
+ public void invalidField(
+ QualifiedNameReference nameRef,
+ FieldBinding field,
+ int index,
+ TypeBinding searchedType) {
+ //the resolution of the index-th field of qname failed
+ //qname.otherBindings[index] is the binding that has produced the error
+
+ //The different targetted errors should be :
+ //UndefinedField
+ //NotVisibleField
+ //AmbiguousField
+
+ if (searchedType.isBaseType()) {
+ this.handle(
+ NoFieldOnBaseType,
+ new String[] {
+ new String(searchedType.readableName()),
+ CharOperation.toString(CharOperation.subarray(nameRef.tokens, 0, index)),
+ new String(nameRef.tokens[index])},
+ nameRef.sourceStart(),
+ nameRef.sourceEnd());
+ return;
+ }
+
+ int flag = UndefinedField;
+ switch (field.problemId()) {
+ case NotFound :
+ flag = UndefinedField;
+ /* also need to check that the searchedType is the receiver type
+ if (searchedType.isHierarchyInconsistent())
+ severity = SecondaryError;
+ */
+ break;
+ case NotVisible :
+ flag = NotVisibleField;
+ break;
+ case Ambiguous :
+ flag = AmbiguousField;
+ break;
+ case NonStaticReferenceInStaticContext :
+ flag = NonStaticFieldFromStaticInvocation;
+ break;
+ case NonStaticReferenceInConstructorInvocation :
+ flag = InstanceFieldDuringConstructorInvocation;
+ break;
+ case InheritedNameHidesEnclosingName :
+ flag = InheritedFieldHidesEnclosingName;
+ break;
+ case NoError : // 0
+ default :
+ needImplementation(); // want to fail to see why we were here...
+ break;
+ }
+ this.handle(
+ flag,
+ new String[] {
+ CharOperation.toString(CharOperation.subarray(nameRef.tokens, 0, index + 1))},
+ nameRef.sourceStart,
+ nameRef.sourceEnd);
+ }
+
+ public void invalidMethod(MessageSend messageSend, MethodBinding method) {
+ // CODE should be UPDATED according to error coding in the different method binding errors
+ // The different targetted errors should be :
+ // UndefinedMethod
+ // NotVisibleMethod
+ // AmbiguousMethod
+ // InheritedNameHidesEnclosingName
+ // InstanceMethodDuringConstructorInvocation
+ // StaticMethodRequested
+
+ int flag = UndefinedMethod; //default...
+ switch (method.problemId()) {
+ case NotFound :
+ flag = UndefinedMethod;
+ break;
+ case NotVisible :
+ flag = NotVisibleMethod;
+ break;
+ case Ambiguous :
+ flag = AmbiguousMethod;
+ break;
+ case InheritedNameHidesEnclosingName :
+ flag = InheritedMethodHidesEnclosingName;
+ break;
+ case NonStaticReferenceInConstructorInvocation :
+ flag = InstanceMethodDuringConstructorInvocation;
+ break;
+ case NonStaticReferenceInStaticContext :
+ flag = StaticMethodRequested;
+ break;
+ case NoError : // 0
+ default :
+ needImplementation(); // want to fail to see why we were here...
+ break;
+ }
+
+ if (flag == UndefinedMethod) {
+ ProblemMethodBinding problemMethod = (ProblemMethodBinding) method;
+ if (problemMethod.closestMatch != null) {
+ this.handle(
+ ParameterMismatch,
+ new String[] {
+ new String(problemMethod.closestMatch.declaringClass.readableName()),
+ new String(problemMethod.closestMatch.selector),
+ parametersAsString(problemMethod.closestMatch),
+ parametersAsString(method)},
+ (int) (messageSend.nameSourcePosition >>> 32),
+ (int) messageSend.nameSourcePosition);
+ return;
+ }
+ }
+
+ this.handle(
+ flag,
+ new String[] {
+ new String(method.declaringClass.readableName()),
+ new String(method.selector),
+ parametersAsString(method)},
+ (int) (messageSend.nameSourcePosition >>> 32),
+ (int) messageSend.nameSourcePosition);
+ }
+
+ public void invalidNullToSynchronize(Expression expression) {
+ this.handle(
+ InvalidNullToSynchronized,
+ new String[0],
+ expression.sourceStart,
+ expression.sourceEnd);
+ }
+
+ public void invalidOperator(
+ BinaryExpression expression,
+ TypeBinding leftType,
+ TypeBinding rightType) {
+ this.handle(
+ InvalidOperator,
+ new String[] {
+ expression.operatorToString(),
+ new String(leftType.readableName())
+ + ", "
+ + new String(rightType.readableName())},
+ expression.sourceStart,
+ expression.sourceEnd);
+ }
+
+ public void invalidOperator(
+ CompoundAssignment assign,
+ TypeBinding leftType,
+ TypeBinding rightType) {
+ this.handle(
+ InvalidOperator,
+ new String[] {
+ assign.operatorToString(),
+ new String(leftType.readableName())
+ + ", "
+ + new String(rightType.readableName())},
+ assign.sourceStart,
+ assign.sourceEnd);
+ }
+
+ public void invalidOperator(UnaryExpression expression, TypeBinding type) {
+ this.handle(
+ InvalidOperator,
+ new String[] { expression.operatorToString(), new String(type.readableName())},
+ expression.sourceStart,
+ expression.sourceEnd);
+ }
+
+ public void invalidSuperclass(
+ SourceTypeBinding type,
+ TypeReference superclassRef,
+ ReferenceBinding expectedType) {
+ int problemId = expectedType.problemId();
+ switch (problemId) {
+ case NotFound : // 1
+ case NotVisible : // 2
+ case Ambiguous : // 3
+ case InternalNameProvided : // 4
+ case InheritedNameHidesEnclosingName : // 5
+ this.handle(
+ InvalidSuperclassBase + problemId,
+ new String[] {
+ new String(expectedType.readableName()),
+ new String(type.sourceName())},
+ superclassRef.sourceStart(),
+ superclassRef.sourceEnd());
+ break;
+ case NoError : // 0
+ default :
+ needImplementation(); // want to fail to see why we were here...
+ break;
+ }
+ }
+
+ public void invalidSuperinterface(
+ SourceTypeBinding type,
+ TypeReference superinterfaceRef,
+ ReferenceBinding expectedType) {
+ int problemId = expectedType.problemId();
+ switch (problemId) {
+ case NotFound : // 1
+ case NotVisible : // 2
+ case Ambiguous : // 3
+ case InternalNameProvided : // 4
+ case InheritedNameHidesEnclosingName : // 5
+ this.handle(
+ InvalidInterfaceBase + problemId,
+ new String[] {
+ new String(expectedType.readableName()),
+ new String(type.sourceName())},
+ superinterfaceRef.sourceStart(),
+ superinterfaceRef.sourceEnd());
+ break;
+ case NoError : // 0
+ default :
+ needImplementation(); // want to fail to see why we were here...
+ break;
+ }
+ }
+
+ public void invalidType(Expression expression, TypeBinding type) {
+ // CODE should be UPDATED according to error coding in the different type binding errors
+ //The different targetted errors should be :
+ //UndefinedType
+ //NotVisibleType
+ //AmbiguousType
+ //InternalTypeNameProvided
+ //InheritedTypeHidesEnclosingName
+
+ int flag = UndefinedType; // default
+ switch (type.problemId()) {
+ case NotFound :
+ flag = UndefinedType;
+ break;
+ case NotVisible :
+ flag = NotVisibleType;
+ break;
+ case Ambiguous :
+ flag = AmbiguousType;
+ break;
+ case InternalNameProvided :
+ flag = InternalTypeNameProvided;
+ break;
+ case InheritedNameHidesEnclosingName :
+ flag = InheritedTypeHidesEnclosingName;
+ break;
+ case NoError : // 0
+ default :
+ needImplementation(); // want to fail to see why we were here...
+ break;
+ }
+
+ this.handle(
+ flag,
+ new String[] { new String(type.readableName())},
+ expression.sourceStart,
+ expression.sourceEnd);
+ }
+
+ public void invalidTypeReference(Expression expression) {
+ this.handle(
+ InvalidTypeExpression,
+ new String[0],
+ expression.sourceStart,
+ expression.sourceEnd);
+ }
+
+ public void invalidTypeToSynchronize(Expression expression, TypeBinding type) {
+ this.handle(
+ InvalidTypeToSynchronized,
+ new String[] { new String(type.readableName())},
+ expression.sourceStart,
+ expression.sourceEnd);
+ }
+
+ public void invalidUnaryExpression(Expression expression) {
+ this.handle(
+ InvalidUnaryExpression,
+ new String[0],
+ expression.sourceStart,
+ expression.sourceEnd);
+ }
+
+ public void isClassPathCorrect(
+ char[][] wellKnownTypeName,
+ CompilationUnitDeclaration compUnitDecl) {
+ referenceContext = compUnitDecl;
+ this.handle(
+ IsClassPathCorrect,
+ new String[] { CharOperation.toString(wellKnownTypeName)},
+ AbortCompilation | Error,
+ compUnitDecl == null ? 0 : compUnitDecl.sourceStart,
+ compUnitDecl == null ? 1 : compUnitDecl.sourceEnd);
+ }
+
+ public void maskedExceptionHandler(
+ ReferenceBinding exceptionType,
+ AstNode location) {
+ this.handle(
+ MaskedCatch,
+ new String[0],
+ location.sourceStart(),
+ location.sourceEnd());
+ }
+
+ public void methodNeedingAbstractModifier(MethodDeclaration methodDecl) {
+ this.handle(
+ MethodRequiresBody,
+ new String[0],
+ methodDecl.sourceStart,
+ methodDecl.sourceEnd);
+ }
+
+ public void methodNeedingNoBody(MethodDeclaration methodDecl) {
+ this.handle(
+ ((methodDecl.modifiers & CompilerModifiers.AccNative) != 0)
+ ? BodyForNativeMethod
+ : BodyForAbstractMethod,
+ new String[0],
+ methodDecl.sourceStart,
+ methodDecl.sourceEnd);
+ }
+
+ public void methodWithConstructorName(MethodDeclaration methodDecl) {
+ this.handle(
+ MethodButWithConstructorName,
+ new String[0],
+ methodDecl.sourceStart,
+ methodDecl.sourceEnd);
+ }
+
+ public void missingEnclosingInstanceSpecification(
+ ReferenceBinding enclosingType,
+ AstNode location) {
+ boolean insideConstructorCall =
+ (location instanceof ExplicitConstructorCall)
+ && (((ExplicitConstructorCall) location).accessMode
+ == ExplicitConstructorCall.ImplicitSuper);
+
+ this.handle(
+ insideConstructorCall
+ ? MissingEnclosingInstanceForConstructorCall
+ : MissingEnclosingInstance,
+ new String[] { new String(enclosingType.readableName())},
+ location.sourceStart,
+ location.sourceEnd);
+ }
+
+ public void missingReturnType(AbstractMethodDeclaration methodDecl) {
+ this.handle(
+ MissingReturnType,
+ new String[0],
+ methodDecl.sourceStart,
+ methodDecl.sourceEnd);
+ }
+
+ public void mustDefineDimensionsOrInitializer(ArrayAllocationExpression expression) {
+ this.handle(
+ MustDefineEitherDimensionExpressionsOrInitializer,
+ new String[0],
+ expression.sourceStart,
+ expression.sourceEnd);
+ }
+
+ public void mustSpecifyPackage(CompilationUnitDeclaration compUnitDecl) {
+ this.handle(
+ MustSpecifyPackage,
+ new String[] { new String(compUnitDecl.getFileName())},
+ compUnitDecl.sourceStart,
+ compUnitDecl.sourceStart + 1);
+ }
+
+ public void mustUseAStaticMethod(
+ MessageSend messageSend,
+ MethodBinding method) {
+ this.handle(
+ StaticMethodRequested,
+ new String[] {
+ new String(method.declaringClass.readableName()),
+ new String(method.selector),
+ parametersAsString(method)},
+ messageSend.sourceStart,
+ messageSend.sourceEnd);
+ }
+
+ public void nativeMethodsCannotBeStrictfp(
+ ReferenceBinding type,
+ AbstractMethodDeclaration methodDecl) {
+ this.handle(
+ NativeMethodsCannotBeStrictfp,
+ new String[] { new String(type.sourceName()), new String(methodDecl.selector)},
+ methodDecl.sourceStart(),
+ methodDecl.sourceEnd());
+ }
+
+ public void needImplementation() {
+ this.abortDueToInternalError("Missing code implementation in the compiler");
+ }
+
+ public void needToEmulateFieldReadAccess(
+ FieldBinding field,
+ AstNode location) {
+ this.handle(
+ NeedToEmulateFieldReadAccess,
+ new String[] {
+ new String(field.declaringClass.readableName()),
+ new String(field.name)},
+ location.sourceStart,
+ location.sourceEnd);
+ }
+
+ public void needToEmulateFieldWriteAccess(
+ FieldBinding field,
+ AstNode location) {
+ this.handle(
+ NeedToEmulateFieldWriteAccess,
+ new String[] {
+ new String(field.declaringClass.readableName()),
+ new String(field.name)},
+ location.sourceStart,
+ location.sourceEnd);
+ }
+
+ public void needToEmulateMethodAccess(MethodBinding method, AstNode location) {
+
+ if (method.isConstructor())
+ this.handle(
+ NeedToEmulateConstructorAccess,
+ new String[] {
+ new String(method.declaringClass.readableName()),
+ parametersAsString(method)},
+ location.sourceStart,
+ location.sourceEnd);
+ else
+ this.handle(
+ NeedToEmulateMethodAccess,
+ new String[] {
+ new String(method.declaringClass.readableName()),
+ new String(method.selector),
+ parametersAsString(method)},
+ location.sourceStart,
+ location.sourceEnd);
+ }
+
+ public void nestedClassCannotDeclareInterface(TypeDeclaration typeDecl) {
+ this.handle(
+ CannotDefineInterfaceInLocalType,
+ new String[] { new String(typeDecl.name)},
+ typeDecl.sourceStart(),
+ typeDecl.sourceEnd());
+ }
+
+ public void noMoreAvailableSpaceForArgument(LocalDeclaration localDeclaration) {
+ this.handle(
+ TooManyArgumentSlots,
+ new String[] { localDeclaration.name()},
+ Abort | Error,
+ localDeclaration.sourceStart(),
+ localDeclaration.sourceEnd());
+ }
+
+ public void noMoreAvailableSpaceForLocal(LocalDeclaration localDeclaration) {
+ this.handle(
+ TooManyLocalVariableSlots,
+ new String[] { localDeclaration.name()},
+ Abort | Error,
+ localDeclaration.sourceStart(),
+ localDeclaration.sourceEnd());
+ }
+
+ public void notCompatibleTypesError(
+ EqualExpression expression,
+ TypeBinding leftType,
+ TypeBinding rightType) {
+ this.handle(
+ IncompatibleTypesInEqualityOperator,
+ new String[] {
+ new String(leftType.readableName()),
+ new String(rightType.readableName())},
+ expression.sourceStart,
+ expression.sourceEnd);
+ }
+
+ public void notCompatibleTypesError(
+ InstanceOfExpression expression,
+ TypeBinding leftType,
+ TypeBinding rightType) {
+ this.handle(
+ IncompatibleTypesInConditionalOperator,
+ new String[] {
+ new String(leftType.readableName()),
+ new String(rightType.readableName())},
+ expression.sourceStart,
+ expression.sourceEnd);
+ }
+
+ public void operatorOnlyValidOnNumericType(
+ CompoundAssignment assignment,
+ TypeBinding leftType,
+ TypeBinding rightType) {
+ this.handle(
+ TypeMismatch,
+ new String[] {
+ new String(leftType.readableName()),
+ new String(rightType.readableName())},
+ assignment.sourceStart,
+ assignment.sourceEnd);
+ }
+
+ public void overridesDeprecatedMethod(
+ MethodBinding currentMethod,
+ MethodBinding inheritedMethod) {
+ this.handle(
+ OverridingDeprecatedMethod,
+ new String[] { new String(inheritedMethod.declaringClass.readableName())},
+ currentMethod.sourceStart(),
+ currentMethod.sourceEnd());
+ }
+
+ public void overridesPackageDefaultMethod(
+ MethodBinding localMethod,
+ MethodBinding inheritedMethod) {
+ this.handle(
+ OverridingNonVisibleMethod,
+ new String[] {
+ new String(
+ CharOperation.concat(
+ localMethod.declaringClass.readableName(),
+ localMethod.readableName(),
+ '.')),
+ new String(inheritedMethod.declaringClass.readableName())},
+ localMethod.sourceStart(),
+ localMethod.sourceEnd());
+ }
+
+ public void packageCollidesWithType(CompilationUnitDeclaration compUnitDecl) {
+ this.handle(
+ PackageCollidesWithType,
+ new String[] { CharOperation.toString(compUnitDecl.currentPackage.tokens)},
+ compUnitDecl.currentPackage.sourceStart,
+ compUnitDecl.currentPackage.sourceEnd);
+ }
+
+ private String parametersAsString(MethodBinding method) {
+ TypeBinding[] params = method.parameters;
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0, length = params.length; i < length; i++) {
+ if (i != 0)
+ buffer.append(", ");
+ buffer.append(new String(params[i].readableName()));
+ }
+ return buffer.toString();
+ }
+
+ public void parseError(
+ int startPosition,
+ int endPosition,
+ char[] currentTokenSource,
+ String errorTokenName,
+ String[] possibleTokens,
+ ReferenceContext context,
+ CompilationResult compilationResult) {
+
+ if (possibleTokens.length == 0) { //no suggestion available
+ this.handle(ParsingErrorNoSuggestion, new String[] { errorTokenName },
+ // this is the current -invalid- token position
+ startPosition, endPosition, context, compilationResult);
+ return;
+ }
+
+ //build a list of probable right tokens
+ StringBuffer list = new StringBuffer(20);
+ for (int i = 0, max = possibleTokens.length; i < max; i++) {
+ if (i > 0)
+ list.append(", ");
+ list.append('"');
+ list.append(possibleTokens[i]);
+ list.append('"');
+ }
+
+ //extract the literal when it's a literal (fancier error message ...)
+ if ((errorTokenName.equals("IntegerLiteral"))
+ || (errorTokenName.equals("LongLiteral"))
+ || (errorTokenName.equals("FloatingPointLiteral"))
+ || (errorTokenName.equals("DoubleLiteral"))
+ || (errorTokenName.equals("StringLiteral"))
+ || (errorTokenName.equals("CharacterLiteral"))
+ || (errorTokenName.equals("Identifier"))) {
+ errorTokenName = new String(currentTokenSource);
+ }
+
+ this.handle(ParsingError, new String[] { errorTokenName, list.toString()},
+ // this is the current -invalid- token position
+ startPosition, endPosition, context, compilationResult);
+ }
+
+ public void publicClassMustMatchFileName(
+ CompilationUnitDeclaration compUnitDecl,
+ TypeDeclaration typeDecl) {
+ this.referenceContext = typeDecl;
+ // report the problem against the type not the entire compilation unit
+ this.handle(
+ PublicClassMustMatchFileName,
+ new String[] {
+ new String(compUnitDecl.getFileName()),
+ new String(typeDecl.name)},
+ typeDecl.sourceStart(),
+ typeDecl.sourceEnd(),
+ compUnitDecl.compilationResult);
+ }
+
+ /*
+ * Flag all constructors involved in a cycle, we know we have a cycle.
+ */
+ public void recursiveConstructorInvocation(TypeDeclaration typeDeclaration) {
+
+ // propagate the reference count, negative counts means leading to a super constructor invocation (directly or indirectly)
+ boolean hasChanged;
+ AbstractMethodDeclaration[] methods = typeDeclaration.methods;
+ int max = methods.length;
+ do {
+ hasChanged = false;
+ for (int i = 0; i < max; i++) {
+ if (methods[i].isConstructor()) {
+ ConstructorDeclaration constructor = (ConstructorDeclaration) methods[i];
+ if (constructor.referenceCount > 0) {
+ ConstructorDeclaration targetConstructor =
+ (ConstructorDeclaration) (typeDeclaration
+ .declarationOf(constructor.constructorCall.binding));
+ if ((targetConstructor == null) || (targetConstructor.referenceCount < 0)) {
+ hasChanged = true;
+ constructor.referenceCount = -1;
+ }
+ }
+ }
+ }
+ } while (hasChanged);
+
+ // all remaining constructors with a positive count are still involved in a cycle
+ for (int i = 0; i < max; i++) {
+ if (methods[i].isConstructor()) {
+ ConstructorDeclaration constructor = (ConstructorDeclaration) methods[i];
+ if (constructor.referenceCount > 0) {
+ this.referenceContext = constructor;
+ this.handle(
+ RecursiveConstructorInvocation,
+ new String[] {
+ new String(constructor.constructorCall.binding.declaringClass.readableName()),
+ parametersAsString(constructor.constructorCall.binding)},
+ constructor.constructorCall.sourceStart,
+ constructor.constructorCall.sourceEnd);
+ }
+ }
+ }
+ }
+
+ public void redefineArgument(Argument arg) {
+ this.handle(
+ RedefinedArgument,
+ new String[] { new String(arg.name)},
+ arg.sourceStart,
+ arg.sourceEnd);
+ }
+
+ public void redefineLocal(LocalDeclaration localDecl) {
+ this.handle(
+ RedefinedLocal,
+ new String[] { new String(localDecl.name)},
+ localDecl.sourceStart,
+ localDecl.sourceEnd);
+ }
+
+ public void referenceMustBeArrayTypeAt(
+ TypeBinding arrayType,
+ ArrayReference arrayRef) {
+ this.handle(
+ ArrayReferenceRequired,
+ new String[] { new String(arrayType.readableName())},
+ arrayRef.sourceStart,
+ arrayRef.sourceEnd);
+ }
+
+ public void returnTypeCannotBeVoidArray(
+ SourceTypeBinding type,
+ MethodDeclaration methodDecl) {
+ this.handle(
+ ReturnTypeCannotBeVoidArray,
+ new String[] { new String(methodDecl.selector)},
+ methodDecl.sourceStart(),
+ methodDecl.sourceEnd());
+ }
+
+ public void returnTypeProblem(
+ SourceTypeBinding type,
+ MethodDeclaration methodDecl,
+ TypeBinding expectedType) {
+ int problemId = expectedType.problemId();
+ switch (problemId) {
+ case NotFound : // 1
+ case NotVisible : // 2
+ case Ambiguous : // 3
+ case InternalNameProvided : // 4
+ case InheritedNameHidesEnclosingName : // 5
+ this.handle(
+ ReturnTypeProblemBase + problemId,
+ new String[] {
+ new String(methodDecl.selector),
+ new String(expectedType.readableName())},
+ methodDecl.returnType.sourceStart(),
+ methodDecl.returnType.sourceEnd());
+ break;
+ case NoError : // 0
+ default :
+ needImplementation(); // want to fail to see why we were here...
+ break;
+ }
+ }
+
+ public void scannerError(Parser parser, String errorTokenName) {
+ Scanner scanner = parser.scanner;
+
+ int flag = ParsingErrorNoSuggestion;
+ int startPos = scanner.startPosition;
+
+ //special treatment for recognized errors....
+ if (errorTokenName.equals(Scanner.END_OF_SOURCE))
+ flag = END_OF_SOURCE;
+ else
+ if (errorTokenName.equals(Scanner.INVALID_HEXA))
+ flag = INVALID_HEXA;
+ else
+ if (errorTokenName.equals(Scanner.INVALID_OCTAL))
+ flag = INVALID_OCTAL;
+ else
+ if (errorTokenName.equals(Scanner.INVALID_CHARACTER_CONSTANT))
+ flag = INVALID_CHARACTER_CONSTANT;
+ else
+ if (errorTokenName.equals(Scanner.INVALID_ESCAPE))
+ flag = INVALID_ESCAPE;
+ else
+ if (errorTokenName.equals(Scanner.INVALID_UNICODE_ESCAPE)) {
+ flag = INVALID_UNICODE_ESCAPE;
+ // better locate the error message
+ int checkPos = scanner.currentPosition - 1;
+ char[] source = scanner.source;
+ while (checkPos >= startPos) {
+ if (source[checkPos] == '\\')
+ break;
+ checkPos--;
+ }
+ startPos = checkPos;
+ } else
+ if (errorTokenName.equals(Scanner.INVALID_FLOAT))
+ flag = INVALID_FLOAT;
+ else
+ if (errorTokenName.equals(Scanner.UNTERMINATED_STRING))
+ flag = UNTERMINATED_STRING;
+ else
+ if (errorTokenName.equals(Scanner.UNTERMINATED_COMMENT))
+ flag = UNTERMINATED_COMMENT;
+ else
+ if (errorTokenName.equals(Scanner.INVALID_CHAR_IN_STRING))
+ flag = UNTERMINATED_STRING;
+
+ this
+ .handle(flag, flag == ParsingErrorNoSuggestion ? new String[] { errorTokenName }
+ : new String[0],
+ // this is the current -invalid- token position
+ startPos,
+ scanner.currentPosition - 1,
+ parser.compilationUnit.compilationResult);
+ }
+
+ public void shouldReturn(TypeBinding returnType, AstNode location) {
+ this.handle(
+ ShouldReturnValue,
+ new String[] { new String(returnType.readableName())},
+ location.sourceStart(),
+ location.sourceEnd());
+ }
+
+ public void signalNoImplicitStringConversionForCharArrayExpression(Expression expression) {
+ this.handle(NoImplicitStringConversionForCharArrayExpression, new String[] {
+ }, expression.sourceStart, expression.sourceEnd);
+ }
+
+ public void staticAndInstanceConflict(
+ MethodBinding currentMethod,
+ MethodBinding inheritedMethod) {
+ if (currentMethod.isStatic())
+ this.handle(
+ // This static method cannot hide the instance method from %1
+ // 8.4.6.4 - If a class inherits more than one method with the same signature a static (non-abstract) method cannot hide an instance method.
+ CannotHideAnInstanceMethodWithAStaticMethod,
+ new String[] { new String(inheritedMethod.declaringClass.readableName())},
+ currentMethod.sourceStart(),
+ currentMethod.sourceEnd());
+ else
+ this.handle(
+ // This instance method cannot override the static method from %1
+ // 8.4.6.4 - If a class inherits more than one method with the same signature an instance (non-abstract) method cannot override a static method.
+ CannotOverrideAStaticMethodWithAnInstanceMethod,
+ new String[] { new String(inheritedMethod.declaringClass.readableName())},
+ currentMethod.sourceStart(),
+ currentMethod.sourceEnd());
+ }
+
+ public void staticFieldAccessToNonStaticVariable(
+ FieldReference fieldRef,
+ FieldBinding field) {
+ this.handle(
+ NonStaticFieldFromStaticInvocation,
+ new String[] { new String(field.readableName())},
+ fieldRef.sourceStart,
+ fieldRef.sourceEnd);
+ }
+
+ public void staticFieldAccessToNonStaticVariable(
+ QualifiedNameReference nameRef,
+ FieldBinding field) {
+ int fieldIndex = nameRef.indexOfFirstFieldBinding - 1;
+ this.handle(
+ NonStaticFieldFromStaticInvocation,
+ new String[] { new String(field.readableName())},
+ nameRef.sourceStart,
+ nameRef.sourceEnd);
+ }
+
+ public void staticFieldAccessToNonStaticVariable(
+ SingleNameReference nameRef,
+ FieldBinding field) {
+ this.handle(
+ NonStaticFieldFromStaticInvocation,
+ new String[] { new String(field.readableName())},
+ nameRef.sourceStart,
+ nameRef.sourceEnd);
+ }
+
+ public void staticInheritedMethodConflicts(
+ SourceTypeBinding type,
+ MethodBinding concreteMethod,
+ MethodBinding[] abstractMethods) {
+ this.handle(
+ // The static method %1 conflicts with the abstract method in %2
+ // 8.4.6.4 - If a class inherits more than one method with the same signature it is an error for one to be static (non-abstract) and the other abstract.
+ StaticInheritedMethodConflicts,
+ new String[] {
+ new String(concreteMethod.readableName()),
+ new String(abstractMethods[0].declaringClass.readableName())},
+ type.sourceStart(),
+ type.sourceEnd());
+ }
+
+ public void stringConstantIsExceedingUtf8Limit(AstNode location) {
+ this.handle(
+ StringConstantIsExceedingUtf8Limit,
+ new String[0],
+ location.sourceStart(),
+ location.sourceEnd());
+ }
+
+ public void superclassMustBeAClass(
+ SourceTypeBinding type,
+ TypeReference superclassRef,
+ ReferenceBinding superType) {
+ this.handle(
+ SuperclassMustBeAClass,
+ new String[] {
+ new String(superType.readableName()),
+ new String(type.sourceName())},
+ superclassRef.sourceStart(),
+ superclassRef.sourceEnd());
+ }
+
+ public void superinterfaceMustBeAnInterface(
+ SourceTypeBinding type,
+ TypeDeclaration typeDecl,
+ ReferenceBinding superType) {
+ this.handle(
+ SuperInterfaceMustBeAnInterface,
+ new String[] {
+ new String(superType.readableName()),
+ new String(type.sourceName())},
+ typeDecl.sourceStart(),
+ typeDecl.sourceEnd());
+ }
+
+ public void typeCastError(
+ CastExpression expression,
+ TypeBinding leftType,
+ TypeBinding rightType) {
+ this.handle(
+ IllegalCast,
+ new String[] {
+ new String(rightType.readableName()),
+ new String(leftType.readableName())},
+ expression.sourceStart,
+ expression.sourceEnd);
+ }
+
+ public void typeCollidesWithPackage(
+ CompilationUnitDeclaration compUnitDecl,
+ TypeDeclaration typeDecl) {
+ this.referenceContext = typeDecl;
+ // report the problem against the type not the entire compilation unit
+ this.handle(
+ TypeCollidesWithPackage,
+ new String[] {
+ new String(compUnitDecl.getFileName()),
+ new String(typeDecl.name)},
+ typeDecl.sourceStart(),
+ typeDecl.sourceEnd(),
+ compUnitDecl.compilationResult);
+ }
+
+ public void typeMismatchError(
+ TypeBinding resultType,
+ TypeBinding expectedType,
+ AstNode location) {
+ this.handle(
+ TypeMismatch,
+ new String[] {
+ new String(resultType.readableName()),
+ new String(expectedType.readableName())},
+ location.sourceStart(),
+ location.sourceEnd());
+ }
+
+ public void typeMismatchErrorActualTypeExpectedType(
+ Expression expression,
+ TypeBinding constantType,
+ TypeBinding expectedType) {
+ this.handle(
+ TypeMismatch,
+ new String[] {
+ new String(constantType.readableName()),
+ new String(expectedType.readableName())},
+ expression.sourceStart,
+ expression.sourceEnd);
+ }
+
+ public void undefinedLabel(BranchStatement statement) {
+ this.handle(
+ UndefinedLabel,
+ new String[] { new String(statement.label)},
+ statement.sourceStart(),
+ statement.sourceEnd());
+ }
+
+ public void unexpectedStaticModifierForField(
+ SourceTypeBinding type,
+ FieldDeclaration fieldDecl) {
+ this.handle(
+ UnexpectedStaticModifierForField,
+ new String[] { fieldDecl.name()},
+ fieldDecl.sourceStart(),
+ fieldDecl.sourceEnd());
+ }
+
+ public void unexpectedStaticModifierForMethod(
+ ReferenceBinding type,
+ AbstractMethodDeclaration methodDecl) {
+ this.handle(
+ UnexpectedStaticModifierForMethod,
+ new String[] { new String(type.sourceName()), new String(methodDecl.selector)},
+ methodDecl.sourceStart(),
+ methodDecl.sourceEnd());
+ }
+
+ public void unhandledException(
+ TypeBinding exceptionType,
+ AstNode location,
+ Scope scope) {
+ this.handle(
+ scope.methodScope().isInsideInitializer()
+ ? CannotThrowCheckedExceptionInInitializer
+ : (location instanceof AnonymousLocalTypeDeclaration
+ ? NoExceptionInAnonymousTypeConstructor
+ : UnhandledException),
+ new String[] { new String(exceptionType.readableName())},
+ location.sourceStart(),
+ location.sourceEnd());
+ }
+
+ public void uninitializedBlankFinalField(
+ FieldBinding binding,
+ AstNode location) {
+ this.handle(
+ UninitializedBlankFinalField,
+ new String[] { new String(binding.readableName())},
+ location.sourceStart(),
+ location.sourceEnd());
+ }
+
+ public void uninitializedLocalVariable(
+ LocalVariableBinding binding,
+ AstNode location) {
+ this.handle(
+ UninitializedLocalVariable,
+ new String[] { new String(binding.readableName())},
+ location.sourceStart(),
+ location.sourceEnd());
+ }
+
+ public void unmatchedBracket(
+ int position,
+ ReferenceContext context,
+ CompilationResult compilationResult) {
+
+ this.handle(UnmatchedBracket, new String[] {
+ }, position, position, context, compilationResult);
+ }
+
+ public void unnecessaryEnclosingInstanceSpecification(
+ Expression expression,
+ ReferenceBinding targetType) {
+ this.handle(
+ IllegalEnclosingInstanceSpecification,
+ new String[] { new String(targetType.readableName())},
+ expression.sourceStart,
+ expression.sourceEnd);
+ }
+
+ public void unreachableCode(Statement statement) {
+ this.handle(
+ CodeCannotBeReached,
+ new String[0],
+ statement.sourceStart(),
+ statement.sourceEnd());
+ }
+
+ public void unreachableExceptionHandler(
+ ReferenceBinding exceptionType,
+ AstNode location) {
+ this.handle(
+ UnreachableCatch,
+ new String[0],
+ location.sourceStart(),
+ location.sourceEnd());
+ }
+
+ public void unresolvableReference(NameReference nameRef, Binding binding) {
+ int severity = Error;
+ /* also need to check that the searchedType is the receiver type
+ if (binding instanceof ProblemBinding) {
+ ProblemBinding problem = (ProblemBinding) binding;
+ if (problem.searchType != null && problem.searchType.isHierarchyInconsistent())
+ severity = SecondaryError;
+ }
+ */
+ this.handle(
+ UndefinedName,
+ new String[] { new String(binding.readableName())},
+ severity,
+ nameRef.sourceStart,
+ nameRef.sourceEnd);
+ }
+
+ public void unusedArgument(LocalDeclaration localDecl) {
+ this.handle(
+ ArgumentIsNeverUsed,
+ new String[] { localDecl.name()},
+ localDecl.sourceStart,
+ localDecl.sourceEnd);
+ }
+
+ public void unusedLocalVariable(LocalDeclaration localDecl) {
+ this.handle(
+ LocalVariableIsNeverUsed,
+ new String[] { localDecl.name()},
+ localDecl.sourceStart,
+ localDecl.sourceEnd);
+ }
+
+ public void variableTypeCannotBeVoid(AbstractVariableDeclaration varDecl) {
+ this.handle(
+ VariableTypeCannotBeVoid,
+ new String[] { new String(varDecl.name)},
+ varDecl.sourceStart(),
+ varDecl.sourceEnd());
+ }
+
+ public void variableTypeCannotBeVoidArray(AbstractVariableDeclaration varDecl) {
+ this.handle(
+ VariableTypeCannotBeVoidArray,
+ new String[] { new String(varDecl.name)},
+ varDecl.sourceStart(),
+ varDecl.sourceEnd());
+ }
+
+ public void visibilityConflict(
+ MethodBinding currentMethod,
+ MethodBinding inheritedMethod) {
+ this.handle(
+ // Cannot reduce the visibility of the inherited method from %1
+ // 8.4.6.3 - The access modifier of an hiding method must provide at least as much access as the hidden method.
+ // 8.4.6.3 - The access modifier of an overiding method must provide at least as much access as the overriden method.
+ MethodReducesVisibility,
+ new String[] { new String(inheritedMethod.declaringClass.readableName())},
+ currentMethod.sourceStart(),
+ currentMethod.sourceEnd());
+ }
+
+ public void wrongSequenceOfExceptionTypesError(
+ TryStatement statement,
+ int under,
+ int upper) {
+ //the two catch block under and upper are in an incorrect order.
+ //under should be define BEFORE upper in the source
+
+ //notice that the compiler could arrange automatically the
+ //correct order - and the only error would be on cycle ....
+ //on this one again , java is compiler-driven instead of being
+ //user-driven .....
+
+ TypeReference typeRef = statement.catchArguments[under].type;
+ this.handle(
+ UnreachableCatch,
+ new String[0],
+ typeRef.sourceStart,
+ typeRef.sourceEnd);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemSeverities.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemSeverities.java
new file mode 100644
index 0000000000..b59edb61c9
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemSeverities.java
@@ -0,0 +1,15 @@
+package org.eclipse.jdt.internal.compiler.problem;
+
+public interface ProblemSeverities {
+ final int Ignore = -1; // during handling only
+ final int Warning = 0; // during handling only
+
+ final int Error = 1;
+ // when bit is set: problem is error, if not it is a warning
+ final int AbortCompilation = 2;
+ final int AbortCompilationUnit = 4;
+ final int AbortType = 8;
+ final int AbortMethod = 16;
+ final int Abort = 30; // 2r11110
+ final int SecondaryError = 64;
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ShouldNotImplement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ShouldNotImplement.java
new file mode 100644
index 0000000000..d1ca40a827
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ShouldNotImplement.java
@@ -0,0 +1,11 @@
+package org.eclipse.jdt.internal.compiler.problem;
+
+public class ShouldNotImplement extends RuntimeException {
+ public ShouldNotImplement() {
+ }
+
+ public ShouldNotImplement(String message) {
+ super(message);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/UnresolvedCompilationError.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/UnresolvedCompilationError.java
new file mode 100644
index 0000000000..b960321464
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/UnresolvedCompilationError.java
@@ -0,0 +1,25 @@
+package org.eclipse.jdt.internal.compiler.problem;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+import java.util.*;
+
+/*
+ * Special unchecked exception type used
+ * to report a problem at runtime.
+ * Used to create the problem method.
+ *
+ */
+public class UnresolvedCompilationError extends Error {
+ /**
+ * Insert method's description here.
+ * @param s java.lang.String
+ */
+ public UnresolvedCompilationError(String s) {
+ super(s);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/CharOperation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/CharOperation.java
new file mode 100644
index 0000000000..43117f6d56
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/CharOperation.java
@@ -0,0 +1,641 @@
+package org.eclipse.jdt.internal.compiler.util;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
+
+public final class CharOperation {
+ public static final char[][] arrayConcat(char[][] first, char[][] second) {
+ if (first == null)
+ return second;
+ if (second == null)
+ return first;
+
+ int length1 = first.length;
+ int length2 = second.length;
+ char[][] result = new char[length1 + length2][];
+ /* if we do not trust System.arraycopy on our VM with char[][]'s
+ int i;
+ for (i = 0; i < length1; i++)
+ result[i] = first[i];
+ for (int j = 0; j < length2; j++)
+ result[i++] = second[j];
+ */
+ System.arraycopy(first, 0, result, 0, length1);
+ System.arraycopy(second, 0, result, length1, length2);
+ return result;
+ }
+
+ public static final char[][] arrayConcat(char[][] first, char[] second) {
+ if (second == null)
+ return first;
+ if (first == null)
+ return new char[][] { second };
+
+ int length = first.length;
+ char[][] result = new char[length + 1][];
+ /* if we do not trust System.arraycopy on our VM with char[][]'s
+ for (int i = 0; i < length; i++)
+ result[i] = first[i];
+ */
+ System.arraycopy(first, 0, result, 0, length);
+ result[length] = second;
+ return result;
+ }
+
+ public static final char[] concat(char[] first, char[] second) {
+ if (first == null)
+ return second;
+ if (second == null)
+ return first;
+
+ int length1 = first.length;
+ int length2 = second.length;
+ char[] result = new char[length1 + length2];
+ System.arraycopy(first, 0, result, 0, length1);
+ System.arraycopy(second, 0, result, length1, length2);
+ return result;
+ }
+
+ public static final char[] concat(char[] first, char[] second, char[] third) {
+ if (first == null)
+ return concat(second, third);
+ if (second == null)
+ return concat(first, third);
+ if (third == null)
+ return concat(first, second);
+
+ int length1 = first.length;
+ int length2 = second.length;
+ int length3 = third.length;
+ char[] result = new char[length1 + length2 + length3];
+ System.arraycopy(first, 0, result, 0, length1);
+ System.arraycopy(second, 0, result, length1, length2);
+ System.arraycopy(third, 0, result, length1 + length2, length3);
+ return result;
+ }
+
+ public static final char[] concat(
+ char[] first,
+ char[] second,
+ char separator) {
+ if (first == null)
+ return second;
+ if (second == null)
+ return first;
+
+ int length1 = first.length;
+ if (length1 == 0)
+ return second;
+ int length2 = second.length;
+ if (length2 == 0)
+ return first;
+
+ char[] result = new char[length1 + length2 + 1];
+ System.arraycopy(first, 0, result, 0, length1);
+ result[length1] = separator;
+ System.arraycopy(second, 0, result, length1 + 1, length2);
+ return result;
+ }
+
+ public static final char[] concat(
+ char[] first,
+ char sep1,
+ char[] second,
+ char sep2,
+ char[] third) {
+ if (first == null)
+ return concat(second, third, sep2);
+ if (second == null)
+ return concat(first, third, sep1);
+ if (third == null)
+ return concat(first, second, sep1);
+
+ int length1 = first.length;
+ int length2 = second.length;
+ int length3 = third.length;
+ char[] result = new char[length1 + length2 + length3 + 2];
+ System.arraycopy(first, 0, result, 0, length1);
+ result[length1] = sep1;
+ System.arraycopy(second, 0, result, length1 + 1, length2);
+ result[length1 + length2 + 1] = sep2;
+ System.arraycopy(third, 0, result, length1 + length2 + 2, length3);
+ return result;
+ }
+
+ public static final char[] concat(char prefix, char[] array, char suffix) {
+ if (array == null)
+ return new char[] { prefix, suffix };
+
+ int length = array.length;
+ char[] result = new char[length + 2];
+ result[0] = prefix;
+ System.arraycopy(array, 0, result, 1, length);
+ result[length + 1] = suffix;
+ return result;
+ }
+
+ public static final char[] concatWith(
+ char[][] array,
+ char[] name,
+ char separator) {
+ int nameLength = name == null ? 0 : name.length;
+ if (nameLength == 0)
+ return concatWith(array, separator);
+
+ int length = array == null ? 0 : array.length;
+ if (length == 0)
+ return name;
+
+ int size = nameLength;
+ int index = length;
+ while (--index >= 0)
+ if (array[index].length > 0)
+ size += array[index].length + 1;
+ char[] result = new char[size];
+ index = 0;
+ for (int i = 0; i < length; i++) {
+ int subLength = array[i].length;
+ if (subLength > 0) {
+ System.arraycopy(array[i], 0, result, index, subLength);
+ index += subLength;
+ result[index++] = separator;
+ }
+ }
+ System.arraycopy(name, 0, result, index, nameLength);
+ return result;
+ }
+
+ public static final char[] concatWith(char[][] array, char separator) {
+ int length = array == null ? 0 : array.length;
+ if (length == 0)
+ return TypeConstants.NoChar;
+
+ int size = length - 1;
+ int index = length;
+ while (--index >= 0) {
+ if (array[index].length == 0)
+ size--;
+ else
+ size += array[index].length;
+ }
+ if (size <= 0)
+ return TypeConstants.NoChar;
+ char[] result = new char[size];
+ index = length;
+ while (--index >= 0) {
+ length = array[index].length;
+ if (length > 0) {
+ System.arraycopy(array[index], 0, result, (size -= length), length);
+ if (--size >= 0)
+ result[size] = separator;
+ }
+ }
+ return result;
+ }
+
+ public static final boolean contains(char character, char[][] array) {
+ for (int i = array.length; --i >= 0;) {
+ char[] subarray = array[i];
+ for (int j = subarray.length; --j >= 0;)
+ if (subarray[j] == character)
+ return true;
+ }
+ return false;
+ }
+
+ public static final boolean contains(char character, char[] array) {
+ for (int i = array.length; --i >= 0;)
+ if (array[i] == character)
+ return true;
+ return false;
+ }
+
+ public static final char[][] deepCopy(char[][] toCopy) {
+ int toCopyLength = toCopy.length;
+ char[][] result = new char[toCopyLength][];
+ for (int i = 0; i < toCopyLength; i++) {
+ char[] toElement = toCopy[i];
+ int toElementLength = toElement.length;
+ char[] resultElement = new char[toElementLength];
+ System.arraycopy(toElement, 0, resultElement, 0, toElementLength);
+ result[i] = resultElement;
+ }
+ return result;
+ }
+
+ public static final boolean equals(char[][] first, char[][] second) {
+ if (first == second)
+ return true;
+ if (first == null || second == null)
+ return false;
+ if (first.length != second.length)
+ return false;
+
+ for (int i = first.length; --i >= 0;)
+ if (!equals(first[i], second[i]))
+ return false;
+ return true;
+ }
+
+ public static final boolean equals(
+ char[][] first,
+ char[][] second,
+ boolean isCaseSensitive) {
+
+ if (isCaseSensitive) {
+ return equals(first, second);
+ }
+ if (first == second)
+ return true;
+ if (first == null || second == null)
+ return false;
+ if (first.length != second.length)
+ return false;
+
+ for (int i = first.length; --i >= 0;)
+ if (!equals(first[i], second[i], false))
+ return false;
+ return true;
+ }
+
+ public static final boolean equals(char[] first, char[] second) {
+ if (first == second)
+ return true;
+ if (first == null || second == null)
+ return false;
+ if (first.length != second.length)
+ return false;
+
+ for (int i = first.length; --i >= 0;)
+ if (first[i] != second[i])
+ return false;
+ return true;
+ }
+
+ public static final boolean equals(
+ char[] first,
+ char[] second,
+ boolean isCaseSensitive) {
+
+ if (isCaseSensitive) {
+ return equals(first, second);
+ }
+ if (first == second)
+ return true;
+ if (first == null || second == null)
+ return false;
+ if (first.length != second.length)
+ return false;
+
+ for (int i = first.length; --i >= 0;)
+ if (Character.toLowerCase(first[i]) != Character.toLowerCase(second[i]))
+ return false;
+ return true;
+ }
+
+ public static final boolean fragmentEquals(
+ char[] fragment,
+ char[] name,
+ int startIndex,
+ boolean isCaseSensitive) {
+
+ int max = fragment.length;
+ if (name.length < max + startIndex)
+ return false;
+ if (isCaseSensitive) {
+ for (int i = max; --i >= 0;) // assumes the prefix is not larger than the name
+ if (fragment[i] != name[i + startIndex])
+ return false;
+ return true;
+ }
+ for (int i = max; --i >= 0;) // assumes the prefix is not larger than the name
+ if (Character.toLowerCase(fragment[i])
+ != Character.toLowerCase(name[i + startIndex]))
+ return false;
+ return true;
+ }
+
+ public static final int hashCode(char[] array) {
+ int hash = 0;
+ int offset = 0;
+ int length = array.length;
+ if (length < 16) {
+ for (int i = length; i > 0; i--)
+ hash = (hash * 37) + array[offset++];
+ } else {
+ // only sample some characters
+ int skip = length / 8;
+ for (int i = length; i > 0; i -= skip, offset += skip)
+ hash = (hash * 39) + array[offset];
+ }
+ return hash & 0x7FFFFFFF;
+ }
+
+ public static final int indexOf(char toBeFound, char[] array) {
+ for (int i = 0; i < array.length; i++)
+ if (toBeFound == array[i])
+ return i;
+ return -1;
+ }
+
+ public static final int indexOf(char toBeFound, char[] array, int start) {
+ for (int i = start; i < array.length; i++)
+ if (toBeFound == array[i])
+ return i;
+ return -1;
+ }
+
+ public static final int lastIndexOf(char toBeFound, char[] array) {
+ for (int i = array.length; --i >= 0;)
+ if (toBeFound == array[i])
+ return i;
+ return -1;
+ }
+
+ public static final int lastIndexOf(
+ char toBeFound,
+ char[] array,
+ int startIndex) {
+ for (int i = array.length; --i >= startIndex;)
+ if (toBeFound == array[i])
+ return i;
+ return -1;
+ }
+
+ public static final int lastIndexOf(
+ char toBeFound,
+ char[] array,
+ int startIndex,
+ int endIndex) {
+ for (int i = endIndex; --i >= startIndex;)
+ if (toBeFound == array[i])
+ return i;
+ return -1;
+ }
+
+ /**
+ * Answer the last portion of a name given a separator
+ * e.g. lastSegment("java.lang.Object".toCharArray(),'.') --> Object
+ */
+ final static public char[] lastSegment(char[] array, char separator) {
+ int pos = lastIndexOf(separator, array);
+ if (pos < 0)
+ return array;
+ return subarray(array, pos + 1, array.length);
+ }
+
+ /**
+ * char[] pattern matching, accepting wild-cards '*'.
+ *
+ * When not case sensitive, the pattern is assumed to already be lowercased, the
+ * name will be lowercased character per character as comparing.
+ */
+ public static final boolean match(
+ char[] pattern,
+ char[] name,
+ boolean isCaseSensitive) {
+
+ if (name == null)
+ return false; // null name cannot match
+ if (pattern == null)
+ return true; // null pattern is equivalent to '*'
+ int iPattern = 0, patternLength = pattern.length;
+ int iName = 0, nameLength = name.length;
+
+ /* check first segment */
+ char patternChar = 0;
+ while ((iPattern < patternLength)
+ && (patternChar = pattern[iPattern]) != '*') {
+ if (iName == nameLength)
+ return false;
+ if (patternChar
+ != (isCaseSensitive ? name[iName] : Character.toLowerCase(name[iName]))) {
+ return false;
+ }
+ iName++;
+ iPattern++;
+ }
+ /* check sequence of star+segment */
+ int segmentStart;
+ if (patternChar == '*') {
+ segmentStart = ++iPattern; // skip star
+ } else {
+ segmentStart = 0; // force iName check
+ }
+ int prefixStart = iName;
+ checkSegment : while (iName < nameLength && iPattern < patternLength) {
+ /* segment is ending */
+ if ((patternChar = pattern[iPattern]) == '*') {
+ segmentStart = ++iPattern; // skip start
+ prefixStart = iName;
+ continue checkSegment;
+ }
+ /* chech current name character */
+ if ((isCaseSensitive ? name[iName] : Character.toLowerCase(name[iName]))
+ != patternChar) {
+ iPattern = segmentStart; // mismatch - restart current segment
+ iName = ++prefixStart;
+ continue checkSegment;
+ }
+ iName++;
+ iPattern++;
+ }
+
+ return (segmentStart == patternLength)
+ || (iName == nameLength && iPattern == patternLength)
+ || (iPattern == patternLength - 1 && pattern[iPattern] == '*');
+ }
+
+ public static final int occurencesOf(char toBeFound, char[] array) {
+ int count = 0;
+ for (int i = 0; i < array.length; i++)
+ if (toBeFound == array[i])
+ count++;
+ return count;
+ }
+
+ public static final int occurencesOf(char toBeFound, char[] array, int start) {
+ int count = 0;
+ for (int i = start; i < array.length; i++)
+ if (toBeFound == array[i])
+ count++;
+ return count;
+ }
+
+ public static final boolean prefixEquals(char[] prefix, char[] name) {
+
+ int max = prefix.length;
+ if (name.length < max)
+ return false;
+ for (int i = max; --i >= 0;) // assumes the prefix is not larger than the name
+ if (prefix[i] != name[i])
+ return false;
+ return true;
+ }
+
+ public static final boolean prefixEquals(
+ char[] prefix,
+ char[] name,
+ boolean isCaseSensitive) {
+
+ int max = prefix.length;
+ if (name.length < max)
+ return false;
+ if (isCaseSensitive) {
+ for (int i = max; --i >= 0;) // assumes the prefix is not larger than the name
+ if (prefix[i] != name[i])
+ return false;
+ return true;
+ }
+
+ for (int i = max; --i >= 0;) // assumes the prefix is not larger than the name
+ if (Character.toLowerCase(prefix[i]) != Character.toLowerCase(name[i]))
+ return false;
+ return true;
+ }
+
+ public static final void replace(
+ char[] array,
+ char toBeReplaced,
+ char replacementChar) {
+ if (toBeReplaced != replacementChar) {
+ for (int i = 0, max = array.length; i < max; i++) {
+ if (array[i] == toBeReplaced)
+ array[i] = replacementChar;
+ }
+ }
+ }
+
+ public static final char[][] splitOn(char divider, char[] array) {
+ int length = array == null ? 0 : array.length;
+ if (length == 0)
+ return TypeConstants.NoCharChar;
+
+ int wordCount = 1;
+ for (int i = 0; i < length; i++)
+ if (array[i] == divider)
+ wordCount++;
+ char[][] split = new char[wordCount][];
+ int last = 0, currentWord = 0;
+ for (int i = 0; i < length; i++) {
+ if (array[i] == divider) {
+ split[currentWord] = new char[i - last];
+ System.arraycopy(array, last, split[currentWord++], 0, i - last);
+ last = i + 1;
+ }
+ }
+ split[currentWord] = new char[length - last];
+ System.arraycopy(array, last, split[currentWord], 0, length - last);
+ return split;
+ }
+
+ public static final char[][] splitOn(
+ char divider,
+ char[] array,
+ int start,
+ int end) {
+ int length = array == null ? 0 : array.length;
+ if (length == 0)
+ return TypeConstants.NoCharChar;
+
+ int wordCount = 1;
+ for (int i = start; i < end; i++)
+ if (array[i] == divider)
+ wordCount++;
+ char[][] split = new char[wordCount][];
+ int last = start, currentWord = 0;
+ for (int i = start; i < end; i++) {
+ if (array[i] == divider) {
+ split[currentWord] = new char[i - last];
+ System.arraycopy(array, last, split[currentWord++], 0, i - last);
+ last = i + 1;
+ }
+ }
+ split[currentWord] = new char[end - last + 1];
+ System.arraycopy(array, last, split[currentWord], 0, end - last + 1);
+ return split;
+ }
+
+ public static final boolean startsWith(char[] array, char[] toBeFound) {
+ int i = toBeFound.length;
+ if (i > array.length)
+ return false;
+ while (--i >= 0)
+ if (toBeFound[i] != array[i])
+ return false;
+ return true;
+ }
+
+ /*
+ * copies from array[start] through array[end - 1] (does not copy array[end])
+ */
+ public static final char[][] subarray(char[][] array, int start, int end) {
+ if (end == -1)
+ end = array.length;
+ if (start > end)
+ return null;
+ if (start < 0)
+ return null;
+ if (end > array.length)
+ return null;
+
+ char[][] result = new char[end - start][];
+ /* if we do not trust System.arraycopy on our VM with char[][]'s
+ for (int i = 0, s = start; s < end; i++, s++)
+ result[i] = array[s];
+ */
+ System.arraycopy(array, start, result, 0, end - start);
+ return result;
+ }
+
+ /*
+ * copies from array[start] through array[end - 1] (does not copy array[end])
+ */
+ public static final char[] subarray(char[] array, int start, int end) {
+ if (end == -1)
+ end = array.length;
+ if (start > end)
+ return null;
+ if (start < 0)
+ return null;
+ if (end > array.length)
+ return null;
+
+ char[] result = new char[end - start];
+ System.arraycopy(array, start, result, 0, end - start);
+ return result;
+ }
+
+ /**
+ * Answers the result of a char[] conversion to lowercase.
+ * NOTE: if no conversion was necessary, then answers back the argument one.
+ */
+ final static public char[] toLowerCase(char[] chars) {
+ if (chars == null)
+ return null;
+ int length = chars.length;
+ char[] lowerChars = null;
+ for (int i = 0; i < length; i++) {
+ char c = chars[i];
+ char lc = Character.toLowerCase(c);
+ if ((c != lc) || (lowerChars != null)) {
+ if (lowerChars == null) {
+ System.arraycopy(chars, 0, lowerChars = new char[length], 0, i);
+ }
+ lowerChars[i] = lc;
+ }
+ }
+ return lowerChars == null ? chars : lowerChars;
+ }
+
+ final static public String toString(char[][] array) {
+ char[] result = concatWith(array, '.');
+ if (result == null)
+ return "";
+ return new String(result);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfInt.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfInt.java
new file mode 100644
index 0000000000..2a8438c68f
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfInt.java
@@ -0,0 +1,89 @@
+package org.eclipse.jdt.internal.compiler.util;
+
+public final class HashtableOfInt {
+ // to avoid using Enumerations, walk the individual tables skipping nulls
+ public int[] keyTable;
+ public Object[] valueTable;
+
+ int elementSize; // number of elements in the table
+ int threshold;
+ public HashtableOfInt() {
+ this(13);
+ }
+
+ public HashtableOfInt(int size) {
+ this.elementSize = 0;
+ this.threshold = size; // size represents the expected number of elements
+ int extraRoom = (int) (size * 1.75f);
+ if (this.threshold == extraRoom)
+ extraRoom++;
+ this.keyTable = new int[extraRoom];
+ this.valueTable = new Object[extraRoom];
+ }
+
+ public boolean containsKey(int key) {
+ int index = key % valueTable.length;
+ int currentKey;
+ while ((currentKey = keyTable[index]) != 0) {
+ if (currentKey == key)
+ return true;
+ index = (index + 1) % keyTable.length;
+ }
+ return false;
+ }
+
+ public Object get(int key) {
+ int index = key % valueTable.length;
+ int currentKey;
+ while ((currentKey = keyTable[index]) != 0) {
+ if (currentKey == key)
+ return valueTable[index];
+ index = (index + 1) % keyTable.length;
+ }
+ return null;
+ }
+
+ public Object put(int key, Object value) {
+ int index = key % valueTable.length;
+ int currentKey;
+ while ((currentKey = keyTable[index]) != 0) {
+ if (currentKey == key)
+ return valueTable[index] = value;
+ index = (index + 1) % keyTable.length;
+ }
+ keyTable[index] = key;
+ valueTable[index] = value;
+
+ // assumes the threshold is never equal to the size of the table
+ if (++elementSize > threshold)
+ rehash();
+ return value;
+ }
+
+ private void rehash() {
+ HashtableOfInt newHashtable = new HashtableOfInt(elementSize * 2);
+ // double the number of expected elements
+ int currentKey;
+ for (int i = keyTable.length; --i >= 0;)
+ if ((currentKey = keyTable[i]) != 0)
+ newHashtable.put(currentKey, valueTable[i]);
+
+ this.keyTable = newHashtable.keyTable;
+ this.valueTable = newHashtable.valueTable;
+ this.threshold = newHashtable.threshold;
+ }
+
+ public int size() {
+ return elementSize;
+ }
+
+ public String toString() {
+ String s = "";
+ Object object;
+ for (int i = 0, length = valueTable.length; i < length; i++)
+ if ((object = valueTable[i]) != null)
+ s += keyTable[i] + " -> " + object.toString() + "\n";
+ return s;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfObject.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfObject.java
new file mode 100644
index 0000000000..d352c013d4
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfObject.java
@@ -0,0 +1,95 @@
+package org.eclipse.jdt.internal.compiler.util;
+
+public final class HashtableOfObject {
+ // to avoid using Enumerations, walk the individual tables skipping nulls
+ public char[] keyTable[];
+ public Object valueTable[];
+
+ int elementSize; // number of elements in the table
+ int threshold;
+ public HashtableOfObject() {
+ this(13);
+ }
+
+ public HashtableOfObject(int size) {
+ this.elementSize = 0;
+ this.threshold = size; // size represents the expected number of elements
+ int extraRoom = (int) (size * 1.75f);
+ if (this.threshold == extraRoom)
+ extraRoom++;
+ this.keyTable = new char[extraRoom][];
+ this.valueTable = new Object[extraRoom];
+ }
+
+ public boolean containsKey(char[] key) {
+ int index = CharOperation.hashCode(key) % valueTable.length;
+ int keyLength = key.length;
+ char[] currentKey;
+ while ((currentKey = keyTable[index]) != null) {
+ if (currentKey.length == keyLength
+ && CharOperation.prefixEquals(currentKey, key))
+ return true;
+ index = (index + 1) % keyTable.length;
+ }
+ return false;
+ }
+
+ public Object get(char[] key) {
+ int index = CharOperation.hashCode(key) % valueTable.length;
+ int keyLength = key.length;
+ char[] currentKey;
+ while ((currentKey = keyTable[index]) != null) {
+ if (currentKey.length == keyLength
+ && CharOperation.prefixEquals(currentKey, key))
+ return valueTable[index];
+ index = (index + 1) % keyTable.length;
+ }
+ return null;
+ }
+
+ public Object put(char[] key, Object value) {
+ int index = CharOperation.hashCode(key) % valueTable.length;
+ int keyLength = key.length;
+ char[] currentKey;
+ while ((currentKey = keyTable[index]) != null) {
+ if (currentKey.length == keyLength
+ && CharOperation.prefixEquals(currentKey, key))
+ return valueTable[index] = value;
+ index = (index + 1) % keyTable.length;
+ }
+ keyTable[index] = key;
+ valueTable[index] = value;
+
+ // assumes the threshold is never equal to the size of the table
+ if (++elementSize > threshold)
+ rehash();
+ return value;
+ }
+
+ private void rehash() {
+ HashtableOfObject newHashtable = new HashtableOfObject(elementSize * 2);
+ // double the number of expected elements
+ char[] currentKey;
+ for (int i = keyTable.length; --i >= 0;)
+ if ((currentKey = keyTable[i]) != null)
+ newHashtable.put(currentKey, valueTable[i]);
+
+ this.keyTable = newHashtable.keyTable;
+ this.valueTable = newHashtable.valueTable;
+ this.threshold = newHashtable.threshold;
+ }
+
+ public int size() {
+ return elementSize;
+ }
+
+ public String toString() {
+ String s = "";
+ Object object;
+ for (int i = 0, length = valueTable.length; i < length; i++)
+ if ((object = valueTable[i]) != null)
+ s += new String(keyTable[i]) + " -> " + object.toString() + "\n";
+ return s;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfPackage.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfPackage.java
new file mode 100644
index 0000000000..93db9f0f08
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfPackage.java
@@ -0,0 +1,101 @@
+package org.eclipse.jdt.internal.compiler.util;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
+
+public final class HashtableOfPackage {
+ // to avoid using Enumerations, walk the individual tables skipping nulls
+ public char[] keyTable[];
+ public PackageBinding valueTable[];
+
+ int elementSize; // number of elements in the table
+ int threshold;
+ public HashtableOfPackage() {
+ this(3); // usually not very large
+ }
+
+ public HashtableOfPackage(int size) {
+ this.elementSize = 0;
+ this.threshold = size; // size represents the expected number of elements
+ int extraRoom = (int) (size * 1.75f);
+ if (this.threshold == extraRoom)
+ extraRoom++;
+ this.keyTable = new char[extraRoom][];
+ this.valueTable = new PackageBinding[extraRoom];
+ }
+
+ public boolean containsKey(char[] key) {
+ int index = CharOperation.hashCode(key) % valueTable.length;
+ int keyLength = key.length;
+ char[] currentKey;
+ while ((currentKey = keyTable[index]) != null) {
+ if (currentKey.length == keyLength
+ && CharOperation.prefixEquals(currentKey, key))
+ return true;
+ index = (index + 1) % keyTable.length;
+ }
+ return false;
+ }
+
+ public PackageBinding get(char[] key) {
+ int index = CharOperation.hashCode(key) % valueTable.length;
+ int keyLength = key.length;
+ char[] currentKey;
+ while ((currentKey = keyTable[index]) != null) {
+ if (currentKey.length == keyLength
+ && CharOperation.prefixEquals(currentKey, key))
+ return valueTable[index];
+ index = (index + 1) % keyTable.length;
+ }
+ return null;
+ }
+
+ public PackageBinding put(char[] key, PackageBinding value) {
+ int index = CharOperation.hashCode(key) % valueTable.length;
+ int keyLength = key.length;
+ char[] currentKey;
+ while ((currentKey = keyTable[index]) != null) {
+ if (currentKey.length == keyLength
+ && CharOperation.prefixEquals(currentKey, key))
+ return valueTable[index] = value;
+ index = (index + 1) % keyTable.length;
+ }
+ keyTable[index] = key;
+ valueTable[index] = value;
+
+ // assumes the threshold is never equal to the size of the table
+ if (++elementSize > threshold)
+ rehash();
+ return value;
+ }
+
+ private void rehash() {
+ HashtableOfPackage newHashtable = new HashtableOfPackage(elementSize * 2);
+ // double the number of expected elements
+ char[] currentKey;
+ for (int i = keyTable.length; --i >= 0;)
+ if ((currentKey = keyTable[i]) != null)
+ newHashtable.put(currentKey, valueTable[i]);
+
+ this.keyTable = newHashtable.keyTable;
+ this.valueTable = newHashtable.valueTable;
+ this.threshold = newHashtable.threshold;
+ }
+
+ public int size() {
+ return elementSize;
+ }
+
+ public String toString() {
+ String s = "";
+ PackageBinding pkg;
+ for (int i = 0, length = valueTable.length; i < length; i++)
+ if ((pkg = valueTable[i]) != null)
+ s += pkg.toString() + "\n";
+ return s;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfType.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfType.java
new file mode 100644
index 0000000000..6cd432c466
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfType.java
@@ -0,0 +1,102 @@
+package org.eclipse.jdt.internal.compiler.util;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+
+public final class HashtableOfType {
+ // to avoid using Enumerations, walk the individual tables skipping nulls
+ public char[] keyTable[];
+ public ReferenceBinding valueTable[];
+
+ int elementSize; // number of elements in the table
+ int threshold;
+ public HashtableOfType() {
+ this(3);
+ }
+
+ public HashtableOfType(int size) {
+ this.elementSize = 0;
+ this.threshold = size; // size represents the expected number of elements
+ int extraRoom = (int) (size * 1.75f);
+ if (this.threshold == extraRoom)
+ extraRoom++;
+ this.keyTable = new char[extraRoom][];
+ this.valueTable = new ReferenceBinding[extraRoom];
+ }
+
+ public boolean containsKey(char[] key) {
+ int index = CharOperation.hashCode(key) % valueTable.length;
+ int keyLength = key.length;
+ char[] currentKey;
+ while ((currentKey = keyTable[index]) != null) {
+ if (currentKey.length == keyLength
+ && CharOperation.prefixEquals(currentKey, key))
+ return true;
+ index = (index + 1) % keyTable.length;
+ }
+ return false;
+ }
+
+ public ReferenceBinding get(char[] key) {
+ int index = CharOperation.hashCode(key) % valueTable.length;
+ int keyLength = key.length;
+ char[] currentKey;
+ while ((currentKey = keyTable[index]) != null) {
+ if (currentKey.length == keyLength
+ && CharOperation.prefixEquals(currentKey, key))
+ return valueTable[index];
+ index = (index + 1) % keyTable.length;
+ }
+ return null;
+ }
+
+ public ReferenceBinding put(char[] key, ReferenceBinding value) {
+ int index = CharOperation.hashCode(key) % valueTable.length;
+ int keyLength = key.length;
+ char[] currentKey;
+ while ((currentKey = keyTable[index]) != null) {
+ if (currentKey.length == keyLength
+ && CharOperation.prefixEquals(currentKey, key))
+ return valueTable[index] = value;
+ index = (index + 1) % keyTable.length;
+ }
+ keyTable[index] = key;
+ valueTable[index] = value;
+
+ // assumes the threshold is never equal to the size of the table
+ if (++elementSize > threshold)
+ rehash();
+ return value;
+ }
+
+ private void rehash() {
+ HashtableOfType newHashtable =
+ new HashtableOfType(elementSize < 100 ? 100 : elementSize * 2);
+ // double the number of expected elements
+ char[] currentKey;
+ for (int i = keyTable.length; --i >= 0;)
+ if ((currentKey = keyTable[i]) != null)
+ newHashtable.put(currentKey, valueTable[i]);
+
+ this.keyTable = newHashtable.keyTable;
+ this.valueTable = newHashtable.valueTable;
+ this.threshold = newHashtable.threshold;
+ }
+
+ public int size() {
+ return elementSize;
+ }
+
+ public String toString() {
+ String s = "";
+ ReferenceBinding type;
+ for (int i = 0, length = valueTable.length; i < length; i++)
+ if ((type = valueTable[i]) != null)
+ s += type.toString() + "\n";
+ return s;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/ObjectVector.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/ObjectVector.java
new file mode 100644
index 0000000000..8c5cd5d2bb
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/ObjectVector.java
@@ -0,0 +1,73 @@
+package org.eclipse.jdt.internal.compiler.util;
+
+public final class ObjectVector {
+ static int INITIAL_SIZE = 10;
+
+ public int size;
+ int maxSize;
+ Object[] elements;
+ public ObjectVector() {
+ maxSize = INITIAL_SIZE;
+ size = 0;
+ elements = new Object[maxSize];
+ }
+
+ public void add(Object newElement) {
+ if (size == maxSize) // knows that size starts <= maxSize
+ System.arraycopy(elements, 0, (elements = new Object[maxSize *= 2]), 0, size);
+ elements[size++] = newElement;
+ }
+
+ public void addAll(Object[] newElements) {
+ if (size + newElements.length >= maxSize) {
+ maxSize = size + newElements.length; // assume no more elements will be added
+ System.arraycopy(elements, 0, (elements = new Object[maxSize]), 0, size);
+ }
+ System.arraycopy(newElements, 0, elements, size, newElements.length);
+ size += newElements.length;
+ }
+
+ public boolean contains(Object element) {
+ for (int i = size; --i >= 0;)
+ if (element == elements[i])
+ return true;
+ return false;
+ }
+
+ public Object elementAt(int index) {
+ return elements[index];
+ }
+
+ public Object find(Object element) {
+ for (int i = size; --i >= 0;)
+ if (element == elements[i])
+ return elements[i];
+ return null;
+ }
+
+ public Object remove(Object element) {
+ // assumes only one occurrence of the element exists
+ for (int i = size; --i >= 0;)
+ if (element == elements[i]) {
+ // shift the remaining elements down one spot
+ System.arraycopy(elements, i + 1, elements, i, --size - i);
+ elements[size] = null;
+ return element;
+ }
+ return null;
+ }
+
+ public void removeAll() {
+ for (int i = size; --i >= 0;)
+ elements[i] = null;
+ size = 0;
+ }
+
+ public String toString() {
+ String s = "";
+ for (int i = 0; i < size; i++)
+ s += elements[i].toString() + "\n";
+ return s;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/SimpleNameVector.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/SimpleNameVector.java
new file mode 100644
index 0000000000..b844c598ac
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/SimpleNameVector.java
@@ -0,0 +1,67 @@
+package org.eclipse.jdt.internal.compiler.util;
+
+public final class SimpleNameVector {
+ static int INITIAL_SIZE = 10;
+
+ public int size;
+ int maxSize;
+ char[][] elements;
+ public SimpleNameVector() {
+ maxSize = INITIAL_SIZE;
+ size = 0;
+ elements = new char[maxSize][];
+ }
+
+ public void add(char[] newElement) {
+ if (size == maxSize) // knows that size starts <= maxSize
+ System.arraycopy(elements, 0, (elements = new char[maxSize *= 2][]), 0, size);
+ elements[size++] = newElement;
+ }
+
+ public void addAll(char[][] newElements) {
+ if (size + newElements.length >= maxSize) {
+ maxSize = size + newElements.length; // assume no more elements will be added
+ System.arraycopy(elements, 0, (elements = new char[maxSize][]), 0, size);
+ }
+ System.arraycopy(newElements, 0, elements, size, newElements.length);
+ size += newElements.length;
+ }
+
+ public boolean contains(char[] element) {
+ for (int i = size; --i >= 0;)
+ if (CharOperation.equals(element, elements[i]))
+ return true;
+ return false;
+ }
+
+ public char[] elementAt(int index) {
+ return elements[index];
+ }
+
+ public char[] remove(char[] element) {
+ // assumes only one occurrence of the element exists
+ for (int i = size; --i >= 0;)
+ if (element == elements[i]) {
+ // shift the remaining elements down one spot
+ System.arraycopy(elements, i + 1, elements, i, --size - i);
+ elements[size] = null;
+ return element;
+ }
+ return null;
+ }
+
+ public void removeAll() {
+ for (int i = size; --i >= 0;)
+ elements[i] = null;
+ size = 0;
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < size; i++) {
+ buffer.append(elements[i]).append("\n");
+ }
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetAllocationExpression.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetAllocationExpression.java
new file mode 100644
index 0000000000..dc333c1081
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetAllocationExpression.java
@@ -0,0 +1,181 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
+
+public class CodeSnippetAllocationExpression
+ extends AllocationExpression
+ implements ProblemReasons, EvaluationConstants {
+ EvaluationContext evaluationContext;
+ FieldBinding delegateThis;
+ /**
+ * CodeSnippetAllocationExpression constructor comment.
+ */
+ public CodeSnippetAllocationExpression(EvaluationContext evaluationContext) {
+ this.evaluationContext = evaluationContext;
+ }
+
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+
+ int pc = codeStream.position;
+ ReferenceBinding allocatedType = binding.declaringClass;
+
+ if (binding.canBeSeenBy(allocatedType, this, currentScope)) {
+ codeStream.new_(allocatedType);
+ if (valueRequired) {
+ codeStream.dup();
+ }
+ // better highlight for allocation: display the type individually
+ codeStream.recordPositionsFrom(pc, type);
+
+ // handling innerclass instance allocation
+ if (allocatedType.isNestedType()) {
+ codeStream.generateSyntheticArgumentValues(
+ currentScope,
+ allocatedType,
+ enclosingInstance(),
+ this);
+ }
+ // generate the arguments for constructor
+ if (arguments != null) {
+ for (int i = 0, count = arguments.length; i < count; i++) {
+ arguments[i].generateCode(currentScope, codeStream, true);
+ }
+ }
+ // invoke constructor
+ codeStream.invokespecial(binding);
+ } else {
+ // private emulation using reflect
+ ((CodeSnippetCodeStream) codeStream).generateEmulationForConstructor(
+ currentScope,
+ binding);
+ // generate arguments
+ if (arguments != null) {
+ int argsLength = arguments.length;
+ codeStream.generateInlinedValue(argsLength);
+ codeStream.newArray(
+ currentScope,
+ new ArrayBinding(currentScope.getType(TypeBinding.JAVA_LANG_OBJECT), 1));
+ codeStream.dup();
+ for (int i = 0; i < argsLength; i++) {
+ codeStream.generateInlinedValue(i);
+ arguments[i].generateCode(currentScope, codeStream, true);
+ if (binding.parameters[i].isBaseType()) {
+ codeStream.generateObjectWrapperForType(binding.parameters[i]);
+ }
+ codeStream.aastore();
+ if (i < argsLength - 1) {
+ codeStream.dup();
+ }
+ }
+ } else {
+ codeStream.generateInlinedValue(0);
+ codeStream.newArray(
+ currentScope,
+ new ArrayBinding(currentScope.getType(TypeBinding.JAVA_LANG_OBJECT), 1));
+ }
+ ((CodeSnippetCodeStream) codeStream)
+ .invokeJavaLangReflectConstructorNewInstance();
+ codeStream.checkcast(allocatedType);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ /* Inner emulation consists in either recording a dependency
+ * link only, or performing one level of propagation.
+ *
+ * Dependency mechanism is used whenever dealing with source target
+ * types, since by the time we reach them, we might not yet know their
+ * exact need.
+ */
+ public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
+ // not supported yet
+ }
+
+ public void manageSyntheticAccessIfNecessary(BlockScope currentScope) {
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ // Propagate the type checking to the arguments, and check if the constructor is defined.
+ constant = NotAConstant;
+ TypeBinding typeBinding = type.resolveType(scope);
+ // will check for null after args are resolved
+
+ // buffering the arguments' types
+ TypeBinding[] argumentTypes = NoParameters;
+ if (arguments != null) {
+ boolean argHasError = false;
+ int length = arguments.length;
+ argumentTypes = new TypeBinding[length];
+ for (int i = 0; i < length; i++)
+ if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null)
+ argHasError = true;
+ if (argHasError)
+ return null;
+ }
+ if (typeBinding == null)
+ return null;
+
+ if (!typeBinding.canBeInstantiated()) {
+ scope.problemReporter().cannotInstantiate(type, typeBinding);
+ return null;
+ }
+ ReferenceBinding allocatedType = (ReferenceBinding) typeBinding;
+ if (!(binding = scope.getConstructor(allocatedType, argumentTypes, this))
+ .isValidBinding()) {
+ if (binding instanceof ProblemMethodBinding
+ && ((ProblemMethodBinding) binding).problemId() == NotVisible) {
+ if (this.evaluationContext.declaringTypeName != null) {
+ delegateThis = scope.getField(scope.enclosingSourceType(), DELEGATE_THIS, this);
+ if (delegateThis == null) {
+ if (binding.declaringClass == null)
+ binding.declaringClass = allocatedType;
+ scope.problemReporter().invalidConstructor(this, binding);
+ return null;
+ }
+ } else {
+ if (binding.declaringClass == null)
+ binding.declaringClass = allocatedType;
+ scope.problemReporter().invalidConstructor(this, binding);
+ return null;
+ }
+ CodeSnippetScope localScope = new CodeSnippetScope(scope);
+ MethodBinding privateBinding =
+ localScope.getConstructor(
+ (ReferenceBinding) delegateThis.type,
+ argumentTypes,
+ this);
+ if (!privateBinding.isValidBinding()) {
+ if (binding.declaringClass == null)
+ binding.declaringClass = allocatedType;
+ scope.problemReporter().invalidConstructor(this, binding);
+ return null;
+ } else {
+ binding = privateBinding;
+ }
+ } else {
+ if (binding.declaringClass == null)
+ binding.declaringClass = allocatedType;
+ scope.problemReporter().invalidConstructor(this, binding);
+ return null;
+ }
+ }
+ if (isMethodUseDeprecated(binding, scope))
+ scope.problemReporter().deprecatedMethod(binding, this);
+
+ if (arguments != null)
+ for (int i = 0; i < arguments.length; i++)
+ arguments[i].implicitWidening(binding.parameters[i], argumentTypes[i]);
+ return allocatedType;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetClassFile.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetClassFile.java
new file mode 100644
index 0000000000..106198c730
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetClassFile.java
@@ -0,0 +1,245 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.ClassFile;
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.IProblem;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.FieldReference;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class CodeSnippetClassFile extends ClassFile {
+ /**
+ * CodeSnippetClassFile constructor comment.
+ * @param aType org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding
+ * @param enclosingClassFile org.eclipse.jdt.internal.compiler.ClassFile
+ * @param creatingProblemType boolean
+ */
+ public CodeSnippetClassFile(
+ org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding aType,
+ org.eclipse.jdt.internal.compiler.ClassFile enclosingClassFile,
+ boolean creatingProblemType) {
+ /**
+ * INTERNAL USE-ONLY
+ * This methods creates a new instance of the receiver.
+ *
+ * @param aType org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding
+ * @param enclosingClassFile org.eclipse.jdt.internal.compiler.codegen.ClassFile
+ * @param creatingProblemType <CODE>boolean</CODE>
+ */
+ referenceBinding = aType;
+ header = new byte[INITIAL_HEADER_SIZE];
+ // generate the magic numbers inside the header
+ header[headerOffset++] = (byte) (0xCAFEBABEL >> 24);
+ header[headerOffset++] = (byte) (0xCAFEBABEL >> 16);
+ header[headerOffset++] = (byte) (0xCAFEBABEL >> 8);
+ header[headerOffset++] = (byte) (0xCAFEBABEL >> 0);
+ if (((SourceTypeBinding) referenceBinding)
+ .scope
+ .environment()
+ .options
+ .targetJDK
+ == CompilerOptions.JDK1_2) {
+ // Compatible with JDK 1.2
+ header[headerOffset++] = 0;
+ // minorVersion = 0 means we just need to offset the current offset by 2
+ header[headerOffset++] = 0;
+ header[headerOffset++] = 0;
+ header[headerOffset++] = 46;
+ } else {
+ // Compatible with JDK 1.1
+ header[headerOffset++] = 0;
+ header[headerOffset++] = 3;
+ header[headerOffset++] = 0;
+ header[headerOffset++] = 45;
+ }
+ constantPoolOffset = headerOffset;
+ headerOffset += 2;
+ constantPool = new CodeSnippetConstantPool(this);
+ int accessFlags = aType.getAccessFlags() | AccSuper;
+ if (aType.isNestedType()) {
+ if (aType.isStatic()) {
+ // clear Acc_Static
+ accessFlags &= ~AccStatic;
+ }
+ if (aType.isPrivate()) {
+ // clear Acc_Private and Acc_Public
+ accessFlags &= ~(AccPrivate | AccPublic);
+ }
+ if (aType.isProtected()) {
+ // clear Acc_Protected and set Acc_Public
+ accessFlags &= ~AccProtected;
+ accessFlags |= AccPublic;
+ }
+ }
+ // clear Acc_Strictfp
+ accessFlags &= ~AccStrictfp;
+
+ this.enclosingClassFile = enclosingClassFile;
+ // innerclasses get their names computed at code gen time
+ if (aType.isLocalType()) {
+ ((LocalTypeBinding) aType).constantPoolName(
+ computeConstantPoolName((LocalTypeBinding) aType));
+ ReferenceBinding[] memberTypes = aType.memberTypes();
+ for (int i = 0, max = memberTypes.length; i < max; i++) {
+ ((LocalTypeBinding) memberTypes[i]).constantPoolName(
+ computeConstantPoolName((LocalTypeBinding) memberTypes[i]));
+ }
+ }
+ contents = new byte[INITIAL_CONTENTS_SIZE];
+ // now we continue to generate the bytes inside the contents array
+ contents[contentsOffset++] = (byte) (accessFlags >> 8);
+ contents[contentsOffset++] = (byte) accessFlags;
+ int classNameIndex = constantPool.literalIndex(aType);
+ contents[contentsOffset++] = (byte) (classNameIndex >> 8);
+ contents[contentsOffset++] = (byte) classNameIndex;
+ int superclassNameIndex;
+ if (aType.isInterface()) {
+ superclassNameIndex = constantPool.literalIndexForJavaLangObject();
+ } else {
+ superclassNameIndex =
+ (aType.superclass == null ? 0 : constantPool.literalIndex(aType.superclass));
+ }
+ contents[contentsOffset++] = (byte) (superclassNameIndex >> 8);
+ contents[contentsOffset++] = (byte) superclassNameIndex;
+ ReferenceBinding[] superInterfacesBinding = aType.superInterfaces();
+ int interfacesCount = superInterfacesBinding.length;
+ contents[contentsOffset++] = (byte) (interfacesCount >> 8);
+ contents[contentsOffset++] = (byte) interfacesCount;
+ if (superInterfacesBinding != null) {
+ for (int i = 0; i < interfacesCount; i++) {
+ int interfaceIndex = constantPool.literalIndex(superInterfacesBinding[i]);
+ contents[contentsOffset++] = (byte) (interfaceIndex >> 8);
+ contents[contentsOffset++] = (byte) interfaceIndex;
+ }
+ }
+ produceDebugAttributes =
+ ((SourceTypeBinding) referenceBinding)
+ .scope
+ .environment()
+ .options
+ .produceDebugAttributes;
+ innerClassesBindings = new ReferenceBinding[INNER_CLASSES_SIZE];
+ this.creatingProblemType = creatingProblemType;
+ codeStream = new CodeSnippetCodeStream(this);
+
+ // retrieve the enclosing one guaranteed to be the one matching the propagated flow info
+ // 1FF9ZBU: LFCOM:ALL - Local variable attributes busted (Sanity check)
+ ClassFile outermostClassFile = this.outerMostEnclosingClassFile();
+ if (this == outermostClassFile) {
+ codeStream.maxFieldCount = aType.scope.referenceType().maxFieldCount;
+ } else {
+ codeStream.maxFieldCount = outermostClassFile.codeStream.maxFieldCount;
+ }
+ }
+
+ /**
+ * INTERNAL USE-ONLY
+ * Request the creation of a ClassFile compatible representation of a problematic type
+ *
+ * @param typeDeclaration org.eclipse.jdt.internal.compiler.ast.TypeDeclaration
+ * @param unitResult org.eclipse.jdt.internal.compiler.CompilationUnitResult
+ */
+ public static void createProblemType(
+ TypeDeclaration typeDeclaration,
+ CompilationResult unitResult) {
+ SourceTypeBinding typeBinding = typeDeclaration.binding;
+ ClassFile classFile = new CodeSnippetClassFile(typeBinding, null, true);
+
+ // inner attributes
+ if (typeBinding.isMemberType())
+ classFile.recordEnclosingTypeAttributes(typeBinding);
+
+ // add its fields
+ FieldBinding[] fields = typeBinding.fields;
+ if ((fields != null) && (fields != NoFields)) {
+ for (int i = 0, max = fields.length; i < max; i++) {
+ if (fields[i].constant == null) {
+ FieldReference.getConstantFor(fields[i], false, null, 0);
+ }
+ }
+ classFile.addFieldInfos();
+ } else {
+ // we have to set the number of fields to be equals to 0
+ classFile.contents[classFile.contentsOffset++] = 0;
+ classFile.contents[classFile.contentsOffset++] = 0;
+ }
+ // leave some space for the methodCount
+ classFile.setForMethodInfos();
+ // add its user defined methods
+ MethodBinding[] methods = typeBinding.methods;
+ AbstractMethodDeclaration[] methodDeclarations = typeDeclaration.methods;
+ int maxMethodDecl = methodDeclarations == null ? 0 : methodDeclarations.length;
+ int problemsLength;
+ IProblem[] problems = unitResult.getProblems();
+ if (problems == null) {
+ problems = new IProblem[0];
+ }
+ IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
+ System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
+ if (methods != null) {
+ if (typeBinding.isInterface()) {
+ // we cannot create problem methods for an interface. So we have to generate a clinit
+ // which should contain all the problem
+ classFile.addProblemClinit(problemsCopy);
+ for (int i = 0, max = methods.length; i < max; i++) {
+ MethodBinding methodBinding;
+ if ((methodBinding = methods[i]) != null) {
+ // find the corresponding method declaration
+ for (int j = 0; j < maxMethodDecl; j++) {
+ if ((methodDeclarations[j] != null)
+ && (methodDeclarations[j].binding == methods[i])) {
+ if (!methodBinding.isConstructor()) {
+ classFile.addAbstractMethod(methodDeclarations[j], methodBinding);
+ }
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ for (int i = 0, max = methods.length; i < max; i++) {
+ MethodBinding methodBinding;
+ if ((methodBinding = methods[i]) != null) {
+ // find the corresponding method declaration
+ for (int j = 0; j < maxMethodDecl; j++) {
+ if ((methodDeclarations[j] != null)
+ && (methodDeclarations[j].binding == methods[i])) {
+ AbstractMethodDeclaration methodDecl;
+ if ((methodDecl = methodDeclarations[j]).isConstructor()) {
+ classFile.addProblemConstructor(methodDecl, methodBinding, problemsCopy);
+ } else {
+ classFile.addProblemMethod(methodDecl, methodBinding, problemsCopy);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ // add abstract methods
+ classFile.addDefaultAbstractMethods();
+ }
+ // propagate generation of (problem) member types
+ if (typeDeclaration.memberTypes != null) {
+ CompilationResult result =
+ typeDeclaration.scope.referenceCompilationUnit().compilationResult;
+ for (int i = 0, max = typeDeclaration.memberTypes.length; i < max; i++) {
+ TypeDeclaration memberType = typeDeclaration.memberTypes[i];
+ if (memberType.binding != null) {
+ classFile.recordNestedMemberAttribute(memberType.binding);
+ ClassFile.createProblemType(memberType, unitResult);
+ }
+ }
+ }
+ classFile.addAttributes();
+ unitResult.record(typeBinding.constantPoolName(), classFile);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetCodeStream.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetCodeStream.java
new file mode 100644
index 0000000000..cf65dd205b
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetCodeStream.java
@@ -0,0 +1,446 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.ast.Assignment;
+import org.eclipse.jdt.internal.compiler.ast.CompoundAssignment;
+import org.eclipse.jdt.internal.compiler.ast.Expression;
+import org.eclipse.jdt.internal.compiler.ast.IntLiteral;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class CodeSnippetCodeStream extends CodeStream {
+ /**
+ * CodeSnippetCodeStream constructor comment.
+ * @param classFile org.eclipse.jdt.internal.compiler.ClassFile
+ */
+ public CodeSnippetCodeStream(
+ org.eclipse.jdt.internal.compiler.ClassFile classFile) {
+ super(classFile);
+ }
+
+ protected void checkcast(int baseId) {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_checkcast;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_checkcast);
+ }
+ switch (baseId) {
+ case T_byte :
+ writeUnsignedShort(constantPool.literalIndexForJavaLangByte());
+ break;
+ case T_short :
+ writeUnsignedShort(constantPool.literalIndexForJavaLangShort());
+ break;
+ case T_char :
+ writeUnsignedShort(constantPool.literalIndexForJavaLangCharacter());
+ break;
+ case T_int :
+ writeUnsignedShort(constantPool.literalIndexForJavaLangInteger());
+ break;
+ case T_long :
+ writeUnsignedShort(constantPool.literalIndexForJavaLangLong());
+ break;
+ case T_float :
+ writeUnsignedShort(constantPool.literalIndexForJavaLangFloat());
+ break;
+ case T_double :
+ writeUnsignedShort(constantPool.literalIndexForJavaLangDouble());
+ break;
+ case T_boolean :
+ writeUnsignedShort(constantPool.literalIndexForJavaLangBoolean());
+ }
+ }
+
+ public void generateEmulatedAccessForMethod(
+ Scope scope,
+ MethodBinding methodBinding) {
+ CodeSnippetCodeStream localCodeStream = (CodeSnippetCodeStream) this;
+ localCodeStream.generateEmulationForMethod(scope, methodBinding);
+ localCodeStream.invokeJavaLangReflectMethodInvoke();
+ }
+
+ public void generateEmulatedReadAccessForField(FieldBinding fieldBinding) {
+ CodeSnippetCodeStream localCodeStream = (CodeSnippetCodeStream) this;
+ localCodeStream.generateEmulationForField(fieldBinding);
+ // swap the field with the receiver
+ this.swap();
+ localCodeStream.invokeJavaLangReflectFieldGetter(fieldBinding.type.id);
+ if (fieldBinding.type.isArrayType()) {
+ this.checkcast(fieldBinding.type);
+ }
+ }
+
+ public void generateEmulatedWriteAccessForField(FieldBinding fieldBinding) {
+ CodeSnippetCodeStream localCodeStream = (CodeSnippetCodeStream) this;
+ localCodeStream.invokeJavaLangReflectFieldSetter(fieldBinding.type.id);
+ }
+
+ public void generateEmulationForConstructor(
+ Scope scope,
+ MethodBinding methodBinding) {
+ // leave a java.lang.reflect.Field object on the stack
+ CodeSnippetCodeStream localCodeStream = (CodeSnippetCodeStream) this;
+ this.ldc(
+ String.valueOf(methodBinding.declaringClass.constantPoolName()).replace(
+ '/',
+ '.'));
+ this.invokeClassForName();
+ int paramLength = methodBinding.parameters.length;
+ this.generateInlinedValue(paramLength);
+ this.newArray(
+ scope,
+ new ArrayBinding(scope.getType(TypeBinding.JAVA_LANG_CLASS), 1));
+ if (paramLength > 0) {
+ this.dup();
+ for (int i = 0; i < paramLength; i++) {
+ this.generateInlinedValue(i);
+ TypeBinding parameter = methodBinding.parameters[i];
+ if (parameter.isBaseType()) {
+ this.getTYPE(parameter.id);
+ } else
+ if (parameter.isArrayType()) {
+ ArrayBinding array = (ArrayBinding) parameter;
+ if (array.leafComponentType.isBaseType()) {
+ this.getTYPE(array.leafComponentType.id);
+ } else {
+ this.ldc(
+ String.valueOf(array.leafComponentType.constantPoolName()).replace('/', '.'));
+ this.invokeClassForName();
+ }
+ int dimensions = array.dimensions;
+ this.generateInlinedValue(dimensions);
+ this.newarray(T_int);
+ this.invokeArrayNewInstance();
+ this.invokeObjectGetClass();
+ } else {
+ // parameter is a reference binding
+ this.ldc(
+ String.valueOf(methodBinding.declaringClass.constantPoolName()).replace(
+ '/',
+ '.'));
+ this.invokeClassForName();
+ }
+ this.aastore();
+ if (i < paramLength - 1) {
+ this.dup();
+ }
+ }
+ }
+ localCodeStream.invokeClassGetDeclaredConstructor();
+ this.dup();
+ this.iconst_1();
+ localCodeStream.invokeAccessibleObjectSetAccessible();
+ }
+
+ public void generateEmulationForField(FieldBinding fieldBinding) {
+ // leave a java.lang.reflect.Field object on the stack
+ CodeSnippetCodeStream localCodeStream = (CodeSnippetCodeStream) this;
+ this.ldc(
+ String.valueOf(fieldBinding.declaringClass.constantPoolName()).replace(
+ '/',
+ '.'));
+ this.invokeClassForName();
+ this.ldc(String.valueOf(fieldBinding.name));
+ localCodeStream.invokeClassGetDeclaredField();
+ this.dup();
+ this.iconst_1();
+ localCodeStream.invokeAccessibleObjectSetAccessible();
+ }
+
+ public void generateEmulationForMethod(
+ Scope scope,
+ MethodBinding methodBinding) {
+ // leave a java.lang.reflect.Field object on the stack
+ CodeSnippetCodeStream localCodeStream = (CodeSnippetCodeStream) this;
+ this.ldc(
+ String.valueOf(methodBinding.declaringClass.constantPoolName()).replace(
+ '/',
+ '.'));
+ this.invokeClassForName();
+ this.ldc(String.valueOf(methodBinding.selector));
+ int paramLength = methodBinding.parameters.length;
+ this.generateInlinedValue(paramLength);
+ this.newArray(
+ scope,
+ new ArrayBinding(scope.getType(TypeBinding.JAVA_LANG_CLASS), 1));
+ if (paramLength > 0) {
+ this.dup();
+ for (int i = 0; i < paramLength; i++) {
+ this.generateInlinedValue(i);
+ TypeBinding parameter = methodBinding.parameters[i];
+ if (parameter.isBaseType()) {
+ this.getTYPE(parameter.id);
+ } else
+ if (parameter.isArrayType()) {
+ ArrayBinding array = (ArrayBinding) parameter;
+ if (array.leafComponentType.isBaseType()) {
+ this.getTYPE(array.leafComponentType.id);
+ } else {
+ this.ldc(
+ String.valueOf(array.leafComponentType.constantPoolName()).replace('/', '.'));
+ this.invokeClassForName();
+ }
+ int dimensions = array.dimensions;
+ this.generateInlinedValue(dimensions);
+ this.newarray(T_int);
+ this.invokeArrayNewInstance();
+ this.invokeObjectGetClass();
+ } else {
+ // parameter is a reference binding
+ this.ldc(
+ String.valueOf(methodBinding.declaringClass.constantPoolName()).replace(
+ '/',
+ '.'));
+ this.invokeClassForName();
+ }
+ this.aastore();
+ if (i < paramLength - 1) {
+ this.dup();
+ }
+ }
+ }
+ localCodeStream.invokeClassGetDeclaredMethod();
+ this.dup();
+ this.iconst_1();
+ localCodeStream.invokeAccessibleObjectSetAccessible();
+ }
+
+ public void getBaseTypeValue(int baseTypeID) {
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokevirtual;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokevirtual);
+ }
+ switch (baseTypeID) {
+ case T_byte :
+ // invokevirtual: byteValue()
+ writeUnsignedShort(
+ ((CodeSnippetConstantPool) constantPool)
+ .literalIndexForJavaLangByteByteValue());
+ break;
+ case T_short :
+ // invokevirtual: shortValue()
+ writeUnsignedShort(
+ ((CodeSnippetConstantPool) constantPool)
+ .literalIndexForJavaLangShortShortValue());
+ break;
+ case T_char :
+ // invokevirtual: charValue()
+ writeUnsignedShort(
+ ((CodeSnippetConstantPool) constantPool)
+ .literalIndexForJavaLangCharacterCharValue());
+ break;
+ case T_int :
+ // invokevirtual: intValue()
+ writeUnsignedShort(
+ ((CodeSnippetConstantPool) constantPool)
+ .literalIndexForJavaLangIntegerIntValue());
+ break;
+ case T_long :
+ // invokevirtual: longValue()
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ writeUnsignedShort(
+ ((CodeSnippetConstantPool) constantPool)
+ .literalIndexForJavaLangLongLongValue());
+ break;
+ case T_float :
+ // invokevirtual: floatValue()
+ writeUnsignedShort(
+ ((CodeSnippetConstantPool) constantPool)
+ .literalIndexForJavaLangFloatFloatValue());
+ break;
+ case T_double :
+ // invokevirtual: doubleValue()
+ stackDepth++;
+ if (stackDepth > stackMax)
+ stackMax = stackDepth;
+ writeUnsignedShort(
+ ((CodeSnippetConstantPool) constantPool)
+ .literalIndexForJavaLangDoubleDoubleValue());
+ break;
+ case T_boolean :
+ // invokevirtual: booleanValue()
+ writeUnsignedShort(
+ ((CodeSnippetConstantPool) constantPool)
+ .literalIndexForJavaLangBooleanBooleanValue());
+ }
+ }
+
+ protected void invokeAccessibleObjectSetAccessible() {
+ // invokevirtual: java.lang.reflect.AccessibleObject.setAccessible(Z)V;
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokevirtual;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokevirtual);
+ }
+ writeUnsignedShort(
+ ((CodeSnippetConstantPool) constantPool)
+ .literalIndexForJavaLangReflectAccessibleObjectSetAccessible());
+ stackDepth -= 2;
+ }
+
+ protected void invokeArrayNewInstance() {
+ // invokestatic: java.lang.reflect.Array.newInstance(Ljava.lang.Class;int[])Ljava.lang.reflect.Array;
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokestatic;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokestatic);
+ }
+ writeUnsignedShort(
+ ((CodeSnippetConstantPool) constantPool)
+ .literalIndexForJavaLangReflectArrayNewInstance());
+ stackDepth--;
+ }
+
+ protected void invokeClassGetDeclaredConstructor() {
+ // invokevirtual: java.lang.Class getDeclaredConstructor([Ljava.lang.Class)Ljava.lang.reflect.Constructor;
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokevirtual;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokevirtual);
+ }
+ writeUnsignedShort(
+ ((CodeSnippetConstantPool) constantPool)
+ .literalIndexForJavaLangClassGetDeclaredConstructor());
+ stackDepth--;
+ }
+
+ protected void invokeClassGetDeclaredField() {
+ // invokevirtual: java.lang.Class.getDeclaredField(Ljava.lang.String)Ljava.lang.reflect.Field;
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokevirtual;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokevirtual);
+ }
+ writeUnsignedShort(
+ ((CodeSnippetConstantPool) constantPool)
+ .literalIndexForJavaLangClassGetDeclaredField());
+ stackDepth--;
+ }
+
+ protected void invokeClassGetDeclaredMethod() {
+ // invokevirtual: java.lang.Class getDeclaredMethod(Ljava.lang.String, [Ljava.lang.Class)Ljava.lang.reflect.Method;
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokevirtual;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokevirtual);
+ }
+ writeUnsignedShort(
+ ((CodeSnippetConstantPool) constantPool)
+ .literalIndexForJavaLangClassGetDeclaredMethod());
+ stackDepth -= 2;
+ }
+
+ protected void invokeJavaLangReflectConstructorNewInstance() {
+ // invokevirtual: java.lang.reflect.Constructor.newInstance([Ljava.lang.Object;)Ljava.lang.Object;
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokevirtual;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokevirtual);
+ }
+ writeUnsignedShort(
+ ((CodeSnippetConstantPool) constantPool)
+ .literalIndexForJavaLangReflectConstructorNewInstance());
+ stackDepth--;
+ }
+
+ protected void invokeJavaLangReflectFieldGetter(int typeID) {
+ countLabels = 0;
+ int usedTypeID;
+ if (typeID == T_null)
+ usedTypeID = T_Object;
+ else
+ usedTypeID = typeID;
+ // invokevirtual
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokevirtual;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokevirtual);
+ }
+ writeUnsignedShort(
+ (
+ (CodeSnippetConstantPool) constantPool).literalIndexJavaLangReflectFieldGetter(
+ typeID));
+ if ((usedTypeID != T_long) && (usedTypeID != T_double)) {
+ stackDepth--;
+ }
+ }
+
+ protected void invokeJavaLangReflectFieldSetter(int typeID) {
+ countLabels = 0;
+ int usedTypeID;
+ if (typeID == T_null)
+ usedTypeID = T_Object;
+ else
+ usedTypeID = typeID;
+ // invokevirtual
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokevirtual;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokevirtual);
+ }
+ writeUnsignedShort(
+ (
+ (CodeSnippetConstantPool) constantPool).literalIndexJavaLangReflectFieldSetter(
+ typeID));
+ if ((usedTypeID != T_long) && (usedTypeID != T_double)) {
+ stackDepth -= 3;
+ } else {
+ stackDepth -= 4;
+ }
+ }
+
+ protected void invokeJavaLangReflectMethodInvoke() {
+ // invokevirtual: java.lang.reflect.Method.invoke(Ljava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokevirtual;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokevirtual);
+ }
+ writeUnsignedShort(
+ ((CodeSnippetConstantPool) constantPool)
+ .literalIndexForJavaLangReflectMethodInvoke());
+ stackDepth -= 2;
+ }
+
+ protected void invokeObjectGetClass() {
+ // invokevirtual: java.lang.Object.getClass()Ljava.lang.Class;
+ countLabels = 0;
+ try {
+ position++;
+ bCodeStream[classFileOffset++] = OPC_invokevirtual;
+ } catch (IndexOutOfBoundsException e) {
+ resizeByteArray(OPC_invokevirtual);
+ }
+ writeUnsignedShort(
+ ((CodeSnippetConstantPool) constantPool)
+ .literalIndexForJavaLangObjectGetClass());
+ }
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetCompiler.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetCompiler.java
new file mode 100644
index 0000000000..4f22535e30
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetCompiler.java
@@ -0,0 +1,38 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
+
+/**
+ * A compiler that compiles code snippets.
+ */
+public class CodeSnippetCompiler extends Compiler {
+ /**
+ * Creates a new code snippet compiler initialized with a code snippet parser.
+ */
+ public CodeSnippetCompiler(
+ INameEnvironment environment,
+ IErrorHandlingPolicy policy,
+ ConfigurableOption[] settings,
+ ICompilerRequestor requestor,
+ IProblemFactory problemFactory,
+ EvaluationContext evaluationContext,
+ int codeSnippetStart,
+ int codeSnippetEnd) {
+ super(environment, policy, settings, requestor, problemFactory);
+ this.parser =
+ new CodeSnippetParser(
+ problemReporter,
+ evaluationContext,
+ this.options.parseLiteralExpressionsAsConstants,
+ codeSnippetStart,
+ codeSnippetEnd);
+ this.parseThreshold = 1; // fully parse only the code snippet compilation unit
+ }
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetConstantPool.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetConstantPool.java
new file mode 100644
index 0000000000..0003f376fc
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetConstantPool.java
@@ -0,0 +1,2071 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+/**
+ * This constant pool is used to manage well known methods and fields related specifically to the
+ * code snippet code generation (java.lang.reflect classes).
+ */
+public class CodeSnippetConstantPool
+ extends ConstantPool
+ implements TypeConstants {
+
+ // predefined type constant names
+ final static char[][] JAVA_LANG_REFLECT_FIELD =
+ new char[][] { JAVA, LANG, REFLECT, "Field".toCharArray()};
+ final static char[][] JAVA_LANG_REFLECT_ACCESSIBLEOBJECT =
+ new char[][] { JAVA, LANG, REFLECT, "AccessibleObject".toCharArray()};
+ final static char[][] JAVA_LANG_REFLECT_METHOD =
+ new char[][] { JAVA, LANG, REFLECT, "Method".toCharArray()};
+ final static char[][] JAVA_LANG_REFLECT_ARRAY =
+ new char[][] { JAVA, LANG, REFLECT, "Array".toCharArray()};
+
+ // predefined methods constant names
+ final static char[] GETDECLAREDFIELD_NAME = "getDeclaredField".toCharArray();
+ final static char[] GETDECLAREDFIELD_SIGNATURE =
+ "(Ljava/lang/String;)Ljava/lang/reflect/Field;".toCharArray();
+ final static char[] SETACCESSIBLE_NAME = "setAccessible".toCharArray();
+ final static char[] SETACCESSIBLE_SIGNATURE = "(Z)V".toCharArray();
+ final static char[] JAVALANGREFLECTFIELD_CONSTANTPOOLNAME =
+ "java/lang/reflect/Field".toCharArray();
+ final static char[] JAVALANGREFLECTACCESSIBLEOBJECT_CONSTANTPOOLNAME =
+ "java/lang/reflect/AccessibleObject".toCharArray();
+ final static char[] JAVALANGREFLECTARRAY_CONSTANTPOOLNAME =
+ "java/lang/reflect/Array".toCharArray();
+ final static char[] JAVALANGREFLECTMETHOD_CONSTANTPOOLNAME =
+ "java/lang/reflect/Method".toCharArray();
+ final static char[] GET_INT_METHOD_NAME = "getInt".toCharArray();
+ final static char[] GET_LONG_METHOD_NAME = "getLong".toCharArray();
+ final static char[] GET_DOUBLE_METHOD_NAME = "getDouble".toCharArray();
+ final static char[] GET_FLOAT_METHOD_NAME = "getFloat".toCharArray();
+ final static char[] GET_BYTE_METHOD_NAME = "getByte".toCharArray();
+ final static char[] GET_CHAR_METHOD_NAME = "getChar".toCharArray();
+ final static char[] GET_BOOLEAN_METHOD_NAME = "getBoolean".toCharArray();
+ final static char[] GET_OBJECT_METHOD_NAME = "get".toCharArray();
+ final static char[] GET_SHORT_METHOD_NAME = "getShort".toCharArray();
+ final static char[] ARRAY_NEWINSTANCE_NAME = "newInstance".toCharArray();
+ final static char[] GET_INT_METHOD_SIGNATURE =
+ "(Ljava/lang/Object;)I".toCharArray();
+ final static char[] GET_LONG_METHOD_SIGNATURE =
+ "(Ljava/lang/Object;)J".toCharArray();
+ final static char[] GET_DOUBLE_METHOD_SIGNATURE =
+ "(Ljava/lang/Object;)D".toCharArray();
+ final static char[] GET_FLOAT_METHOD_SIGNATURE =
+ "(Ljava/lang/Object;)F".toCharArray();
+ final static char[] GET_BYTE_METHOD_SIGNATURE =
+ "(Ljava/lang/Object;)B".toCharArray();
+ final static char[] GET_CHAR_METHOD_SIGNATURE =
+ "(Ljava/lang/Object;)C".toCharArray();
+ final static char[] GET_BOOLEAN_METHOD_SIGNATURE =
+ "(Ljava/lang/Object;)Z".toCharArray();
+ final static char[] GET_OBJECT_METHOD_SIGNATURE =
+ "(Ljava/lang/Object;)Ljava/lang/Object;".toCharArray();
+ final static char[] GET_SHORT_METHOD_SIGNATURE =
+ "(Ljava/lang/Object;)S".toCharArray();
+ final static char[] SET_INT_METHOD_NAME = "setInt".toCharArray();
+ final static char[] SET_LONG_METHOD_NAME = "setLong".toCharArray();
+ final static char[] SET_DOUBLE_METHOD_NAME = "setDouble".toCharArray();
+ final static char[] SET_FLOAT_METHOD_NAME = "setFloat".toCharArray();
+ final static char[] SET_BYTE_METHOD_NAME = "setByte".toCharArray();
+ final static char[] SET_CHAR_METHOD_NAME = "setChar".toCharArray();
+ final static char[] SET_BOOLEAN_METHOD_NAME = "setBoolean".toCharArray();
+ final static char[] SET_OBJECT_METHOD_NAME = "set".toCharArray();
+ final static char[] SET_SHORT_METHOD_NAME = "setShort".toCharArray();
+ final static char[] GETCLASS_OBJECT_METHOD_NAME = "getClass".toCharArray();
+ final static char[] SET_INT_METHOD_SIGNATURE =
+ "(Ljava/lang/Object;I)V".toCharArray();
+ final static char[] SET_LONG_METHOD_SIGNATURE =
+ "(Ljava/lang/Object;J)V".toCharArray();
+ final static char[] SET_DOUBLE_METHOD_SIGNATURE =
+ "(Ljava/lang/Object;D)V".toCharArray();
+ final static char[] SET_FLOAT_METHOD_SIGNATURE =
+ "(Ljava/lang/Object;F)V".toCharArray();
+ final static char[] SET_BYTE_METHOD_SIGNATURE =
+ "(Ljava/lang/Object;B)V".toCharArray();
+ final static char[] SET_CHAR_METHOD_SIGNATURE =
+ "(Ljava/lang/Object;C)V".toCharArray();
+ final static char[] SET_BOOLEAN_METHOD_SIGNATURE =
+ "(Ljava/lang/Object;Z)V".toCharArray();
+ final static char[] SET_OBJECT_METHOD_SIGNATURE =
+ "(Ljava/lang/Object;Ljava/lang/Object;)V".toCharArray();
+ final static char[] SET_SHORT_METHOD_SIGNATURE =
+ "(Ljava/lang/Object;S)V".toCharArray();
+ final static char[] GETDECLAREDMETHOD_NAME = "getDeclaredMethod".toCharArray();
+ final static char[] GETDECLAREDMETHOD_SIGNATURE =
+ "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;"
+ .toCharArray();
+ final static char[] ARRAY_NEWINSTANCE_SIGNATURE =
+ "(Ljava/lang/Class;[I)Ljava/lang/Object;".toCharArray();
+ final static char[] GETCLASS_OBJECT_METHOD_SIGNATURE =
+ "()Ljava/lang/Class;".toCharArray();
+ final static char[] INVOKE_METHOD_METHOD_NAME = "invoke".toCharArray();
+ final static char[] INVOKE_METHOD_METHOD_SIGNATURE =
+ "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;".toCharArray();
+ final static char[] BYTEVALUE_BYTE_METHOD_NAME = "byteValue".toCharArray();
+ final static char[] BYTEVALUE_BYTE_METHOD_SIGNATURE = "()B".toCharArray();
+ final static char[] SHORTVALUE_SHORT_METHOD_NAME = "shortValue".toCharArray();
+ final static char[] DOUBLEVALUE_DOUBLE_METHOD_NAME =
+ "doubleValue".toCharArray();
+ final static char[] FLOATVALUE_FLOAT_METHOD_NAME = "floatValue".toCharArray();
+ final static char[] INTVALUE_INTEGER_METHOD_NAME = "intValue".toCharArray();
+ final static char[] CHARVALUE_CHARACTER_METHOD_NAME = "charValue".toCharArray();
+ final static char[] BOOLEANVALUE_BOOLEAN_METHOD_NAME =
+ "booleanValue".toCharArray();
+ final static char[] LONGVALUE_LONG_METHOD_NAME = "longValue".toCharArray();
+ final static char[] SHORTVALUE_SHORT_METHOD_SIGNATURE = "()S".toCharArray();
+ final static char[] DOUBLEVALUE_DOUBLE_METHOD_SIGNATURE = "()D".toCharArray();
+ final static char[] FLOATVALUE_FLOAT_METHOD_SIGNATURE = "()F".toCharArray();
+ final static char[] INTVALUE_INTEGER_METHOD_SIGNATURE = "()I".toCharArray();
+ final static char[] CHARVALUE_CHARACTER_METHOD_SIGNATURE = "()C".toCharArray();
+ final static char[] BOOLEANVALUE_BOOLEAN_METHOD_SIGNATURE = "()Z".toCharArray();
+ final static char[] LONGVALUE_LONG_METHOD_SIGNATURE = "()J".toCharArray();
+ final static char[] GETDECLAREDCONSTRUCTOR_NAME =
+ "getDeclaredConstructor".toCharArray();
+ final static char[] GETDECLAREDCONSTRUCTOR_SIGNATURE =
+ "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;".toCharArray();
+
+ // predefined constant index for well known types
+ final static int JAVA_LANG_REFLECT_FIELD_TYPE = 0;
+ final static int JAVA_LANG_REFLECT_METHOD_TYPE = 1;
+ final static int JAVA_LANG_REFLECT_ACCESSIBLEOBJECT_TYPE = 2;
+ final static int JAVA_LANG_REFLECT_ARRAY_TYPE = 3;
+
+ // predefined constant index for well known methods
+ final static int GETDECLAREDFIELD_CLASS_METHOD = 0;
+ final static int SETACCESSIBLE_ACCESSIBLEOBJECT_METHOD = 1;
+ final static int GET_INT_METHOD = 2;
+ final static int GET_LONG_METHOD = 3;
+ final static int GET_DOUBLE_METHOD = 4;
+ final static int GET_FLOAT_METHOD = 5;
+ final static int GET_BYTE_METHOD = 6;
+ final static int GET_CHAR_METHOD = 7;
+ final static int GET_BOOLEAN_METHOD = 8;
+ final static int GET_OBJECT_METHOD = 9;
+ final static int GET_SHORT_METHOD = 10;
+ final static int SET_INT_METHOD = 11;
+ final static int SET_LONG_METHOD = 12;
+ final static int SET_DOUBLE_METHOD = 13;
+ final static int SET_FLOAT_METHOD = 14;
+ final static int SET_BYTE_METHOD = 15;
+ final static int SET_CHAR_METHOD = 16;
+ final static int SET_BOOLEAN_METHOD = 17;
+ final static int SET_OBJECT_METHOD = 18;
+ final static int SET_SHORT_METHOD = 19;
+ final static int GETDECLAREDMETHOD_CLASS_METHOD = 20;
+ final static int NEWINSTANCE_ARRAY_METHOD = 21;
+ final static int GETCLASS_OBJECT_METHOD = 22;
+ final static int INVOKE_METHOD_METHOD = 23;
+ final static int BYTEVALUE_BYTE_METHOD = 24;
+ final static int SHORTVALUE_SHORT_METHOD = 25;
+ final static int DOUBLEVALUE_DOUBLE_METHOD = 26;
+ final static int FLOATVALUE_FLOAT_METHOD = 27;
+ final static int INTVALUE_INTEGER_METHOD = 28;
+ final static int CHARVALUE_CHARACTER_METHOD = 29;
+ final static int BOOLEANVALUE_BOOLEAN_METHOD = 30;
+ final static int LONGVALUE_LONG_METHOD = 31;
+ final static int GETDECLAREDCONSTRUCTOR_CLASS_METHOD = 32;
+
+ // predefined constant index for well known name and type for methods
+ final static int GETDECLAREDFIELD_CLASS_METHOD_NAME_AND_TYPE = 0;
+ final static int SETACCESSIBLE_ACCESSIBLEOBJECT_METHOD_NAME_AND_TYPE = 1;
+ final static int GET_INT_METHOD_NAME_AND_TYPE = 2;
+ final static int GET_LONG_METHOD_NAME_AND_TYPE = 3;
+ final static int GET_DOUBLE_METHOD_NAME_AND_TYPE = 4;
+ final static int GET_FLOAT_METHOD_NAME_AND_TYPE = 5;
+ final static int GET_BYTE_METHOD_NAME_AND_TYPE = 6;
+ final static int GET_CHAR_METHOD_NAME_AND_TYPE = 7;
+ final static int GET_BOOLEAN_METHOD_NAME_AND_TYPE = 8;
+ final static int GET_OBJECT_METHOD_NAME_AND_TYPE = 9;
+ final static int GET_SHORT_METHOD_NAME_AND_TYPE = 10;
+ final static int SET_INT_METHOD_NAME_AND_TYPE = 11;
+ final static int SET_LONG_METHOD_NAME_AND_TYPE = 12;
+ final static int SET_DOUBLE_METHOD_NAME_AND_TYPE = 13;
+ final static int SET_FLOAT_METHOD_NAME_AND_TYPE = 14;
+ final static int SET_BYTE_METHOD_NAME_AND_TYPE = 15;
+ final static int SET_CHAR_METHOD_NAME_AND_TYPE = 16;
+ final static int SET_BOOLEAN_METHOD_NAME_AND_TYPE = 17;
+ final static int SET_OBJECT_METHOD_NAME_AND_TYPE = 18;
+ final static int SET_SHORT_METHOD_NAME_AND_TYPE = 19;
+ final static int GETDECLAREDMETHOD_CLASS_METHOD_NAME_AND_TYPE = 20;
+ final static int ARRAY_NEWINSTANCE_METHOD_NAME_AND_TYPE = 21;
+ final static int GETCLASS_OBJECT_METHOD_NAME_AND_TYPE = 22;
+ final static int INVOKE_METHOD_METHOD_NAME_AND_TYPE = 23;
+ final static int BYTEVALUE_BYTE_METHOD_NAME_AND_TYPE = 24;
+ final static int SHORTVALUE_SHORT_METHOD_NAME_AND_TYPE = 25;
+ final static int DOUBLEVALUE_DOUBLE_METHOD_NAME_AND_TYPE = 26;
+ final static int FLOATVALUE_FLOAT_METHOD_NAME_AND_TYPE = 27;
+ final static int INTVALUE_INTEGER_METHOD_NAME_AND_TYPE = 28;
+ final static int CHARVALUE_CHARACTER_METHOD_NAME_AND_TYPE = 29;
+ final static int BOOLEANVALUE_BOOLEAN_METHOD_NAME_AND_TYPE = 30;
+ final static int LONGVALUE_LONG_METHOD_NAME_AND_TYPE = 31;
+ final static int GETDECLAREDCONSTRUCTOR_CLASS_METHOD_NAME_AND_TYPE = 32;
+
+ int[] wellKnownTypes = new int[4];
+ int[] wellKnownMethods = new int[33];
+ int[] wellKnownMethodNameAndTypes = new int[33];
+ /**
+ * CodeSnippetConstantPool constructor comment.
+ * @param classFile org.eclipse.jdt.internal.compiler.ClassFile
+ */
+ public CodeSnippetConstantPool(
+ org.eclipse.jdt.internal.compiler.ClassFile classFile) {
+ super(classFile);
+ }
+
+ /**
+ * Return the index of the @methodBinding.
+ *
+ * Returns -1 if the @methodBinding is not a predefined methodBinding,
+ * the right index otherwise.
+ *
+ * @param methodBinding com.ibm.compiler.namelookup.MethodBinding
+ * @return <CODE>int</CODE>
+ */
+ public int indexOfWellKnownMethodNameAndType(MethodBinding methodBinding) {
+ int index = super.indexOfWellKnownMethodNameAndType(methodBinding);
+ if (index == -1) {
+ char firstChar = methodBinding.selector[0];
+ switch (firstChar) {
+ case 'g' :
+ if (methodBinding.parameters.length == 1
+ && methodBinding.parameters[0].id == T_JavaLangString
+ && CharOperation.equals(methodBinding.selector, GETDECLAREDFIELD_NAME)
+ && methodBinding.returnType instanceof ReferenceBinding
+ && CharOperation.equals(
+ ((ReferenceBinding) methodBinding.returnType).compoundName,
+ JAVA_LANG_REFLECT_FIELD)) {
+ return GETDECLAREDFIELD_CLASS_METHOD_NAME_AND_TYPE;
+ }
+ if (methodBinding.parameters.length == 2
+ && methodBinding.parameters[0].id == T_JavaLangString
+ && methodBinding.parameters[1].isArrayType()
+ && ((ArrayBinding) methodBinding.parameters[1]).leafComponentType.id
+ == T_JavaLangClass
+ && CharOperation.equals(methodBinding.selector, GETDECLAREDMETHOD_NAME)
+ && methodBinding.returnType instanceof ReferenceBinding
+ && CharOperation.equals(
+ ((ReferenceBinding) methodBinding.returnType).compoundName,
+ JAVA_LANG_REFLECT_METHOD)) {
+ return GETDECLAREDMETHOD_CLASS_METHOD_NAME_AND_TYPE;
+ }
+ if (methodBinding.parameters.length == 1
+ && methodBinding.parameters[0].isArrayType()
+ && ((ArrayBinding) methodBinding.parameters[0]).leafComponentType.id
+ == T_JavaLangClass
+ && CharOperation.equals(methodBinding.selector, GETDECLAREDCONSTRUCTOR_NAME)
+ && methodBinding.returnType instanceof ReferenceBinding
+ && CharOperation.equals(
+ ((ReferenceBinding) methodBinding.returnType).compoundName,
+ JAVA_LANG_REFLECT_CONSTRUCTOR)) {
+ return GETDECLAREDCONSTRUCTOR_CLASS_METHOD_NAME_AND_TYPE;
+ }
+ if (methodBinding.parameters.length == 0
+ && CharOperation.equals(methodBinding.selector, GETCLASS_OBJECT_METHOD_NAME)
+ && methodBinding.returnType.id == T_JavaLangClass) {
+ return GETCLASS_OBJECT_METHOD_NAME_AND_TYPE;
+ }
+ if (methodBinding.parameters.length == 1
+ && methodBinding.parameters[0].id == T_Object) {
+ switch (methodBinding.returnType.id) {
+ case T_int :
+ if (CharOperation.equals(methodBinding.selector, GET_INT_METHOD_NAME)
+ && methodBinding.returnType.id == T_int) {
+ return GET_INT_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case T_byte :
+ if (CharOperation.equals(methodBinding.selector, GET_BYTE_METHOD_NAME)
+ && methodBinding.returnType.id == T_byte) {
+ return GET_BYTE_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case T_short :
+ if (CharOperation.equals(methodBinding.selector, GET_SHORT_METHOD_NAME)
+ && methodBinding.returnType.id == T_short) {
+ return GET_SHORT_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case T_char :
+ if (CharOperation.equals(methodBinding.selector, GET_CHAR_METHOD_NAME)
+ && methodBinding.returnType.id == T_char) {
+ return GET_CHAR_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case T_double :
+ if (CharOperation.equals(methodBinding.selector, GET_DOUBLE_METHOD_NAME)
+ && methodBinding.returnType.id == T_double) {
+ return GET_DOUBLE_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case T_float :
+ if (CharOperation.equals(methodBinding.selector, GET_FLOAT_METHOD_NAME)
+ && methodBinding.returnType.id == T_float) {
+ return GET_FLOAT_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case T_long :
+ if (CharOperation.equals(methodBinding.selector, GET_LONG_METHOD_NAME)
+ && methodBinding.returnType.id == T_long) {
+ return GET_LONG_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case T_boolean :
+ if (CharOperation.equals(methodBinding.selector, GET_BOOLEAN_METHOD_NAME)
+ && methodBinding.returnType.id == T_boolean) {
+ return GET_BOOLEAN_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case T_Object :
+ if (CharOperation.equals(methodBinding.selector, GET_OBJECT_METHOD_NAME)
+ && methodBinding.returnType.id == T_JavaLangObject) {
+ return GET_OBJECT_METHOD_NAME_AND_TYPE;
+ }
+ }
+ }
+ break;
+ case 'i' :
+ if (methodBinding.parameters.length == 0
+ && CharOperation.equals(methodBinding.selector, INTVALUE_INTEGER_METHOD_NAME)
+ && methodBinding.returnType.id == T_int) {
+ return INTVALUE_INTEGER_METHOD_NAME_AND_TYPE;
+ }
+ if (methodBinding.parameters.length == 2
+ && methodBinding.parameters[0].id == T_JavaLangObject
+ && methodBinding.parameters[1].isArrayType()
+ && ((ArrayBinding) methodBinding.parameters[1]).leafComponentType.id
+ == T_JavaLangObject
+ && CharOperation.equals(methodBinding.selector, INVOKE_METHOD_METHOD_NAME)
+ && methodBinding.returnType.id == T_JavaLangObject) {
+ return INVOKE_METHOD_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case 's' :
+ if (methodBinding.parameters.length == 0
+ && CharOperation.equals(methodBinding.selector, SHORTVALUE_SHORT_METHOD_NAME)
+ && methodBinding.returnType.id == T_short) {
+ return SHORTVALUE_SHORT_METHOD_NAME_AND_TYPE;
+ }
+ if (methodBinding.parameters.length == 1
+ && methodBinding.parameters[0].id == T_boolean
+ && methodBinding.selector.length == 13
+ && CharOperation.equals(methodBinding.selector, SETACCESSIBLE_NAME)
+ && methodBinding.returnType.id == T_void) {
+ return SETACCESSIBLE_ACCESSIBLEOBJECT_METHOD_NAME_AND_TYPE;
+ }
+ if (methodBinding.returnType.id == T_void
+ && methodBinding.parameters.length == 2
+ && methodBinding.parameters[0].id == T_Object) {
+ switch (methodBinding.returnType.id) {
+ case T_int :
+ if (methodBinding.parameters[1].id == T_int
+ && CharOperation.equals(methodBinding.selector, SET_INT_METHOD_NAME)
+ && methodBinding.returnType.id == T_void) {
+ return SET_INT_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case T_byte :
+ if (methodBinding.parameters[1].id == T_byte
+ && CharOperation.equals(methodBinding.selector, SET_BYTE_METHOD_NAME)
+ && methodBinding.returnType.id == T_void) {
+ return SET_BYTE_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case T_short :
+ if (methodBinding.parameters[1].id == T_short
+ && CharOperation.equals(methodBinding.selector, SET_SHORT_METHOD_NAME)
+ && methodBinding.returnType.id == T_void) {
+ return SET_SHORT_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case T_char :
+ if (methodBinding.parameters[1].id == T_char
+ && CharOperation.equals(methodBinding.selector, SET_CHAR_METHOD_NAME)
+ && methodBinding.returnType.id == T_void) {
+ return SET_CHAR_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case T_double :
+ if (methodBinding.parameters[1].id == T_double
+ && CharOperation.equals(methodBinding.selector, SET_DOUBLE_METHOD_NAME)
+ && methodBinding.returnType.id == T_void) {
+ return SET_DOUBLE_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case T_float :
+ if (methodBinding.parameters[1].id == T_float
+ && CharOperation.equals(methodBinding.selector, SET_FLOAT_METHOD_NAME)
+ && methodBinding.returnType.id == T_void) {
+ return SET_FLOAT_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case T_long :
+ if (methodBinding.parameters[1].id == T_long
+ && CharOperation.equals(methodBinding.selector, SET_LONG_METHOD_NAME)
+ && methodBinding.returnType.id == T_void) {
+ return SET_LONG_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case T_boolean :
+ if (methodBinding.parameters[1].id == T_boolean
+ && CharOperation.equals(methodBinding.selector, SET_BOOLEAN_METHOD_NAME)
+ && methodBinding.returnType.id == T_void) {
+ return SET_BOOLEAN_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case T_Object :
+ if (methodBinding.parameters[1].id == T_Object
+ && CharOperation.equals(methodBinding.selector, SET_OBJECT_METHOD_NAME)
+ && methodBinding.returnType.id == T_void) {
+ return SET_OBJECT_METHOD_NAME_AND_TYPE;
+ }
+ }
+ }
+ break;
+ case 'f' :
+ if (methodBinding.parameters.length == 0
+ && CharOperation.equals(methodBinding.selector, FLOATVALUE_FLOAT_METHOD_NAME)
+ && methodBinding.returnType.id == T_float) {
+ return FLOATVALUE_FLOAT_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case 'd' :
+ if (methodBinding.parameters.length == 0
+ && CharOperation.equals(methodBinding.selector, DOUBLEVALUE_DOUBLE_METHOD_NAME)
+ && methodBinding.returnType.id == T_double) {
+ return DOUBLEVALUE_DOUBLE_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case 'c' :
+ if (methodBinding.parameters.length == 0
+ && CharOperation.equals(methodBinding.selector, CHARVALUE_CHARACTER_METHOD_NAME)
+ && methodBinding.returnType.id == T_char) {
+ return CHARVALUE_CHARACTER_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case 'b' :
+ if (methodBinding.parameters.length == 0
+ && CharOperation.equals(methodBinding.selector, BOOLEANVALUE_BOOLEAN_METHOD_NAME)
+ && methodBinding.returnType.id == T_boolean) {
+ return BOOLEANVALUE_BOOLEAN_METHOD_NAME_AND_TYPE;
+ }
+ if (methodBinding.parameters.length == 0
+ && CharOperation.equals(methodBinding.selector, BYTEVALUE_BYTE_METHOD_NAME)
+ && methodBinding.returnType.id == T_byte) {
+ return BYTEVALUE_BYTE_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case 'l' :
+ if (methodBinding.parameters.length == 0
+ && CharOperation.equals(methodBinding.selector, LONGVALUE_LONG_METHOD_NAME)
+ && methodBinding.returnType.id == T_long) {
+ return LONGVALUE_LONG_METHOD_NAME_AND_TYPE;
+ }
+ break;
+ case 'n' :
+ if (methodBinding.parameters.length == 2
+ && methodBinding.parameters[0].id == T_JavaLangClass
+ && methodBinding.parameters[1].isArrayType()
+ && ((ArrayBinding) methodBinding.parameters[1]).leafComponentType.id == T_int
+ && CharOperation.equals(methodBinding.selector, ARRAY_NEWINSTANCE_NAME)
+ && methodBinding.returnType instanceof ReferenceBinding
+ && CharOperation.equals(
+ ((ReferenceBinding) methodBinding.returnType).compoundName,
+ JAVA_LANG_REFLECT_ARRAY)) {
+ return ARRAY_NEWINSTANCE_METHOD_NAME_AND_TYPE;
+ }
+ }
+
+ }
+ return index;
+ }
+
+ /**
+ * Return the index of the @methodBinding.
+ *
+ * Returns -1 if the @methodBinding is not a predefined methodBinding,
+ * the right index otherwise.
+ *
+ * @param methodBinding com.ibm.compiler.namelookup.MethodBinding
+ * @return <CODE>int</CODE>
+ */
+ public int indexOfWellKnownMethods(MethodBinding methodBinding) {
+ int index = super.indexOfWellKnownMethods(methodBinding);
+ if (index == -1) {
+ char firstChar = methodBinding.selector[0];
+ switch (firstChar) {
+ case 'g' :
+ if (methodBinding.declaringClass.id == T_JavaLangClass
+ && methodBinding.parameters.length == 1
+ && methodBinding.parameters[0].id == T_JavaLangString
+ && CharOperation.equals(methodBinding.selector, GETDECLAREDFIELD_NAME)) {
+ return GETDECLAREDFIELD_CLASS_METHOD;
+ }
+ if (methodBinding.declaringClass.id == T_JavaLangClass
+ && methodBinding.parameters.length == 2
+ && methodBinding.parameters[0].id == T_JavaLangString
+ && methodBinding.parameters[1].isArrayType()
+ && ((ArrayBinding) methodBinding.parameters[1]).leafComponentType.id
+ == T_JavaLangClass
+ && CharOperation.equals(methodBinding.selector, GETDECLAREDMETHOD_NAME)) {
+ return GETDECLAREDMETHOD_CLASS_METHOD;
+ }
+ if (methodBinding.declaringClass.id == T_JavaLangClass
+ && methodBinding.parameters.length == 1
+ && methodBinding.parameters[0].isArrayType()
+ && ((ArrayBinding) methodBinding.parameters[0]).leafComponentType.id
+ == T_JavaLangClass
+ && CharOperation.equals(methodBinding.selector, GETDECLAREDCONSTRUCTOR_NAME)) {
+ return GETDECLAREDCONSTRUCTOR_CLASS_METHOD;
+ }
+ if (methodBinding.declaringClass.id == T_JavaLangObject
+ && methodBinding.parameters.length == 0
+ && CharOperation.equals(methodBinding.selector, GETCLASS_OBJECT_METHOD_NAME)) {
+ return GETCLASS_OBJECT_METHOD;
+ }
+ if (CharOperation
+ .equals(methodBinding.declaringClass.compoundName, JAVA_LANG_REFLECT_FIELD)
+ && methodBinding.parameters.length == 1
+ && methodBinding.parameters[0].id == T_Object) {
+ switch (methodBinding.returnType.id) {
+ case T_int :
+ if (CharOperation.equals(methodBinding.selector, GET_INT_METHOD_NAME)) {
+ return GET_INT_METHOD;
+ }
+ break;
+ case T_byte :
+ if (CharOperation.equals(methodBinding.selector, GET_BYTE_METHOD_NAME)) {
+ return GET_BYTE_METHOD;
+ }
+ break;
+ case T_short :
+ if (CharOperation.equals(methodBinding.selector, GET_SHORT_METHOD_NAME)) {
+ return GET_SHORT_METHOD;
+ }
+ break;
+ case T_char :
+ if (CharOperation.equals(methodBinding.selector, GET_CHAR_METHOD_NAME)) {
+ return GET_CHAR_METHOD;
+ }
+ break;
+ case T_double :
+ if (CharOperation.equals(methodBinding.selector, GET_DOUBLE_METHOD_NAME)) {
+ return GET_DOUBLE_METHOD;
+ }
+ break;
+ case T_float :
+ if (CharOperation.equals(methodBinding.selector, GET_FLOAT_METHOD_NAME)) {
+ return GET_FLOAT_METHOD;
+ }
+ break;
+ case T_long :
+ if (CharOperation.equals(methodBinding.selector, GET_LONG_METHOD_NAME)) {
+ return GET_LONG_METHOD;
+ }
+ break;
+ case T_boolean :
+ if (CharOperation.equals(methodBinding.selector, GET_BOOLEAN_METHOD_NAME)) {
+ return GET_BOOLEAN_METHOD;
+ }
+ break;
+ case T_Object :
+ if (CharOperation.equals(methodBinding.selector, GET_OBJECT_METHOD_NAME)) {
+ return GET_OBJECT_METHOD;
+ }
+ }
+ }
+ break;
+ case 'i' :
+ if (methodBinding.declaringClass.id == T_JavaLangInteger
+ && methodBinding.parameters.length == 0
+ && CharOperation.equals(methodBinding.selector, INTVALUE_INTEGER_METHOD_NAME)) {
+ return INTVALUE_INTEGER_METHOD;
+ }
+ if (CharOperation
+ .equals(methodBinding.declaringClass.compoundName, JAVA_LANG_REFLECT_METHOD)
+ && methodBinding.parameters.length == 2
+ && methodBinding.parameters[0].id == T_JavaLangObject
+ && methodBinding.parameters[1].isArrayType()
+ && ((ArrayBinding) methodBinding.parameters[1]).leafComponentType.id
+ == T_JavaLangObject
+ && CharOperation.equals(methodBinding.selector, INVOKE_METHOD_METHOD_NAME)) {
+ return INVOKE_METHOD_METHOD;
+ }
+ break;
+ case 'b' :
+ if (methodBinding.declaringClass.id == T_JavaLangByte
+ && methodBinding.parameters.length == 0
+ && CharOperation.equals(methodBinding.selector, BYTEVALUE_BYTE_METHOD_NAME)) {
+ return BYTEVALUE_BYTE_METHOD;
+ }
+ if (methodBinding.declaringClass.id == T_JavaLangBoolean
+ && methodBinding.parameters.length == 0
+ && CharOperation.equals(
+ methodBinding.selector,
+ BOOLEANVALUE_BOOLEAN_METHOD_NAME)) {
+ return BOOLEANVALUE_BOOLEAN_METHOD;
+ }
+ break;
+ case 's' :
+ if (methodBinding.declaringClass.id == T_JavaLangShort
+ && methodBinding.parameters.length == 0
+ && CharOperation.equals(methodBinding.selector, SHORTVALUE_SHORT_METHOD_NAME)) {
+ return SHORTVALUE_SHORT_METHOD;
+ }
+ if (CharOperation
+ .equals(
+ methodBinding.declaringClass.compoundName,
+ JAVA_LANG_REFLECT_ACCESSIBLEOBJECT)
+ && methodBinding.parameters.length == 1
+ && methodBinding.parameters[0].id == T_boolean
+ && methodBinding.selector.length == 13
+ && CharOperation.equals(methodBinding.selector, SETACCESSIBLE_NAME)) {
+ return SETACCESSIBLE_ACCESSIBLEOBJECT_METHOD;
+ }
+ if (CharOperation
+ .equals(methodBinding.declaringClass.compoundName, JAVA_LANG_REFLECT_FIELD)
+ && methodBinding.returnType.id == T_void
+ && methodBinding.parameters.length == 2
+ && methodBinding.parameters[0].id == T_Object) {
+ switch (methodBinding.returnType.id) {
+ case T_int :
+ if (methodBinding.parameters[1].id == T_int
+ && CharOperation.equals(methodBinding.selector, SET_INT_METHOD_NAME)) {
+ return SET_INT_METHOD;
+ }
+ break;
+ case T_byte :
+ if (methodBinding.parameters[1].id == T_byte
+ && CharOperation.equals(methodBinding.selector, SET_BYTE_METHOD_NAME)) {
+ return SET_BYTE_METHOD;
+ }
+ break;
+ case T_short :
+ if (methodBinding.parameters[1].id == T_short
+ && CharOperation.equals(methodBinding.selector, SET_SHORT_METHOD_NAME)) {
+ return SET_SHORT_METHOD;
+ }
+ break;
+ case T_char :
+ if (methodBinding.parameters[1].id == T_char
+ && CharOperation.equals(methodBinding.selector, SET_CHAR_METHOD_NAME)) {
+ return SET_CHAR_METHOD;
+ }
+ break;
+ case T_double :
+ if (methodBinding.parameters[1].id == T_double
+ && CharOperation.equals(methodBinding.selector, SET_DOUBLE_METHOD_NAME)) {
+ return SET_DOUBLE_METHOD;
+ }
+ break;
+ case T_float :
+ if (methodBinding.parameters[1].id == T_float
+ && CharOperation.equals(methodBinding.selector, SET_FLOAT_METHOD_NAME)) {
+ return SET_FLOAT_METHOD;
+ }
+ break;
+ case T_long :
+ if (methodBinding.parameters[1].id == T_long
+ && CharOperation.equals(methodBinding.selector, SET_LONG_METHOD_NAME)) {
+ return SET_LONG_METHOD;
+ }
+ break;
+ case T_boolean :
+ if (methodBinding.parameters[1].id == T_boolean
+ && CharOperation.equals(methodBinding.selector, SET_BOOLEAN_METHOD_NAME)) {
+ return SET_BOOLEAN_METHOD;
+ }
+ break;
+ case T_Object :
+ if (methodBinding.parameters[1].id == T_Object
+ && CharOperation.equals(methodBinding.selector, SET_OBJECT_METHOD_NAME)) {
+ return SET_OBJECT_METHOD;
+ }
+ }
+ }
+ break;
+ case 'f' :
+ if (methodBinding.declaringClass.id == T_JavaLangFloat
+ && methodBinding.parameters.length == 0
+ && CharOperation.equals(methodBinding.selector, FLOATVALUE_FLOAT_METHOD_NAME)) {
+ return FLOATVALUE_FLOAT_METHOD;
+ }
+ break;
+ case 'd' :
+ if (methodBinding.declaringClass.id == T_JavaLangDouble
+ && methodBinding.parameters.length == 0
+ && CharOperation.equals(methodBinding.selector, DOUBLEVALUE_DOUBLE_METHOD_NAME)) {
+ return DOUBLEVALUE_DOUBLE_METHOD;
+ }
+ break;
+ case 'c' :
+ if (methodBinding.declaringClass.id == T_JavaLangCharacter
+ && methodBinding.parameters.length == 0
+ && CharOperation.equals(
+ methodBinding.selector,
+ CHARVALUE_CHARACTER_METHOD_NAME)) {
+ return CHARVALUE_CHARACTER_METHOD;
+ }
+ break;
+ case 'l' :
+ if (methodBinding.declaringClass.id == T_JavaLangLong
+ && methodBinding.parameters.length == 0
+ && CharOperation.equals(methodBinding.selector, LONGVALUE_LONG_METHOD_NAME)) {
+ return LONGVALUE_LONG_METHOD;
+ }
+ break;
+ case 'n' :
+ if (CharOperation
+ .equals(methodBinding.declaringClass.compoundName, JAVA_LANG_REFLECT_ARRAY)
+ && methodBinding.parameters.length == 2
+ && methodBinding.parameters[0].id == T_JavaLangClass
+ && methodBinding.parameters[1].isArrayType()
+ && ((ArrayBinding) methodBinding.parameters[1]).leafComponentType.id == T_int
+ && CharOperation.equals(methodBinding.selector, ARRAY_NEWINSTANCE_NAME)) {
+ return NEWINSTANCE_ARRAY_METHOD;
+ }
+ break;
+ }
+ }
+ return index;
+ }
+
+ /**
+ * Return the index of the @typeBinding
+ *
+ * Returns -1 if the @typeBinding is not a predefined binding, the right index
+ * otherwise.
+ *
+ * @param typeBinding com.ibm.compiler.namelookup.TypeBinding
+ * @return <CODE>int</CODE>
+ */
+ public int indexOfWellKnownTypes(TypeBinding typeBinding) {
+ int index = super.indexOfWellKnownTypes(typeBinding);
+ if (index == -1) {
+ if (!typeBinding.isBaseType() && !typeBinding.isArrayType()) {
+ ReferenceBinding type = (ReferenceBinding) typeBinding;
+ if (type.compoundName.length == 4) {
+ if (CharOperation.equals(JAVA_LANG_REFLECT_FIELD, type.compoundName)) {
+ return JAVA_LANG_REFLECT_FIELD_TYPE;
+ }
+ if (CharOperation.equals(JAVA_LANG_REFLECT_METHOD, type.compoundName)) {
+ return JAVA_LANG_REFLECT_METHOD_TYPE;
+ }
+ if (CharOperation.equals(JAVA_LANG_REFLECT_ARRAY, type.compoundName)) {
+ return JAVA_LANG_REFLECT_ARRAY_TYPE;
+ }
+ if (CharOperation
+ .equals(JAVA_LANG_REFLECT_ACCESSIBLEOBJECT, type.compoundName)) {
+ return JAVA_LANG_REFLECT_ACCESSIBLEOBJECT_TYPE;
+ }
+ }
+ }
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @param MethodBinding aMethodBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndex(MethodBinding aMethodBinding) {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ int nameIndex;
+ int indexWellKnownMethod;
+ if ((indexWellKnownMethod = super.indexOfWellKnownMethods(aMethodBinding))
+ == -1) {
+ if ((indexWellKnownMethod = indexOfWellKnownMethods(aMethodBinding)) == -1) {
+ if (aMethodBinding.declaringClass.isInterface()) {
+ // Lookinf into the interface method ref table
+ if ((index = interfaceMethodCache.get(aMethodBinding)) < 0) {
+ classIndex = literalIndex(aMethodBinding.declaringClass);
+ nameAndTypeIndex =
+ literalIndexForMethods(
+ literalIndex(aMethodBinding.constantPoolName()),
+ literalIndex(aMethodBinding.signature()),
+ aMethodBinding);
+ index = interfaceMethodCache.put(aMethodBinding, currentIndex++);
+ // Write the interface method ref constant into the constant pool
+ // First add the tag
+ writeU1(InterfaceMethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ } else {
+ // Lookinf into the method ref table
+ if ((index = methodCache.get(aMethodBinding)) < 0) {
+ classIndex = literalIndex(aMethodBinding.declaringClass);
+ nameAndTypeIndex =
+ literalIndexForMethods(
+ literalIndex(aMethodBinding.constantPoolName()),
+ literalIndex(aMethodBinding.signature()),
+ aMethodBinding);
+ index = methodCache.put(aMethodBinding, currentIndex++);
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ }
+ } else {
+ // This is a well known method
+ if ((index = wellKnownMethods[indexWellKnownMethod]) == 0) {
+ // this methods was not inserted yet
+ if (aMethodBinding.declaringClass.isInterface()) {
+ // Lookinf into the interface method ref table
+ classIndex = literalIndex(aMethodBinding.declaringClass);
+ nameAndTypeIndex =
+ literalIndexForMethods(
+ literalIndex(aMethodBinding.constantPoolName()),
+ literalIndex(aMethodBinding.signature()),
+ aMethodBinding);
+ index = wellKnownMethods[indexWellKnownMethod] = currentIndex++;
+ // Write the interface method ref constant into the constant pool
+ // First add the tag
+ writeU1(InterfaceMethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ } else {
+ // Lookinf into the method ref table
+ classIndex = literalIndex(aMethodBinding.declaringClass);
+ nameAndTypeIndex =
+ literalIndexForMethods(
+ literalIndex(aMethodBinding.constantPoolName()),
+ literalIndex(aMethodBinding.signature()),
+ aMethodBinding);
+ index = wellKnownMethods[indexWellKnownMethod] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ }
+ }
+ } else {
+ index = super.literalIndex(aMethodBinding);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the type descriptor.
+ *
+ * @param TypeBinding aTypeBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndex(TypeBinding aTypeBinding) {
+ int index;
+ int nameIndex;
+ int indexWellKnownType;
+ if ((indexWellKnownType = super.indexOfWellKnownTypes(aTypeBinding)) == -1) {
+ if ((indexWellKnownType = indexOfWellKnownTypes(aTypeBinding)) == -1) {
+ if ((index = classCache.get(aTypeBinding)) < 0) {
+ // The entry doesn't exit yet
+ nameIndex = literalIndex(aTypeBinding.constantPoolName());
+ index = classCache.put(aTypeBinding, currentIndex++);
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ } else {
+ if ((index = wellKnownTypes[indexWellKnownType]) == 0) {
+ // Need to insert that binding
+ nameIndex = literalIndex(aTypeBinding.constantPoolName());
+ index = wellKnownTypes[indexWellKnownType] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ }
+ } else {
+ index = super.literalIndex(aTypeBinding);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangBooleanBooleanValue() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[BOOLEANVALUE_BOOLEAN_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangBoolean();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[BOOLEANVALUE_BOOLEAN_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(BOOLEANVALUE_BOOLEAN_METHOD_NAME);
+ int typeIndex = literalIndex(BOOLEANVALUE_BOOLEAN_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[BOOLEANVALUE_BOOLEAN_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index =
+ wellKnownMethods[BOOLEANVALUE_BOOLEAN_METHOD_NAME_AND_TYPE] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangByteByteValue() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[BYTEVALUE_BYTE_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangByte();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[BYTEVALUE_BYTE_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(BYTEVALUE_BYTE_METHOD_NAME);
+ int typeIndex = literalIndex(BYTEVALUE_BYTE_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[BYTEVALUE_BYTE_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[BYTEVALUE_BYTE_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangCharacterCharValue() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[CHARVALUE_CHARACTER_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangCharacter();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[CHARVALUE_CHARACTER_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(CHARVALUE_CHARACTER_METHOD_NAME);
+ int typeIndex = literalIndex(CHARVALUE_CHARACTER_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[CHARVALUE_CHARACTER_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[CHARVALUE_CHARACTER_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangClassGetDeclaredConstructor() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[GETDECLAREDCONSTRUCTOR_CLASS_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangClass();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GETDECLAREDCONSTRUCTOR_CLASS_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(GETDECLAREDCONSTRUCTOR_NAME);
+ int typeIndex = literalIndex(GETDECLAREDCONSTRUCTOR_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GETDECLAREDCONSTRUCTOR_CLASS_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[GETDECLAREDCONSTRUCTOR_CLASS_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangClassGetDeclaredField() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[GETDECLAREDFIELD_CLASS_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangClass();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GETDECLAREDFIELD_CLASS_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(GETDECLAREDFIELD_NAME);
+ int typeIndex = literalIndex(GETDECLAREDFIELD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GETDECLAREDFIELD_CLASS_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[GETDECLAREDFIELD_CLASS_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangClassGetDeclaredMethod() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[GETDECLAREDMETHOD_CLASS_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangClass();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GETDECLAREDMETHOD_CLASS_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(GETDECLAREDMETHOD_NAME);
+ int typeIndex = literalIndex(GETDECLAREDMETHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GETDECLAREDMETHOD_CLASS_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[GETDECLAREDMETHOD_CLASS_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangDoubleDoubleValue() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[DOUBLEVALUE_DOUBLE_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangDouble();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[DOUBLEVALUE_DOUBLE_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(DOUBLEVALUE_DOUBLE_METHOD_NAME);
+ int typeIndex = literalIndex(DOUBLEVALUE_DOUBLE_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[DOUBLEVALUE_DOUBLE_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[DOUBLEVALUE_DOUBLE_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangFloatFloatValue() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[FLOATVALUE_FLOAT_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangFloat();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[FLOATVALUE_FLOAT_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(FLOATVALUE_FLOAT_METHOD_NAME);
+ int typeIndex = literalIndex(FLOATVALUE_FLOAT_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[FLOATVALUE_FLOAT_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[FLOATVALUE_FLOAT_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangIntegerIntValue() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[INTVALUE_INTEGER_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangInteger();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[INTVALUE_INTEGER_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(INTVALUE_INTEGER_METHOD_NAME);
+ int typeIndex = literalIndex(INTVALUE_INTEGER_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[INTVALUE_INTEGER_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[INTVALUE_INTEGER_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangLongLongValue() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[LONGVALUE_LONG_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangLong();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[LONGVALUE_LONG_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(LONGVALUE_LONG_METHOD_NAME);
+ int typeIndex = literalIndex(LONGVALUE_LONG_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[LONGVALUE_LONG_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[LONGVALUE_LONG_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangObjectGetClass() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[GETCLASS_OBJECT_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangObject();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GETCLASS_OBJECT_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(GETCLASS_OBJECT_METHOD_NAME);
+ int typeIndex = literalIndex(GETCLASS_OBJECT_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GETCLASS_OBJECT_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[GETCLASS_OBJECT_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangReflectAccessibleObject() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_REFLECT_ACCESSIBLEOBJECT_TYPE]) == 0) {
+ int nameIndex;
+ // The entry doesn't exit yet
+ nameIndex = literalIndex(JAVALANGREFLECTACCESSIBLEOBJECT_CONSTANTPOOLNAME);
+ index =
+ wellKnownTypes[JAVA_LANG_REFLECT_ACCESSIBLEOBJECT_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangReflectAccessibleObjectSetAccessible() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[SETACCESSIBLE_ACCESSIBLEOBJECT_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangReflectAccessibleObject();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[SETACCESSIBLE_ACCESSIBLEOBJECT_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(SETACCESSIBLE_NAME);
+ int typeIndex = literalIndex(SETACCESSIBLE_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[SETACCESSIBLE_ACCESSIBLEOBJECT_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index =
+ wellKnownMethods[SETACCESSIBLE_ACCESSIBLEOBJECT_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangReflectArray() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_REFLECT_ARRAY_TYPE]) == 0) {
+ int nameIndex;
+ // The entry doesn't exit yet
+ nameIndex = literalIndex(JAVALANGREFLECTARRAY_CONSTANTPOOLNAME);
+ index = wellKnownTypes[JAVA_LANG_REFLECT_ARRAY_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangReflectArrayNewInstance() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[NEWINSTANCE_ARRAY_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangReflectArray();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[ARRAY_NEWINSTANCE_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(ARRAY_NEWINSTANCE_NAME);
+ int typeIndex = literalIndex(ARRAY_NEWINSTANCE_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[ARRAY_NEWINSTANCE_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[NEWINSTANCE_ARRAY_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangReflectField() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_REFLECT_FIELD_TYPE]) == 0) {
+ int nameIndex;
+ // The entry doesn't exit yet
+ nameIndex = literalIndex(JAVALANGREFLECTFIELD_CONSTANTPOOLNAME);
+ index = wellKnownTypes[JAVA_LANG_REFLECT_FIELD_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangReflectMethod() {
+ int index;
+ if ((index = wellKnownTypes[JAVA_LANG_REFLECT_METHOD_TYPE]) == 0) {
+ int nameIndex;
+ // The entry doesn't exit yet
+ nameIndex = literalIndex(JAVALANGREFLECTMETHOD_CONSTANTPOOLNAME);
+ index = wellKnownTypes[JAVA_LANG_REFLECT_METHOD_TYPE] = currentIndex++;
+ writeU1(ClassTag);
+ // Then add the 8 bytes representing the long
+ writeU2(nameIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangReflectMethodInvoke() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[INVOKE_METHOD_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangReflectMethod();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[INVOKE_METHOD_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(INVOKE_METHOD_METHOD_NAME);
+ int typeIndex = literalIndex(INVOKE_METHOD_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[INVOKE_METHOD_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[INVOKE_METHOD_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForJavaLangShortShortValue() {
+ int index;
+ int nameAndTypeIndex;
+ int classIndex;
+ // Looking into the method ref table
+ if ((index = wellKnownMethods[SHORTVALUE_SHORT_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangShort();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[SHORTVALUE_SHORT_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(SHORTVALUE_SHORT_METHOD_NAME);
+ int typeIndex = literalIndex(SHORTVALUE_SHORT_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[SHORTVALUE_SHORT_METHOD_NAME_AND_TYPE] =
+ currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[SHORTVALUE_SHORT_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding
+ * nameAndType constant with nameIndex, typeIndex.
+ *
+ * @param int nameIndex
+ * @param int nameIndex
+ * @param org.eclipse.jdt.internal.compiler.lookup.MethodBinding a methodBinding
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexForMethods(
+ int nameIndex,
+ int typeIndex,
+ MethodBinding key) {
+ int index;
+ int indexOfWellKnownMethodNameAndType;
+ if ((indexOfWellKnownMethodNameAndType =
+ super.indexOfWellKnownMethodNameAndType(key))
+ == -1) {
+ if ((indexOfWellKnownMethodNameAndType =
+ indexOfWellKnownMethodNameAndType(key))
+ == -1) {
+ // check if the entry exists
+ if ((index = nameAndTypeCacheForMethods.get(key)) == -1) {
+ // The entry doesn't exit yet
+ index = nameAndTypeCacheForMethods.put(key, currentIndex++);
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ } else {
+ if ((index = wellKnownMethodNameAndTypes[indexOfWellKnownMethodNameAndType])
+ == 0) {
+ index =
+ wellKnownMethodNameAndTypes[indexOfWellKnownMethodNameAndType] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ }
+ } else {
+ index = super.literalIndexForMethods(nameIndex, typeIndex, key);
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexJavaLangReflectFieldGetter(int typeID) {
+ int index = 0;
+ int nameAndTypeIndex = 0;
+ int classIndex = 0;
+ switch (typeID) {
+ case T_int :
+ if ((index = wellKnownMethods[GET_INT_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangReflectField();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GET_INT_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(GET_INT_METHOD_NAME);
+ int typeIndex = literalIndex(GET_INT_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GET_INT_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[GET_INT_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_byte :
+ if ((index = wellKnownMethods[GET_BYTE_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangReflectField();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GET_BYTE_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(GET_BYTE_METHOD_NAME);
+ int typeIndex = literalIndex(GET_BYTE_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GET_BYTE_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[GET_BYTE_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_short :
+ if ((index = wellKnownMethods[GET_SHORT_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangReflectField();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GET_SHORT_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(GET_SHORT_METHOD_NAME);
+ int typeIndex = literalIndex(GET_SHORT_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GET_SHORT_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[GET_SHORT_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_long :
+ if ((index = wellKnownMethods[GET_LONG_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangReflectField();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GET_LONG_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(GET_LONG_METHOD_NAME);
+ int typeIndex = literalIndex(GET_LONG_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GET_LONG_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[GET_LONG_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_float :
+ if ((index = wellKnownMethods[GET_FLOAT_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangReflectField();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GET_FLOAT_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(GET_FLOAT_METHOD_NAME);
+ int typeIndex = literalIndex(GET_FLOAT_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GET_FLOAT_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[GET_FLOAT_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_double :
+ if ((index = wellKnownMethods[GET_DOUBLE_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangReflectField();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GET_DOUBLE_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(GET_DOUBLE_METHOD_NAME);
+ int typeIndex = literalIndex(GET_DOUBLE_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GET_DOUBLE_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[GET_DOUBLE_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_char :
+ if ((index = wellKnownMethods[GET_CHAR_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangReflectField();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GET_CHAR_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(GET_CHAR_METHOD_NAME);
+ int typeIndex = literalIndex(GET_CHAR_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GET_CHAR_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[GET_CHAR_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_boolean :
+ if ((index = wellKnownMethods[GET_BOOLEAN_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangReflectField();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GET_BOOLEAN_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(GET_BOOLEAN_METHOD_NAME);
+ int typeIndex = literalIndex(GET_BOOLEAN_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GET_BOOLEAN_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[GET_BOOLEAN_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ default :
+ if ((index = wellKnownMethods[GET_OBJECT_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangReflectField();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GET_OBJECT_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(GET_OBJECT_METHOD_NAME);
+ int typeIndex = literalIndex(GET_OBJECT_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[GET_OBJECT_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[GET_OBJECT_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ }
+ return index;
+ }
+
+ /**
+ * This method returns the index into the constantPool corresponding to the
+ * method descriptor. It can be either an interface method reference constant
+ * or a method reference constant.
+ *
+ * @return <CODE>int</CODE>
+ */
+ public int literalIndexJavaLangReflectFieldSetter(int typeID) {
+ int index = 0;
+ int nameAndTypeIndex = 0;
+ int classIndex = 0;
+ switch (typeID) {
+ case T_int :
+ if ((index = wellKnownMethods[SET_INT_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangReflectField();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[SET_INT_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(SET_INT_METHOD_NAME);
+ int typeIndex = literalIndex(SET_INT_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[SET_INT_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[SET_INT_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_byte :
+ if ((index = wellKnownMethods[SET_BYTE_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangReflectField();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[SET_BYTE_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(SET_BYTE_METHOD_NAME);
+ int typeIndex = literalIndex(SET_BYTE_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[SET_BYTE_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[SET_BYTE_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_short :
+ if ((index = wellKnownMethods[SET_SHORT_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangReflectField();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[SET_SHORT_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(SET_SHORT_METHOD_NAME);
+ int typeIndex = literalIndex(SET_SHORT_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[SET_SHORT_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[SET_SHORT_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_long :
+ if ((index = wellKnownMethods[SET_LONG_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangReflectField();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[SET_LONG_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(SET_LONG_METHOD_NAME);
+ int typeIndex = literalIndex(SET_LONG_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[SET_LONG_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[SET_LONG_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_float :
+ if ((index = wellKnownMethods[SET_FLOAT_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangReflectField();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[SET_FLOAT_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(SET_FLOAT_METHOD_NAME);
+ int typeIndex = literalIndex(SET_FLOAT_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[SET_FLOAT_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[SET_FLOAT_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_double :
+ if ((index = wellKnownMethods[SET_DOUBLE_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangReflectField();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[SET_DOUBLE_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(SET_DOUBLE_METHOD_NAME);
+ int typeIndex = literalIndex(SET_DOUBLE_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[SET_DOUBLE_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[SET_DOUBLE_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_char :
+ if ((index = wellKnownMethods[SET_CHAR_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangReflectField();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[SET_CHAR_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(SET_CHAR_METHOD_NAME);
+ int typeIndex = literalIndex(SET_CHAR_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[SET_CHAR_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[SET_CHAR_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ case T_boolean :
+ if ((index = wellKnownMethods[SET_BOOLEAN_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangReflectField();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[SET_BOOLEAN_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(SET_BOOLEAN_METHOD_NAME);
+ int typeIndex = literalIndex(SET_BOOLEAN_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[SET_BOOLEAN_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[SET_BOOLEAN_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ break;
+ default :
+ if ((index = wellKnownMethods[SET_OBJECT_METHOD]) == 0) {
+ classIndex = literalIndexForJavaLangReflectField();
+ if ((nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[SET_OBJECT_METHOD_NAME_AND_TYPE])
+ == 0) {
+ int nameIndex = literalIndex(SET_OBJECT_METHOD_NAME);
+ int typeIndex = literalIndex(SET_OBJECT_METHOD_SIGNATURE);
+ nameAndTypeIndex =
+ wellKnownMethodNameAndTypes[SET_OBJECT_METHOD_NAME_AND_TYPE] = currentIndex++;
+ writeU1(NameAndTypeTag);
+ writeU2(nameIndex);
+ writeU2(typeIndex);
+ }
+ index = wellKnownMethods[SET_OBJECT_METHOD] = currentIndex++;
+ // Write the method ref constant into the constant pool
+ // First add the tag
+ writeU1(MethodRefTag);
+ // Then write the class index
+ writeU2(classIndex);
+ // The write the nameAndType index
+ writeU2(nameAndTypeIndex);
+ }
+ }
+ return index;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetEnvironment.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetEnvironment.java
new file mode 100644
index 0000000000..d6d91cc794
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetEnvironment.java
@@ -0,0 +1,84 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.ClassFile;
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.classfmt.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+/**
+ * An environment that wraps the client's name environment.
+ * This wrapper always considers the wrapped environment then if the name is
+ * not found, it search in the code snippet support. This includes the super class
+ * org.eclipse.jdt.internal.eval.target.CodeSnippet as well as the global variable classes.
+ */
+public class CodeSnippetEnvironment
+ implements INameEnvironment, EvaluationConstants {
+ INameEnvironment env;
+ EvaluationContext context;
+ /**
+ * Creates a new wrapper for the given environment.
+ */
+ public CodeSnippetEnvironment(
+ INameEnvironment env,
+ EvaluationContext context) {
+ this.env = env;
+ this.context = context;
+ }
+
+ /**
+ * @see INameEnvironment
+ */
+ public NameEnvironmentAnswer findType(char[][] compoundTypeName) {
+ NameEnvironmentAnswer result = this.env.findType(compoundTypeName);
+ if (result != null) {
+ return result;
+ }
+ if (CharOperation.equals(compoundTypeName, ROOT_COMPOUND_NAME)) {
+ IBinaryType binary = this.context.getRootCodeSnippetBinary();
+ if (binary == null) {
+ return null;
+ } else {
+ return new NameEnvironmentAnswer(binary);
+ }
+ }
+ VariablesInfo installedVars = this.context.installedVars;
+ ClassFile[] classFiles = installedVars.classFiles;
+ for (int i = 0; i < classFiles.length; i++) {
+ ClassFile classFile = classFiles[i];
+ if (CharOperation.equals(compoundTypeName, classFile.getCompoundName())) {
+ ClassFileReader binary = null;
+ try {
+ binary = new ClassFileReader(classFile.getBytes(), null);
+ } catch (ClassFormatException e) {
+ e.printStackTrace(); // Should never happen since we compiled this type
+ return null;
+ }
+ return new NameEnvironmentAnswer(binary);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @see INameEnvironment.
+ */
+ public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) {
+ NameEnvironmentAnswer result = this.env.findType(typeName, packageName);
+ if (result != null) {
+ return result;
+ }
+ return findType(CharOperation.arrayConcat(packageName, typeName));
+ }
+
+ /**
+ * @see INameEnvironment.
+ */
+ public boolean isPackage(char[][] parentPackageName, char[] packageName) {
+ return this.env.isPackage(parentPackageName, packageName);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetEvaluator.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetEvaluator.java
new file mode 100644
index 0000000000..41f916b692
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetEvaluator.java
@@ -0,0 +1,215 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.classfmt.*;
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+import java.util.*;
+
+/**
+ * A code snippet evaluator compiles and returns class file for a code snippet.
+ * Or it reports problems against the code snippet.
+ */
+public class CodeSnippetEvaluator
+ extends Evaluator
+ implements EvaluationConstants {
+ /**
+ * Whether the code snippet support classes should be found in the provided name environment
+ * or on disk.
+ */
+ final static boolean DEVELOPMENT_MODE = false;
+
+ /**
+ * The code snippet to evaluate.
+ */
+ char[] codeSnippet;
+
+ /**
+ * The code snippet to generated compilation unit mapper
+ */
+ CodeSnippetToCuMapper mapper;
+ /**
+ * Creates a new code snippet evaluator.
+ */
+ CodeSnippetEvaluator(
+ char[] codeSnippet,
+ EvaluationContext context,
+ INameEnvironment environment,
+ ConfigurableOption[] options,
+ IRequestor requestor,
+ IProblemFactory problemFactory) {
+ super(context, environment, options, requestor, problemFactory);
+ this.codeSnippet = codeSnippet;
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.eval.Evaluator
+ */
+ protected void addEvaluationResultForCompilationProblem(
+ Hashtable resultsByIDs,
+ IProblem problem,
+ char[] cuSource) {
+ CodeSnippetToCuMapper mapper = getMapper();
+ int pbLineNumber = problem.getSourceLineNumber();
+ int evaluationType = mapper.getEvaluationType(pbLineNumber);
+
+ char[] evaluationID = null;
+ switch (evaluationType) {
+ case EvaluationResult.T_PACKAGE :
+ evaluationID = this.context.packageName;
+
+ // shift line number, source start and source end
+ problem.setSourceLineNumber(1);
+ problem.setSourceStart(0);
+ problem.setSourceEnd(evaluationID.length - 1);
+ break;
+
+ case EvaluationResult.T_IMPORT :
+ evaluationID = mapper.getImport(pbLineNumber);
+
+ // shift line number, source start and source end
+ problem.setSourceLineNumber(1);
+ problem.setSourceStart(0);
+ problem.setSourceEnd(evaluationID.length - 1);
+ break;
+
+ case EvaluationResult.T_CODE_SNIPPET :
+ evaluationID = this.codeSnippet;
+
+ // shift line number, source start and source end
+ problem.setSourceLineNumber(pbLineNumber - this.mapper.lineNumberOffset);
+ problem.setSourceStart(problem.getSourceStart() - this.mapper.startPosOffset);
+ problem.setSourceEnd(problem.getSourceEnd() - this.mapper.startPosOffset);
+ break;
+
+ case EvaluationResult.T_INTERNAL :
+ evaluationID = cuSource;
+ break;
+ }
+
+ EvaluationResult result = (EvaluationResult) resultsByIDs.get(evaluationID);
+ if (result == null) {
+ resultsByIDs.put(
+ evaluationID,
+ new EvaluationResult(evaluationID, evaluationType, new IProblem[] { problem }));
+ } else {
+ result.addProblem(problem);
+ }
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.eval.Evaluator
+ */
+ protected char[] getClassName() {
+ return CharOperation.concat(
+ CODE_SNIPPET_CLASS_NAME_PREFIX,
+ Integer.toString(this.context.CODE_SNIPPET_COUNTER + 1).toCharArray());
+ }
+
+ /**
+ * @see Evaluator.
+ */
+ Compiler getCompiler(ICompilerRequestor requestor) {
+ Compiler compiler = null;
+ if (!DEVELOPMENT_MODE) {
+ // If we are not developping the code snippet support classes,
+ // use a regular compiler and feed its lookup environment with
+ // the code snippet support classes
+
+ compiler =
+ new CodeSnippetCompiler(
+ this.environment,
+ DefaultErrorHandlingPolicies.exitAfterAllProblems(),
+ this.options,
+ requestor,
+ this.problemFactory,
+ this.context,
+ getMapper().startPosOffset,
+ getMapper().startPosOffset + codeSnippet.length - 1);
+ // Initialize the compiler's lookup environment with the already compiled super classes
+ IBinaryType binary = this.context.getRootCodeSnippetBinary();
+ if (binary != null) {
+ compiler.lookupEnvironment.cacheBinaryType(binary);
+ }
+ VariablesInfo installedVars = this.context.installedVars;
+ if (installedVars != null) {
+ ClassFile[] globalClassFiles = installedVars.classFiles;
+ for (int i = 0; i < globalClassFiles.length; i++) {
+ ClassFileReader binaryType = null;
+ try {
+ binaryType = new ClassFileReader(globalClassFiles[i].getBytes(), null);
+ } catch (ClassFormatException e) {
+ e.printStackTrace(); // Should never happen since we compiled this type
+ }
+ compiler.lookupEnvironment.cacheBinaryType(binaryType);
+ }
+ }
+ } else {
+ // If we are developping the code snippet support classes,
+ // use a wrapped environment so that if the code snippet classes are not found
+ // then a default implementation is provided.
+
+ compiler =
+ new Compiler(
+ getWrapperEnvironment(),
+ DefaultErrorHandlingPolicies.exitAfterAllProblems(),
+ this.options,
+ requestor,
+ this.problemFactory);
+ }
+ return compiler;
+ }
+
+ private CodeSnippetToCuMapper getMapper() {
+ if (this.mapper == null) {
+ char[] varClassName = null;
+ VariablesInfo installedVars = this.context.installedVars;
+ if (installedVars != null) {
+ char[] superPackageName = installedVars.packageName;
+ if (superPackageName != null && superPackageName.length != 0) {
+ varClassName =
+ CharOperation.concat(superPackageName, installedVars.className, '.');
+ } else {
+ varClassName = installedVars.className;
+ }
+
+ }
+ this.mapper =
+ new CodeSnippetToCuMapper(
+ this.codeSnippet,
+ this.context.packageName,
+ this.context.imports,
+ getClassName(),
+ varClassName,
+ this.context.localVariableNames,
+ this.context.localVariableTypeNames,
+ this.context.localVariableModifiers,
+ this.context.declaringTypeName);
+
+ }
+ return this.mapper;
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.eval.Evaluator
+ */
+ protected char[] getSource() {
+ return getMapper().cuSource;
+ }
+
+ /**
+ * Returns an environment that wraps the client's name environment.
+ * This wrapper always considers the wrapped environment then if the name is
+ * not found, it search in the code snippet support. This includes the superclass
+ * org.eclipse.jdt.internal.eval.target.CodeSnippet as well as the global variable classes.
+ */
+ private INameEnvironment getWrapperEnvironment() {
+ return new CodeSnippetEnvironment(this.environment, this.context);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetFieldReference.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetFieldReference.java
new file mode 100644
index 0000000000..fe9170b653
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetFieldReference.java
@@ -0,0 +1,399 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
+import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ProblemFieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+
+public class CodeSnippetFieldReference
+ extends FieldReference
+ implements ProblemReasons, EvaluationConstants {
+ EvaluationContext evaluationContext;
+ FieldBinding delegateThis;
+ TypeBinding receiverType;
+ /**
+ * CodeSnippetFieldReference constructor comment.
+ * @param source char[]
+ * @param pos long
+ */
+ public CodeSnippetFieldReference(
+ char[] source,
+ long pos,
+ EvaluationContext evaluationContext) {
+ super(source, pos);
+ this.evaluationContext = evaluationContext;
+ }
+
+ public void generateAssignment(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Assignment assignment,
+ boolean valueRequired) {
+
+ if (binding.canBeSeenBy(receiverType, this, currentScope)) {
+ receiver.generateCode(currentScope, codeStream, !binding.isStatic());
+ assignment.expression.generateCode(currentScope, codeStream, true);
+ fieldStore(codeStream, binding, null, valueRequired);
+ } else {
+ ((CodeSnippetCodeStream) codeStream).generateEmulationForField(binding);
+ receiver.generateCode(currentScope, codeStream, !binding.isStatic());
+ if (binding.isStatic()) { // need a receiver?
+ codeStream.aconst_null();
+ }
+ assignment.expression.generateCode(currentScope, codeStream, true);
+ if (valueRequired) {
+ if ((binding.type == LongBinding) || (binding.type == DoubleBinding)) {
+ codeStream.dup2_x2();
+ } else {
+ codeStream.dup_x2();
+ }
+ }
+ ((CodeSnippetCodeStream) codeStream).generateEmulatedWriteAccessForField(
+ binding);
+ }
+ if (valueRequired) {
+ codeStream.generateImplicitConversion(assignment.implicitConversion);
+ }
+ }
+
+ /**
+ * Field reference code generation
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param valueRequired boolean
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ if (constant != NotAConstant) {
+ if (valueRequired) {
+ codeStream.generateConstant(constant, implicitConversion);
+ }
+ } else {
+ boolean isStatic = binding.isStatic();
+ receiver.generateCode(
+ currentScope,
+ codeStream,
+ valueRequired && (!isStatic) && (binding.constant == NotAConstant));
+ if (valueRequired) {
+ if (binding.constant == NotAConstant) {
+ if (binding.declaringClass == null) { // array length
+ codeStream.arraylength();
+ } else {
+ if (binding.canBeSeenBy(receiverType, this, currentScope)) {
+ if (isStatic) {
+ codeStream.getstatic(binding);
+ } else {
+ codeStream.getfield(binding);
+ }
+ } else {
+ if (isStatic) {
+ // we need a null on the stack to use the reflect emulation
+ codeStream.aconst_null();
+ }
+ ((CodeSnippetCodeStream) codeStream).generateEmulatedReadAccessForField(
+ binding);
+ }
+ }
+ codeStream.generateImplicitConversion(implicitConversion);
+ } else {
+ codeStream.generateConstant(binding.constant, implicitConversion);
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public void generateCompoundAssignment(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Expression expression,
+ int operator,
+ int assignmentImplicitConversion,
+ boolean valueRequired) {
+
+ boolean isStatic;
+ if (binding.canBeSeenBy(receiverType, this, currentScope)) {
+ receiver.generateCode(
+ currentScope,
+ codeStream,
+ !(isStatic = binding.isStatic()));
+ if (isStatic) {
+ codeStream.getstatic(binding);
+ } else {
+ codeStream.dup();
+ codeStream.getfield(binding);
+ }
+ int operationTypeID;
+ if ((operationTypeID = implicitConversion >> 4) == T_String) {
+ codeStream.generateStringAppend(currentScope, null, expression);
+ } else {
+ // promote the array reference to the suitable operation type
+ codeStream.generateImplicitConversion(implicitConversion);
+ // generate the increment value (will by itself be promoted to the operation value)
+ if (expression == IntLiteral.One) { // prefix operation
+ codeStream.generateConstant(expression.constant, implicitConversion);
+ } else {
+ expression.generateCode(currentScope, codeStream, true);
+ }
+ // perform the operation
+ codeStream.sendOperator(operator, operationTypeID);
+ // cast the value back to the array reference type
+ codeStream.generateImplicitConversion(assignmentImplicitConversion);
+ }
+ fieldStore(codeStream, binding, null, valueRequired);
+ } else {
+ receiver.generateCode(
+ currentScope,
+ codeStream,
+ !(isStatic = binding.isStatic()));
+ if (isStatic) {
+ // used to store the value
+ ((CodeSnippetCodeStream) codeStream).generateEmulationForField(binding);
+ codeStream.aconst_null();
+
+ // used to retrieve the actual value
+ codeStream.aconst_null();
+ ((CodeSnippetCodeStream) codeStream).generateEmulatedReadAccessForField(
+ binding);
+ } else {
+ // used to store the value
+ ((CodeSnippetCodeStream) codeStream).generateEmulationForField(binding);
+ receiver.generateCode(
+ currentScope,
+ codeStream,
+ !(isStatic = binding.isStatic()));
+
+ // used to retrieve the actual value
+ codeStream.dup();
+ ((CodeSnippetCodeStream) codeStream).generateEmulatedReadAccessForField(
+ binding);
+
+ }
+ int operationTypeID;
+ if ((operationTypeID = implicitConversion >> 4) == T_String) {
+ codeStream.generateStringAppend(currentScope, null, expression);
+ } else {
+ // promote the array reference to the suitable operation type
+ codeStream.generateImplicitConversion(implicitConversion);
+ // generate the increment value (will by itself be promoted to the operation value)
+ if (expression == IntLiteral.One) { // prefix operation
+ codeStream.generateConstant(expression.constant, implicitConversion);
+ } else {
+ expression.generateCode(currentScope, codeStream, true);
+ }
+ // perform the operation
+ codeStream.sendOperator(operator, operationTypeID);
+ // cast the value back to the array reference type
+ codeStream.generateImplicitConversion(assignmentImplicitConversion);
+ }
+ // current stack is:
+ // field receiver value
+ if (valueRequired) {
+ if ((binding.type == LongBinding) || (binding.type == DoubleBinding)) {
+ codeStream.dup2_x2();
+ } else {
+ codeStream.dup_x2();
+ }
+ }
+ // current stack is:
+ // value field receiver value
+ ((CodeSnippetCodeStream) codeStream).generateEmulatedWriteAccessForField(
+ binding);
+ }
+ }
+
+ public void generatePostIncrement(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ CompoundAssignment postIncrement,
+ boolean valueRequired) {
+ boolean isStatic;
+ if (binding.canBeSeenBy(receiverType, this, currentScope)) {
+ receiver.generateCode(
+ currentScope,
+ codeStream,
+ !(isStatic = binding.isStatic()));
+ if (isStatic) {
+ codeStream.getstatic(binding);
+ } else {
+ codeStream.dup();
+ codeStream.getfield(binding);
+ }
+ if (valueRequired) {
+ if (isStatic) {
+ if ((binding.type == LongBinding) || (binding.type == DoubleBinding)) {
+ codeStream.dup2();
+ } else {
+ codeStream.dup();
+ }
+ } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value]
+ if ((binding.type == LongBinding) || (binding.type == DoubleBinding)) {
+ codeStream.dup2_x1();
+ } else {
+ codeStream.dup_x1();
+ }
+ }
+ }
+ codeStream.generateConstant(
+ postIncrement.expression.constant,
+ implicitConversion);
+ codeStream.sendOperator(postIncrement.operator, binding.type.id);
+ codeStream.generateImplicitConversion(
+ postIncrement.assignmentImplicitConversion);
+ fieldStore(codeStream, binding, null, false);
+ } else {
+ receiver.generateCode(
+ currentScope,
+ codeStream,
+ !(isStatic = binding.isStatic()));
+ if (binding.isStatic()) {
+ codeStream.aconst_null();
+ }
+ // the actual stack is: receiver
+ codeStream.dup();
+ // the actual stack is: receiver receiver
+ ((CodeSnippetCodeStream) codeStream).generateEmulatedReadAccessForField(
+ binding);
+ // the actual stack is: receiver value
+ // receiver value
+ // value receiver value dup_x1 or dup2_x1 if value required
+ // value value receiver value dup_x1 or dup2_x1
+ // value value receiver pop or pop2
+ // value value receiver field generateEmulationForField
+ // value value field receiver swap
+ // value field receiver value field receiver dup2_x1 or dup2_x2
+ // value field receiver value pop2
+ // value field receiver newvalue generate constant + op
+ // value store
+ if (valueRequired) {
+ if ((binding.type == LongBinding) || (binding.type == DoubleBinding)) {
+ codeStream.dup2_x1();
+ } else {
+ codeStream.dup_x1();
+ }
+ }
+ if ((binding.type == LongBinding) || (binding.type == DoubleBinding)) {
+ codeStream.dup2_x1();
+ codeStream.pop2();
+ } else {
+ codeStream.dup_x1();
+ codeStream.pop();
+ }
+ ((CodeSnippetCodeStream) codeStream).generateEmulationForField(binding);
+ codeStream.swap();
+
+ if ((binding.type == LongBinding) || (binding.type == DoubleBinding)) {
+ codeStream.dup2_x2();
+ } else {
+ codeStream.dup2_x1();
+ }
+ codeStream.pop2();
+
+ codeStream.generateConstant(
+ postIncrement.expression.constant,
+ implicitConversion);
+ codeStream.sendOperator(postIncrement.operator, binding.type.id);
+ codeStream.generateImplicitConversion(
+ postIncrement.assignmentImplicitConversion);
+ ((CodeSnippetCodeStream) codeStream).generateEmulatedWriteAccessForField(
+ binding);
+ }
+ }
+
+ /*
+ * No need to emulate access to protected fields since not implicitly accessed
+ */
+ public void manageSyntheticReadAccessIfNecessary(BlockScope currentScope) {
+ // nothing to do. The private access will be managed through the code generation
+ }
+
+ /*
+ * No need to emulate access to protected fields since not implicitly accessed
+ */
+ public void manageSyntheticWriteAccessIfNecessary(BlockScope currentScope) {
+ // nothing to do. The private access will be managed through the code generation
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ // Answer the signature type of the field.
+ // constants are propaged when the field is final
+ // and initialized with a (compile time) constant
+
+ // regular receiver reference
+ receiverType = receiver.resolveType(scope);
+ if (receiverType == null) {
+ constant = NotAConstant;
+ return null;
+ }
+ // the case receiverType.isArrayType and token = 'length' is handled by the scope API
+ binding = scope.getField(receiverType, token, this);
+ FieldBinding firstAttempt = binding;
+ boolean isNotVisible = false;
+ if (!binding.isValidBinding()) {
+ if (binding instanceof ProblemFieldBinding
+ && ((ProblemFieldBinding) binding).problemId() == NotVisible) {
+ isNotVisible = true;
+ if (this.evaluationContext.declaringTypeName != null) {
+ delegateThis = scope.getField(scope.enclosingSourceType(), DELEGATE_THIS, this);
+ if (delegateThis == null) {
+ ; // if not found then internal error, field should have been found
+ constant = NotAConstant;
+ scope.problemReporter().invalidField(this, receiverType);
+ return null;
+ }
+ } else {
+ constant = NotAConstant;
+ scope.problemReporter().invalidField(this, receiverType);
+ return null;
+ }
+ CodeSnippetScope localScope = new CodeSnippetScope(scope);
+ binding = localScope.getFieldForCodeSnippet(delegateThis.type, token, this);
+ }
+ }
+
+ if (!binding.isValidBinding()) {
+ constant = NotAConstant;
+ if (isNotVisible) {
+ binding = firstAttempt;
+ }
+ scope.problemReporter().invalidField(this, receiverType);
+ return null;
+ }
+
+ if (isFieldUseDeprecated(binding, scope))
+ scope.problemReporter().deprecatedField(binding, this);
+
+ // check for this.x in static is done in the resolution of the receiver
+ constant =
+ FieldReference.getConstantFor(
+ binding,
+ receiver == ThisReference.ThisImplicit,
+ this,
+ 0);
+ if (!receiver.isThis())
+ constant = NotAConstant;
+
+ // if the binding declaring class is not visible, need special action
+ // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
+ if (binding.declaringClass != receiverType
+ && binding.declaringClass != null // array.length
+ && binding.constant == NotAConstant
+ && !binding.declaringClass.canBeSeenBy(scope))
+ binding = new FieldBinding(binding, (ReferenceBinding) receiverType);
+ return binding.type;
+ }
+
+}
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
new file mode 100644
index 0000000000..1d69b8b042
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java
@@ -0,0 +1,276 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
+
+public class CodeSnippetMessageSend
+ extends MessageSend
+ implements ProblemReasons, EvaluationConstants {
+ EvaluationContext evaluationContext;
+ FieldBinding delegateThis;
+ TypeBinding receiverType;
+ /**
+ * CodeSnippetMessageSend constructor comment.
+ */
+ public CodeSnippetMessageSend(EvaluationContext evaluationContext) {
+ this.evaluationContext = evaluationContext;
+ }
+
+ /**
+ * MessageSend code generation
+ *
+ * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param valueRequired boolean
+ */
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+
+ int pc = codeStream.position;
+
+ if (binding.canBeSeenBy(receiverType, this, currentScope)) {
+ // generate receiver/enclosing instance access
+ boolean isStatic = binding.isStatic();
+ // outer access ?
+ if (!isStatic && ((bits & DepthMASK) != 0)) {
+ // outer method can be reached through emulation
+ Object[] path =
+ currentScope.getExactEmulationPath(
+ currentScope.enclosingSourceType().enclosingTypeAt(
+ (bits & DepthMASK) >> DepthSHIFT));
+ if (path == null) {
+ // emulation was not possible (should not happen per construction)
+ currentScope.problemReporter().needImplementation();
+ } else {
+ codeStream.generateOuterAccess(path, this, currentScope);
+ }
+ } else {
+ receiver.generateCode(currentScope, codeStream, !isStatic);
+ }
+ // generate arguments
+ if (arguments != null) {
+ for (int i = 0, max = arguments.length; i < max; i++) {
+ arguments[i].generateCode(currentScope, codeStream, true);
+ }
+ }
+ // actual message invocation
+ if (isStatic) {
+ codeStream.invokestatic(binding);
+ } else {
+ if (receiver.isSuper()) {
+ codeStream.invokespecial(binding);
+ } else {
+ if (binding.declaringClass.isInterface()) {
+ codeStream.invokeinterface(binding);
+ } else {
+ codeStream.invokevirtual(binding);
+ }
+ }
+ }
+ } else {
+ ((CodeSnippetCodeStream) codeStream).generateEmulationForMethod(
+ currentScope,
+ binding);
+ // generate receiver/enclosing instance access
+ boolean isStatic = binding.isStatic();
+ // outer access ?
+ if (!isStatic && ((bits & DepthMASK) != 0)) {
+ // not supported yet
+ currentScope.problemReporter().needImplementation();
+ } else {
+ receiver.generateCode(currentScope, codeStream, !isStatic);
+ }
+ if (isStatic) {
+ // we need an object on the stack which is ignored for the method invocation
+ codeStream.aconst_null();
+ }
+ // generate arguments
+ if (arguments != null) {
+ int argsLength = arguments.length;
+ codeStream.generateInlinedValue(argsLength);
+ codeStream.newArray(
+ currentScope,
+ new ArrayBinding(currentScope.getType(TypeBinding.JAVA_LANG_OBJECT), 1));
+ codeStream.dup();
+ for (int i = 0; i < argsLength; i++) {
+ codeStream.generateInlinedValue(i);
+ arguments[i].generateCode(currentScope, codeStream, true);
+ if (binding.parameters[i].isBaseType()) {
+ codeStream.generateObjectWrapperForType(binding.parameters[i]);
+ }
+ codeStream.aastore();
+ if (i < argsLength - 1) {
+ codeStream.dup();
+ }
+ }
+ } else {
+ codeStream.generateInlinedValue(0);
+ codeStream.newArray(
+ currentScope,
+ new ArrayBinding(currentScope.getType(TypeBinding.JAVA_LANG_OBJECT), 1));
+ }
+ ((CodeSnippetCodeStream) codeStream).invokeJavaLangReflectMethodInvoke();
+
+ // convert the return value to the appropriate type for primitive types
+ if (binding.returnType.isBaseType()) {
+ int typeID = binding.returnType.id;
+ if (typeID == T_void) {
+ // remove the null from the stack
+ codeStream.pop();
+ }
+ ((CodeSnippetCodeStream) codeStream).checkcast(typeID);
+ ((CodeSnippetCodeStream) codeStream).getBaseTypeValue(typeID);
+ } else {
+ codeStream.checkcast(binding.returnType);
+ }
+ }
+ // operation on the returned value
+ if (valueRequired) {
+ // implicit conversion if necessary
+ codeStream.generateImplicitConversion(implicitConversion);
+ } else {
+ // pop return value if any
+ switch (binding.returnType.id) {
+ case T_long :
+ case T_double :
+ codeStream.pop2();
+ break;
+ case T_void :
+ break;
+ default :
+ codeStream.pop();
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
+ }
+
+ public void manageSyntheticAccessIfNecessary(BlockScope currentScope) {
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+ // Answer the signature return type
+ // Base type promotion
+
+ constant = NotAConstant;
+ receiverType = receiver.resolveType(scope);
+ // will check for null after args are resolved
+ TypeBinding[] argumentTypes = NoParameters;
+ if (arguments != null) {
+ boolean argHasError = false; // typeChecks all arguments
+ int length = arguments.length;
+ argumentTypes = new TypeBinding[length];
+ for (int i = 0; i < length; i++)
+ if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null)
+ argHasError = true;
+ if (argHasError)
+ return null;
+ }
+ if (receiverType == null)
+ return null;
+
+ // base type cannot receive any message
+ if (receiverType.isBaseType()) {
+ scope.problemReporter().errorNoMethodFor(this, receiverType, argumentTypes);
+ return null;
+ }
+
+ binding =
+ receiver == ThisReference.ThisImplicit
+ ? scope.getImplicitMethod(selector, argumentTypes, this)
+ : scope.getMethod(receiverType, selector, argumentTypes, this);
+ if (!binding.isValidBinding()) {
+ if (binding instanceof ProblemMethodBinding
+ && ((ProblemMethodBinding) binding).problemId() == NotVisible) {
+ if (this.evaluationContext.declaringTypeName != null) {
+ delegateThis = scope.getField(scope.enclosingSourceType(), DELEGATE_THIS, this);
+ if (delegateThis == null) {
+ ; // if not found then internal error, field should have been found
+ constant = NotAConstant;
+ scope.problemReporter().invalidMethod(this, binding);
+ return null;
+ }
+ } else {
+ constant = NotAConstant;
+ scope.problemReporter().invalidMethod(this, binding);
+ return null;
+ }
+ CodeSnippetScope localScope = new CodeSnippetScope(scope);
+ MethodBinding privateBinding =
+ receiver instanceof CodeSnippetThisReference
+ && ((CodeSnippetThisReference) receiver).isImplicit
+ ? localScope.getImplicitMethod(
+ (ReferenceBinding) delegateThis.type,
+ selector,
+ argumentTypes,
+ this)
+ : localScope.getMethod(delegateThis.type, selector, argumentTypes, this);
+ if (!privateBinding.isValidBinding()) {
+ if (binding.declaringClass == null) {
+ if (receiverType instanceof ReferenceBinding) {
+ binding.declaringClass = (ReferenceBinding) receiverType;
+ } else { // really bad error ....
+ scope.problemReporter().errorNoMethodFor(this, receiverType, argumentTypes);
+ return null;
+ }
+ }
+ scope.problemReporter().invalidMethod(this, binding);
+ return null;
+ } else {
+ binding = privateBinding;
+ }
+ } else {
+ if (binding.declaringClass == null) {
+ if (receiverType instanceof ReferenceBinding) {
+ binding.declaringClass = (ReferenceBinding) receiverType;
+ } else { // really bad error ....
+ scope.problemReporter().errorNoMethodFor(this, receiverType, argumentTypes);
+ return null;
+ }
+ }
+ scope.problemReporter().invalidMethod(this, binding);
+ return null;
+ }
+ }
+ if (!binding.isStatic()) {
+ // the "receiver" must not be a type, i.e. a NameReference that the TC has bound to a Type
+ if (receiver instanceof NameReference) {
+ if ((((NameReference) receiver).bits & BindingIds.TYPE) != 0) {
+ scope.problemReporter().mustUseAStaticMethod(this, binding);
+ return null;
+ }
+ }
+ }
+ if (arguments != null)
+ for (int i = 0; i < arguments.length; i++)
+ arguments[i].implicitWidening(binding.parameters[i], argumentTypes[i]);
+
+ //-------message send that are known to fail at compile time-----------
+ if (binding.isAbstract()) {
+ if (receiver.isSuper()) {
+ scope.problemReporter().cannotDireclyInvokeAbstractMethod(this, binding);
+ return null;
+ }
+ // abstract private methods cannot occur nor abstract static............
+ }
+ if (isMethodUseDeprecated(binding, scope))
+ scope.problemReporter().deprecatedMethod(binding, this);
+ // if the binding declaring class is not visible, need special action
+ // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
+ if (binding.declaringClass != receiverType
+ && !binding.declaringClass.canBeSeenBy(scope))
+ binding = new MethodBinding(binding, (ReferenceBinding) receiverType);
+ return binding.returnType;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetParser.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetParser.java
new file mode 100644
index 0000000000..a03f677395
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetParser.java
@@ -0,0 +1,745 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.parser.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+/**
+ * A parser for code snippets.
+ */
+public class CodeSnippetParser extends Parser implements EvaluationConstants {
+ int codeSnippetStart, codeSnippetEnd;
+ boolean hasRecoveredOnExpression;
+ int problemCountBeforeRecovery = 0;
+ int lastStatement = -1; // end of last top level statement
+
+ EvaluationContext evaluationContext;
+ /**
+ * Creates a new code snippet parser.
+ */
+ public CodeSnippetParser(
+ ProblemReporter problemReporter,
+ EvaluationContext evaluationContext,
+ boolean optimizeStringLiterals,
+ int codeSnippetStart,
+ int codeSnippetEnd) {
+ super(problemReporter, optimizeStringLiterals);
+ this.codeSnippetStart = codeSnippetStart;
+ this.codeSnippetEnd = codeSnippetEnd;
+ this.evaluationContext = evaluationContext;
+ }
+
+ protected void classInstanceCreation(boolean alwaysQualified) {
+ // ClassInstanceCreationExpression ::= 'new' ClassType '(' ArgumentListopt ')' ClassBodyopt
+
+ // ClassBodyopt produces a null item on the astStak if it produces NO class body
+ // An empty class body produces a 0 on the length stack.....
+
+ AllocationExpression alloc;
+ int length;
+ if (((length = astLengthStack[astLengthPtr--]) == 1)
+ && (astStack[astPtr] == null)) {
+ //NO ClassBody
+ astPtr--;
+ if (alwaysQualified) {
+ alloc = new QualifiedAllocationExpression();
+ } else {
+ alloc = new CodeSnippetAllocationExpression(evaluationContext);
+ }
+ alloc.sourceEnd = endPosition; //the position has been stored explicitly
+
+ if ((length = expressionLengthStack[expressionLengthPtr--]) != 0) {
+ expressionPtr -= length;
+ System.arraycopy(
+ expressionStack,
+ expressionPtr + 1,
+ alloc.arguments = new Expression[length],
+ 0,
+ length);
+ }
+ alloc.type = getTypeReference(0);
+ //the default constructor with the correct number of argument
+ //will be created and added by the TC (see createsInternalConstructorWithBinding)
+ alloc.sourceStart = intStack[intPtr--];
+ pushOnExpressionStack(alloc);
+ } else {
+ dispatchDeclarationInto(length);
+ AnonymousLocalTypeDeclaration anonymousTypeDeclaration =
+ (AnonymousLocalTypeDeclaration) astStack[astPtr];
+ anonymousTypeDeclaration.declarationSourceEnd = endStatementPosition;
+ astPtr--;
+ astLengthPtr--;
+ }
+ }
+
+ protected void consumeClassDeclaration() {
+ super.consumeClassDeclaration();
+ /* recovery */
+ recordLastStatementIfNeeded();
+ }
+
+ protected void consumeClassHeaderName() {
+ // ClassHeaderName ::= Modifiersopt 'class' 'Identifier'
+ TypeDeclaration typeDecl;
+ int length;
+ if (nestedMethod[nestedType] == 0) {
+ if (nestedType != 0) {
+ typeDecl = new MemberTypeDeclaration();
+ } else {
+ typeDecl = new CodeSnippetTypeDeclaration();
+ }
+ } else {
+ // Record that the block has a declaration for local types
+ typeDecl = new LocalTypeDeclaration();
+ blockReal();
+ }
+
+ //highlight the name of the type
+ long pos = identifierPositionStack[identifierPtr];
+ typeDecl.sourceEnd = (int) pos;
+ typeDecl.sourceStart = (int) (pos >>> 32);
+ typeDecl.name = identifierStack[identifierPtr--];
+ identifierLengthPtr--;
+
+ //compute the declaration source too
+ typeDecl.declarationSourceStart = intStack[intPtr--];
+ // 'class' and 'interface' push an int position
+ typeDecl.modifiersSourceStart = intStack[intPtr--];
+ typeDecl.modifiers = intStack[intPtr--];
+ if (typeDecl.modifiersSourceStart >= 0) {
+ typeDecl.declarationSourceStart = typeDecl.modifiersSourceStart;
+ }
+ typeDecl.bodyStart = typeDecl.sourceEnd + 1;
+ pushOnAstStack(typeDecl);
+
+ listLength = 0; // will be updated when reading super-interfaces
+ // recovery
+ if (currentElement != null) {
+ lastCheckPoint = typeDecl.bodyStart;
+ currentElement = currentElement.add(typeDecl, 0);
+ lastIgnoredToken = -1;
+ }
+ }
+
+ protected void consumeEmptyStatement() {
+ super.consumeEmptyStatement();
+ /* recovery */
+ recordLastStatementIfNeeded();
+ }
+
+ protected void consumeExpressionStatement() {
+ super.consumeExpressionStatement();
+ /* recovery */
+ recordLastStatementIfNeeded();
+ }
+
+ protected void consumeFieldAccess(boolean isSuperAccess) {
+ // FieldAccess ::= Primary '.' 'Identifier'
+ // FieldAccess ::= 'super' '.' 'Identifier'
+
+ FieldReference fr =
+ new CodeSnippetFieldReference(
+ identifierStack[identifierPtr],
+ identifierPositionStack[identifierPtr--],
+ evaluationContext);
+ identifierLengthPtr--;
+ if (isSuperAccess) {
+ //considerates the fieldReference beginning at the 'super' ....
+ fr.sourceStart = intStack[intPtr--];
+ fr.receiver = new SuperReference(fr.sourceStart, endPosition);
+ pushOnExpressionStack(fr);
+ } else {
+ //optimize push/pop
+ if ((fr.receiver = expressionStack[expressionPtr]).isThis()) {
+ //fieldreference begins at the this
+ fr.sourceStart = fr.receiver.sourceStart;
+ }
+ expressionStack[expressionPtr] = fr;
+ }
+ }
+
+ protected void consumeInterfaceHeaderName() {
+ // InterfaceHeaderName ::= Modifiersopt 'interface' 'Identifier'
+ TypeDeclaration typeDecl;
+ int length;
+ if (nestedMethod[nestedType] == 0) {
+ if (nestedType != 0) {
+ typeDecl = new MemberTypeDeclaration();
+ } else {
+ typeDecl = new CodeSnippetTypeDeclaration();
+ }
+ } else {
+ // Record that the block has a declaration for local types
+ typeDecl = new LocalTypeDeclaration();
+ blockReal();
+ }
+
+ //highlight the name of the type
+ long pos = identifierPositionStack[identifierPtr];
+ typeDecl.sourceEnd = (int) pos;
+ typeDecl.sourceStart = (int) (pos >>> 32);
+ typeDecl.name = identifierStack[identifierPtr--];
+ identifierLengthPtr--;
+
+ //compute the declaration source too
+ typeDecl.declarationSourceStart = intStack[intPtr--];
+ // 'class' and 'interface' push an int position
+ typeDecl.modifiersSourceStart = intStack[intPtr--];
+ typeDecl.modifiers = intStack[intPtr--];
+ if (typeDecl.modifiersSourceStart >= 0) {
+ typeDecl.declarationSourceStart = typeDecl.modifiersSourceStart;
+ }
+ typeDecl.bodyStart = typeDecl.sourceEnd + 1;
+ pushOnAstStack(typeDecl);
+ listLength = 0; // will be updated when reading super-interfaces
+ // recovery
+ if (currentElement != null) { // is recovering
+ lastCheckPoint = typeDecl.bodyStart;
+ currentElement = currentElement.add(typeDecl, 0);
+ lastIgnoredToken = -1;
+ }
+ }
+
+ protected void consumeLocalVariableDeclarationStatement() {
+ super.consumeLocalVariableDeclarationStatement();
+ /* recovery */
+ recordLastStatementIfNeeded();
+ }
+
+ /**
+ * In case emulating local variables, wrap the (recovered) statements inside a
+ * try statement so as to achieve local state commiting (copy local vars back to fields).
+ * The CSToCuMapper could not be used, since it could have interfered with
+ * the syntax recovery specific to code snippets.
+ */
+ protected void consumeMethodDeclaration(boolean isNotAbstract) {
+ // MethodDeclaration ::= MethodHeader MethodBody
+ // AbstractMethodDeclaration ::= MethodHeader ';'
+
+ super.consumeMethodDeclaration(isNotAbstract);
+
+ // now we know that we have a method declaration at the top of the ast stack
+ MethodDeclaration methodDecl = (MethodDeclaration) astStack[astPtr];
+
+ // automatically wrap the last statement inside a return statement, if it is an expression
+ // support have to be defined at toplevel only
+ if (this.isTopLevelType()) {
+ int last =
+ methodDecl.statements == null ? -1 : methodDecl.statements.length - 1;
+ if (last >= 0 && methodDecl.statements[last] instanceof Expression) {
+ Expression lastExpression = (Expression) methodDecl.statements[last];
+ methodDecl.statements[last] =
+ new CodeSnippetReturnStatement(
+ lastExpression,
+ lastExpression.sourceStart(),
+ lastExpression.sourceEnd(),
+ evaluationContext);
+ }
+ }
+
+ int start = methodDecl.bodyStart - 1, end = start;
+ long position = (start << 32) + end;
+ long[] positions = new long[] { position };
+ if (this.evaluationContext.localVariableNames != null) {
+
+ int varCount = this.evaluationContext.localVariableNames.length;
+ // n local decls+ try statement
+
+ // generate n local variable declarations: [type] [name] = val$[name];
+ Statement[] newStatements = new Statement[varCount + 1];
+ for (int i = 0; i < varCount; i++) {
+ char[] trimmedTypeName = this.evaluationContext.localVariableTypeNames[i];
+ int nameEnd = CharOperation.indexOf('[', trimmedTypeName);
+ if (nameEnd >= 0)
+ trimmedTypeName = CharOperation.subarray(trimmedTypeName, 0, nameEnd);
+ nameEnd = CharOperation.indexOf(' ', trimmedTypeName);
+ if (nameEnd >= 0)
+ trimmedTypeName = CharOperation.subarray(trimmedTypeName, 0, nameEnd);
+
+ TypeReference typeReference =
+ new QualifiedTypeReference(
+ CharOperation.splitOn('.', trimmedTypeName),
+ positions);
+ int dimCount =
+ CharOperation.occurencesOf(
+ '[',
+ this.evaluationContext.localVariableTypeNames[i]);
+ if (dimCount > 0) {
+ typeReference = typeReference.copyDims(dimCount);
+ }
+ NameReference init =
+ new SingleNameReference(
+ CharOperation.concat(
+ LOCAL_VAR_PREFIX,
+ this.evaluationContext.localVariableNames[i]),
+ position);
+ LocalDeclaration declaration =
+ new LocalDeclaration(
+ init,
+ this.evaluationContext.localVariableNames[i],
+ start,
+ end);
+ declaration.type = typeReference;
+ declaration.modifiers = this.evaluationContext.localVariableModifiers[i];
+ newStatements[i] = declaration;
+ }
+
+ // generate try { [snippet] } finally { [save locals to fields] }
+ // try block
+ TryStatement tryStatement = new TryStatement();
+ Block tryBlock = new Block(methodDecl.explicitDeclarations);
+ tryBlock.sourceStart = start;
+ tryBlock.sourceEnd = end;
+ tryBlock.statements = methodDecl.statements; // snippet statements
+ tryStatement.tryBlock = tryBlock;
+ // finally block
+ Block finallyBlock = new Block(0);
+ finallyBlock.sourceStart = start;
+ finallyBlock.sourceEnd = end;
+ finallyBlock.statements = new Statement[varCount];
+ for (int i = 0; i < varCount; i++) {
+ finallyBlock.statements[i] =
+ new Assignment(
+ new SingleNameReference(
+ CharOperation.concat(
+ LOCAL_VAR_PREFIX,
+ this.evaluationContext.localVariableNames[i]),
+ position),
+ new SingleNameReference(
+ this.evaluationContext.localVariableNames[i],
+ position));
+ }
+ tryStatement.finallyBlock = finallyBlock;
+
+ newStatements[varCount] = tryStatement;
+ methodDecl.statements = newStatements;
+ }
+ }
+
+ protected void consumeMethodInvocationName() {
+ // MethodInvocation ::= Name '(' ArgumentListopt ')'
+
+ if (scanner.startPosition >= codeSnippetStart
+ && scanner.startPosition <= codeSnippetEnd + 1
+ && isTopLevelType()) {
+
+ // when the name is only an identifier...we have a message send to "this" (implicit)
+
+ MessageSend m = newMessageSend();
+ m.sourceEnd = rParenPos;
+ m.sourceStart =
+ (int) ((m.nameSourcePosition = identifierPositionStack[identifierPtr]) >>> 32);
+ m.selector = identifierStack[identifierPtr--];
+ if (identifierLengthStack[identifierLengthPtr] == 1) {
+ m.receiver = new CodeSnippetThisReference(0, 0, evaluationContext, true);
+ identifierLengthPtr--;
+ } else {
+ identifierLengthStack[identifierLengthPtr]--;
+ m.receiver = getUnspecifiedReference();
+ m.sourceStart = m.receiver.sourceStart;
+ }
+ pushOnExpressionStack(m);
+ } else {
+ super.consumeMethodInvocationName();
+ }
+ }
+
+ protected void consumePrimaryNoNewArrayThis() {
+ // PrimaryNoNewArray ::= 'this'
+
+ if (scanner.startPosition >= codeSnippetStart
+ && scanner.startPosition <= codeSnippetEnd + 1
+ && isTopLevelType()) {
+ pushOnExpressionStack(
+ new CodeSnippetThisReference(
+ intStack[intPtr--],
+ endPosition,
+ evaluationContext,
+ false));
+ } else {
+ super.consumePrimaryNoNewArrayThis();
+ }
+ }
+
+ protected void consumeStatementBreak() {
+ super.consumeStatementBreak();
+ /* recovery */
+ recordLastStatementIfNeeded();
+ }
+
+ protected void consumeStatementBreakWithLabel() {
+ super.consumeStatementBreakWithLabel();
+ /* recovery */
+ recordLastStatementIfNeeded();
+ }
+
+ protected void consumeStatementCatch() {
+ super.consumeStatementCatch();
+ /* recovery */
+ recordLastStatementIfNeeded();
+ }
+
+ protected void consumeStatementContinue() {
+ super.consumeStatementContinue();
+ /* recovery */
+ recordLastStatementIfNeeded();
+ }
+
+ protected void consumeStatementContinueWithLabel() {
+ super.consumeStatementContinueWithLabel();
+ /* recovery */
+ recordLastStatementIfNeeded();
+ }
+
+ protected void consumeStatementDo() {
+ super.consumeStatementDo();
+ /* recovery */
+ recordLastStatementIfNeeded();
+ }
+
+ protected void consumeStatementFor() {
+ super.consumeStatementFor();
+ /* recovery */
+ recordLastStatementIfNeeded();
+ }
+
+ protected void consumeStatementIfNoElse() {
+ super.consumeStatementIfNoElse();
+ /* recovery */
+ recordLastStatementIfNeeded();
+ }
+
+ protected void consumeStatementIfWithElse() {
+ super.consumeStatementIfWithElse();
+ /* recovery */
+ recordLastStatementIfNeeded();
+ }
+
+ protected void consumeStatementLabel() {
+ super.consumeStatementLabel();
+ /* recovery */
+ recordLastStatementIfNeeded();
+ }
+
+ protected void consumeStatementReturn() {
+ // ReturnStatement ::= 'return' Expressionopt ';'
+
+ // returned value intercepted by code snippet
+ // support have to be defined at toplevel only
+ if ((this.hasRecoveredOnExpression
+ || (scanner.startPosition >= codeSnippetStart
+ && scanner.startPosition <= codeSnippetEnd + 1))
+ && this.expressionLengthStack[this.expressionLengthPtr] != 0
+ && isTopLevelType()) {
+ this.expressionLengthPtr--;
+ Expression expression = this.expressionStack[this.expressionPtr--];
+ pushOnAstStack(
+ new CodeSnippetReturnStatement(
+ expression,
+ expression.sourceStart(),
+ expression.sourceEnd(),
+ evaluationContext));
+ } else {
+ super.consumeStatementReturn();
+ }
+ /* recovery */
+ recordLastStatementIfNeeded();
+ }
+
+ protected void consumeStatementSwitch() {
+ super.consumeStatementSwitch();
+ /* recovery */
+ recordLastStatementIfNeeded();
+ }
+
+ protected void consumeStatementSynchronized() {
+ super.consumeStatementSynchronized();
+ /* recovery */
+ recordLastStatementIfNeeded();
+ }
+
+ protected void consumeStatementThrow() {
+ super.consumeStatementThrow();
+ /* recovery */
+ recordLastStatementIfNeeded();
+ }
+
+ protected void consumeStatementTry(boolean arg_0) {
+ super.consumeStatementTry(arg_0);
+ /* recovery */
+ recordLastStatementIfNeeded();
+ }
+
+ protected void consumeStatementWhile() {
+ super.consumeStatementWhile();
+ /* recovery */
+ recordLastStatementIfNeeded();
+ }
+
+ protected CompilationUnitDeclaration endParse(int act) {
+ if (this.hasRecoveredOnExpression) {
+ CompilationResult unitResult = this.compilationUnit.compilationResult;
+ if (act != ERROR_ACTION) { // expression recovery worked
+ // flush previously recorded problems
+ for (int i = 0; i < unitResult.problemCount; i++) {
+ unitResult.problems[i] = null; // discard problem
+ }
+ unitResult.problemCount = 0;
+ if (this.referenceContext instanceof AbstractMethodDeclaration) {
+ ((AbstractMethodDeclaration) this.referenceContext).ignoreFurtherInvestigation =
+ false;
+ }
+ if (this.referenceContext instanceof CompilationUnitDeclaration) {
+ ((CompilationUnitDeclaration) this.referenceContext).ignoreFurtherInvestigation =
+ false;
+ }
+
+ // consume expresion as a return statement
+ consumeStatementReturn();
+ int fieldsCount =
+ (this.evaluationContext.localVariableNames == null
+ ? 0
+ : this.evaluationContext.localVariableNames.length)
+ + (this.evaluationContext.declaringTypeName == null ? 0 : 1);
+ if (this.astPtr > (this.diet ? 0 : 2 + fieldsCount)) {
+ // in diet mode, the ast stack was empty when we went for method body
+ // otherwise it contained the type, the generated fields for local variables,
+ // the generated field for 'this' and the method
+ consumeBlockStatements();
+ }
+ consumeMethodBody();
+ if (!this.diet) {
+ consumeMethodDeclaration(true);
+ if (fieldsCount > 0) {
+ consumeClassBodyDeclarations();
+ }
+ consumeClassBodyDeclarationsopt();
+ consumeClassDeclaration();
+ consumeTypeDeclarationsopt();
+ consumeCompilationUnit();
+ }
+ this.lastAct = ACCEPT_ACTION;
+ } else {
+ // might have more than one error recorded:
+ // 1. during regular parse
+ // 2. during expression recovery
+ // -> must filter out one of them, the earliest one is less accurate
+ int maxRegularPos = 0, problemCount = unitResult.problemCount;
+ for (int i = 0; i < this.problemCountBeforeRecovery; i++) {
+ // skip unmatched bracket problems
+ if (unitResult.problems[i].getID() == ProblemIrritants.UnmatchedBracket)
+ continue;
+
+ int start = unitResult.problems[i].getSourceStart();
+ if (start > maxRegularPos && start <= this.codeSnippetEnd) {
+ maxRegularPos = start;
+ }
+ }
+ int maxRecoveryPos = 0;
+ for (int i = this.problemCountBeforeRecovery; i < problemCount; i++) {
+ // skip unmatched bracket problems
+ if (unitResult.problems[i].getID() == ProblemIrritants.UnmatchedBracket)
+ continue;
+
+ int start = unitResult.problems[i].getSourceStart();
+ if (start > maxRecoveryPos && start <= this.codeSnippetEnd) {
+ maxRecoveryPos = start;
+ }
+ }
+ if (maxRecoveryPos > maxRegularPos) {
+ System.arraycopy(
+ unitResult.problems,
+ this.problemCountBeforeRecovery,
+ unitResult.problems,
+ 0,
+ problemCount - this.problemCountBeforeRecovery);
+ unitResult.problemCount -= this.problemCountBeforeRecovery;
+ } else {
+ unitResult.problemCount -= (problemCount - this.problemCountBeforeRecovery);
+ }
+ for (int i = unitResult.problemCount; i < problemCount; i++) {
+ unitResult.problems[i] = null; // discard problem
+ }
+
+ }
+ }
+ return super.endParse(act);
+ }
+
+ protected NameReference getUnspecifiedReference() {
+ /* build a (unspecified) NameReference which may be qualified*/
+
+ if (scanner.startPosition >= codeSnippetStart
+ && scanner.startPosition <= codeSnippetEnd + 1) {
+ int length;
+ NameReference ref;
+ if ((length = identifierLengthStack[identifierLengthPtr--]) == 1)
+ // single variable reference
+ ref =
+ new CodeSnippetSingleNameReference(
+ identifierStack[identifierPtr],
+ identifierPositionStack[identifierPtr--],
+ this.evaluationContext);
+ else
+ //Qualified variable reference
+ {
+ char[][] tokens = new char[length][];
+ identifierPtr -= length;
+ System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length);
+ ref =
+ new CodeSnippetQualifiedNameReference(
+ tokens,
+ (int) (identifierPositionStack[identifierPtr + 1] >> 32),
+ // sourceStart
+ (int) identifierPositionStack[identifierPtr + length], evaluationContext);
+ // sourceEnd
+ };
+ return ref;
+ } else {
+ return super.getUnspecifiedReference();
+ }
+ }
+
+ protected NameReference getUnspecifiedReferenceOptimized() {
+ /* build a (unspecified) NameReference which may be qualified
+ The optimization occurs for qualified reference while we are
+ certain in this case the last item of the qualified name is
+ a field access. This optimization is IMPORTANT while it results
+ that when a NameReference is build, the type checker should always
+ look for that it is not a type reference */
+
+ if (scanner.startPosition >= codeSnippetStart
+ && scanner.startPosition <= codeSnippetEnd + 1) {
+ int length;
+ NameReference ref;
+ if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) {
+ // single variable reference
+ ref =
+ new CodeSnippetSingleNameReference(
+ identifierStack[identifierPtr],
+ identifierPositionStack[identifierPtr--],
+ this.evaluationContext);
+ ref.bits &= ~NameReference.RestrictiveFlagMASK;
+ ref.bits |= LOCAL | FIELD;
+ return ref;
+ }
+
+ //Qualified-variable-reference
+ //In fact it is variable-reference DOT field-ref , but it would result in a type
+ //conflict tha can be only reduce by making a superclass (or inetrface ) between
+ //nameReference and FiledReference or putting FieldReference under NameReference
+ //or else..........This optimisation is not really relevant so just leave as it is
+
+ char[][] tokens = new char[length][];
+ identifierPtr -= length;
+ System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length);
+ ref =
+ new CodeSnippetQualifiedNameReference(
+ tokens,
+ (int) (identifierPositionStack[identifierPtr + 1] >> 32),
+ // sourceStart
+ (int) identifierPositionStack[identifierPtr + length], evaluationContext);
+ // sourceEnd
+ ref.bits &= ~NameReference.RestrictiveFlagMASK;
+ ref.bits |= LOCAL | FIELD;
+ return ref;
+ } else {
+ return super.getUnspecifiedReferenceOptimized();
+ }
+ }
+
+ protected void ignoreExpressionAssignment() {
+ super.ignoreExpressionAssignment();
+ /* recovery */
+ recordLastStatementIfNeeded();
+ }
+
+ /**
+ * Returns whether we are parsing a top level type or not.
+ */
+ private boolean isTopLevelType() {
+ return this.nestedType == (this.diet ? 0 : 1);
+ }
+
+ protected MessageSend newMessageSend() {
+ // '(' ArgumentListopt ')'
+ // the arguments are on the expression stack
+
+ CodeSnippetMessageSend m = new CodeSnippetMessageSend(evaluationContext);
+ int length;
+ if ((length = expressionLengthStack[expressionLengthPtr--]) != 0) {
+ expressionPtr -= length;
+ System.arraycopy(
+ expressionStack,
+ expressionPtr + 1,
+ m.arguments = new Expression[length],
+ 0,
+ length);
+ };
+ return m;
+ }
+
+ /**
+ * Records the scanner position if we're parsing a top level type.
+ */
+ private void recordLastStatementIfNeeded() {
+ if ((isTopLevelType())
+ && (this.scanner.startPosition <= this.codeSnippetEnd)) {
+ this.lastStatement = this.scanner.startPosition;
+ }
+ }
+
+ protected void reportSyntaxError(int act, int currentKind, int stateStackTop) {
+ if (!this.diet) {
+ this.scanner.initialPosition = this.codeSnippetStart;
+ // for correct bracket match diagnosis
+ this.scanner.eofPosition = this.codeSnippetEnd + 1; // stop after expression
+ }
+ super.reportSyntaxError(act, currentKind, stateStackTop);
+ }
+
+ /*
+ * A syntax error was detected. If a method is being parsed, records the number of errors and
+ * attempts to restart from the last statement by going for an expression.
+ */
+ protected boolean resumeOnSyntaxError() {
+ if (this.diet
+ || this.hasRecoveredOnExpression) { // no reentering inside expression recovery
+ return super.resumeOnSyntaxError();
+ }
+
+ // record previous error, in case more accurate than potential one in expression recovery
+ // e.g. "return foo(a a); 1+3"
+ this.problemCountBeforeRecovery =
+ this.compilationUnit.compilationResult.problemCount;
+
+ // reposition for expression parsing
+ if (this.lastStatement < 0) {
+ this.lastStatement = this.codeSnippetStart;
+ // no statement reduced prior to error point
+ }
+ this.scanner.initialPosition = this.lastStatement;
+ this.scanner.startPosition = this.lastStatement;
+ this.scanner.currentPosition = this.lastStatement;
+ this.scanner.eofPosition = this.codeSnippetEnd + 1; // stop after expression
+ this.scanner.commentPtr = -1;
+
+ // reset stacks in consistent state
+ this.expressionPtr = -1;
+ this.identifierPtr = -1;
+ this.identifierLengthPtr = -1;
+
+ // go for the exprssion
+ goForExpression();
+ this.hasRecoveredOnExpression = true;
+ this.hasReportedError = false;
+ return true;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetQualifiedNameReference.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetQualifiedNameReference.java
new file mode 100644
index 0000000000..0d12775794
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetQualifiedNameReference.java
@@ -0,0 +1,659 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+
+public class CodeSnippetQualifiedNameReference
+ extends QualifiedNameReference
+ implements EvaluationConstants, InvocationSite, ProblemReasons {
+
+ EvaluationContext evaluationContext;
+ FieldBinding delegateThis;
+ TypeBinding receiverType;
+ /**
+ * CodeSnippetQualifiedNameReference constructor comment.
+ * @param sources char[][]
+ * @param sourceStart int
+ * @param sourceEnd int
+ */
+ public CodeSnippetQualifiedNameReference(
+ char[][] sources,
+ int sourceStart,
+ int sourceEnd,
+ EvaluationContext evaluationContext) {
+ super(sources, sourceStart, sourceEnd);
+ this.evaluationContext = evaluationContext;
+ }
+
+ /**
+ * Check and/or redirect the field access to the delegate receiver if any
+ */
+ public TypeBinding checkFieldAccess(BlockScope scope) {
+ // check for forward references
+ bits &= ~RestrictiveFlagMASK; // clear bits
+ bits |= FIELD;
+ return getOtherFieldBindings(scope);
+ }
+
+ public void generateAssignment(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Assignment assignment,
+ boolean valueRequired) {
+ generateReadSequence(currentScope, codeStream, true);
+ if (lastFieldBinding
+ .canBeSeenBy(getReceiverType(currentScope), this, currentScope)) {
+ // the last field access is a write access
+ assignment.expression.generateCode(currentScope, codeStream, true);
+ fieldStore(codeStream, lastFieldBinding, null, valueRequired);
+ } else {
+ ((CodeSnippetCodeStream) codeStream).generateEmulationForField(
+ lastFieldBinding);
+ codeStream.swap();
+ assignment.expression.generateCode(currentScope, codeStream, true);
+ if (valueRequired) {
+ if ((lastFieldBinding.type == LongBinding)
+ || (lastFieldBinding.type == DoubleBinding)) {
+ codeStream.dup2_x2();
+ } else {
+ codeStream.dup_x2();
+ }
+ }
+ ((CodeSnippetCodeStream) codeStream).generateEmulatedWriteAccessForField(
+ lastFieldBinding);
+ }
+ if (valueRequired) {
+ codeStream.generateImplicitConversion(assignment.implicitConversion);
+ }
+ }
+
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ if (constant != NotAConstant) {
+ if (valueRequired) {
+ codeStream.generateConstant(constant, implicitConversion);
+ }
+ } else {
+ generateReadSequence(currentScope, codeStream, valueRequired);
+ if (valueRequired) {
+ if (lastFieldBinding.declaringClass == null) { // array length
+ codeStream.arraylength();
+ codeStream.generateImplicitConversion(implicitConversion);
+ } else {
+ if (lastFieldBinding.constant != NotAConstant) {
+ // inline the last field constant
+ codeStream.generateConstant(lastFieldBinding.constant, implicitConversion);
+ } else {
+ if (lastFieldBinding
+ .canBeSeenBy(getReceiverType(currentScope), this, currentScope)) {
+ if (lastFieldBinding.isStatic()) {
+ codeStream.getstatic(lastFieldBinding);
+ } else {
+ codeStream.getfield(lastFieldBinding);
+ }
+ } else {
+ ((CodeSnippetCodeStream) codeStream).generateEmulatedReadAccessForField(
+ lastFieldBinding);
+ }
+ codeStream.generateImplicitConversion(implicitConversion);
+ }
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public void generateCompoundAssignment(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Expression expression,
+ int operator,
+ int assignmentImplicitConversion,
+ boolean valueRequired) {
+
+ generateReadSequence(currentScope, codeStream, true);
+ if (lastFieldBinding
+ .canBeSeenBy(getReceiverType(currentScope), this, currentScope)) {
+ if (lastFieldBinding.isStatic()) {
+ codeStream.getstatic(lastFieldBinding);
+ } else {
+ codeStream.dup();
+ codeStream.getfield(lastFieldBinding);
+ }
+ // the last field access is a write access
+ // perform the actual compound operation
+ int operationTypeID;
+ if ((operationTypeID = implicitConversion >> 4) == T_String) {
+ codeStream.generateStringAppend(currentScope, null, expression);
+ } else {
+ // promote the array reference to the suitable operation type
+ codeStream.generateImplicitConversion(implicitConversion);
+ // generate the increment value (will by itself be promoted to the operation value)
+ if (expression == IntLiteral.One) { // prefix operation
+ codeStream.generateConstant(expression.constant, implicitConversion);
+ } else {
+ expression.generateCode(currentScope, codeStream, true);
+ }
+ // perform the operation
+ codeStream.sendOperator(operator, operationTypeID);
+ // cast the value back to the array reference type
+ codeStream.generateImplicitConversion(assignmentImplicitConversion);
+ }
+ // actual assignment
+ fieldStore(codeStream, lastFieldBinding, null, valueRequired);
+ } else {
+ if (lastFieldBinding.isStatic()) {
+ ((CodeSnippetCodeStream) codeStream).generateEmulationForField(
+ lastFieldBinding);
+ codeStream.swap();
+ codeStream.aconst_null();
+ codeStream.swap();
+
+ ((CodeSnippetCodeStream) codeStream).generateEmulatedReadAccessForField(
+ lastFieldBinding);
+ } else {
+ ((CodeSnippetCodeStream) codeStream).generateEmulationForField(
+ lastFieldBinding);
+ codeStream.swap();
+ codeStream.dup();
+
+ ((CodeSnippetCodeStream) codeStream).generateEmulatedReadAccessForField(
+ lastFieldBinding);
+ }
+ // the last field access is a write access
+ // perform the actual compound operation
+ int operationTypeID;
+ if ((operationTypeID = implicitConversion >> 4) == T_String) {
+ codeStream.generateStringAppend(currentScope, null, expression);
+ } else {
+ // promote the array reference to the suitable operation type
+ codeStream.generateImplicitConversion(implicitConversion);
+ // generate the increment value (will by itself be promoted to the operation value)
+ if (expression == IntLiteral.One) { // prefix operation
+ codeStream.generateConstant(expression.constant, implicitConversion);
+ } else {
+ expression.generateCode(currentScope, codeStream, true);
+ }
+ // perform the operation
+ codeStream.sendOperator(operator, operationTypeID);
+ // cast the value back to the array reference type
+ codeStream.generateImplicitConversion(assignmentImplicitConversion);
+ }
+ // actual assignment
+
+ // current stack is:
+ // field receiver value
+ if (valueRequired) {
+ if ((lastFieldBinding.type == LongBinding)
+ || (lastFieldBinding.type == DoubleBinding)) {
+ codeStream.dup2_x2();
+ } else {
+ codeStream.dup_x2();
+ }
+ }
+ // current stack is:
+ // value field receiver value
+ ((CodeSnippetCodeStream) codeStream).generateEmulatedWriteAccessForField(
+ lastFieldBinding);
+ }
+ }
+
+ public void generatePostIncrement(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ CompoundAssignment postIncrement,
+ boolean valueRequired) {
+ generateReadSequence(currentScope, codeStream, true);
+
+ if (lastFieldBinding
+ .canBeSeenBy(getReceiverType(currentScope), this, currentScope)) {
+ if (lastFieldBinding.isStatic()) {
+ codeStream.getstatic(lastFieldBinding);
+ } else {
+ codeStream.dup();
+ codeStream.getfield(lastFieldBinding);
+ }
+ // duplicate the old field value
+ if (valueRequired) {
+ if (lastFieldBinding.isStatic()) {
+ if ((lastFieldBinding.type == LongBinding)
+ || (lastFieldBinding.type == DoubleBinding)) {
+ codeStream.dup2();
+ } else {
+ codeStream.dup();
+ }
+ } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value]
+ if ((lastFieldBinding.type == LongBinding)
+ || (lastFieldBinding.type == DoubleBinding)) {
+ codeStream.dup2_x1();
+ } else {
+ codeStream.dup_x1();
+ }
+ }
+ }
+ codeStream.generateConstant(
+ postIncrement.expression.constant,
+ implicitConversion);
+ codeStream.sendOperator(postIncrement.operator, lastFieldBinding.type.id);
+ codeStream.generateImplicitConversion(
+ postIncrement.assignmentImplicitConversion);
+
+ fieldStore(codeStream, lastFieldBinding, null, false);
+ } else {
+ ((CodeSnippetCodeStream) codeStream).generateEmulatedReadAccessForField(
+ lastFieldBinding);
+ if (valueRequired) {
+ if ((lastFieldBinding.type == LongBinding)
+ || (lastFieldBinding.type == DoubleBinding)) {
+ codeStream.dup2();
+ } else {
+ codeStream.dup();
+ }
+ }
+ ((CodeSnippetCodeStream) codeStream).generateEmulationForField(
+ lastFieldBinding);
+ if ((lastFieldBinding.type == LongBinding)
+ || (lastFieldBinding.type == DoubleBinding)) {
+ codeStream.dup_x2();
+ codeStream.pop();
+ if (lastFieldBinding.isStatic()) {
+ codeStream.aconst_null();
+ } else {
+ generateReadSequence(currentScope, codeStream, true);
+ }
+ codeStream.dup_x2();
+ codeStream.pop();
+ } else {
+ codeStream.dup_x1();
+ codeStream.pop();
+ if (lastFieldBinding.isStatic()) {
+ codeStream.aconst_null();
+ } else {
+ generateReadSequence(currentScope, codeStream, true);
+ }
+ codeStream.dup_x1();
+ codeStream.pop();
+ }
+ codeStream.generateConstant(
+ postIncrement.expression.constant,
+ implicitConversion);
+ codeStream.sendOperator(postIncrement.operator, lastFieldBinding.type.id);
+ codeStream.generateImplicitConversion(
+ postIncrement.assignmentImplicitConversion);
+ ((CodeSnippetCodeStream) codeStream).generateEmulatedWriteAccessForField(
+ lastFieldBinding);
+ }
+ }
+
+ /*
+ * Generate code for all bindings (local and fields) excluding the last one, which may then be generated code
+ * for a read or write access.
+ */
+ public void generateReadSequence(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+
+ // determine the rank until which we now we do not need any actual value for the field access
+ int otherBindingsCount = otherBindings == null ? 0 : otherBindings.length;
+ int indexOfFirstValueRequired;
+ if (valueRequired) {
+ indexOfFirstValueRequired = otherBindingsCount;
+ while (indexOfFirstValueRequired > 0) {
+ FieldBinding otherBinding = otherBindings[indexOfFirstValueRequired - 1];
+ if (otherBinding.isStatic() || otherBinding.constant != NotAConstant)
+ break; // no longer need any value before this point
+ indexOfFirstValueRequired--;
+ }
+ } else {
+ indexOfFirstValueRequired = otherBindingsCount + 1;
+ }
+ if (indexOfFirstValueRequired == 0) {
+ switch (bits & RestrictiveFlagMASK) {
+ case FIELD :
+ lastFieldBinding = (FieldBinding) binding;
+ // if first field is actually constant, we can inline it
+ if (lastFieldBinding.constant != NotAConstant) {
+ codeStream.generateConstant(lastFieldBinding.constant, 0);
+ // no implicit conversion
+ lastFieldBinding = null; // will not generate it again
+ break;
+ }
+ if (lastFieldBinding
+ .canBeSeenBy(getReceiverType(currentScope), this, currentScope)) {
+ if (!lastFieldBinding.isStatic()) {
+ if ((bits & DepthMASK) != 0) {
+ Object[] emulationPath =
+ currentScope.getExactEmulationPath(
+ currentScope.enclosingSourceType().enclosingTypeAt(
+ (bits & DepthMASK) >> DepthSHIFT));
+ if (emulationPath == null) {
+ // internal error, per construction we should have found it
+ currentScope.problemReporter().needImplementation();
+ } else {
+ codeStream.generateOuterAccess(emulationPath, this, currentScope);
+ }
+ } else {
+ generateReceiver(codeStream);
+ }
+ }
+ } else {
+ if (!lastFieldBinding.isStatic()) {
+ if ((bits & DepthMASK) != 0) {
+ // internal error, per construction we should have found it
+ // not yet supported
+ currentScope.problemReporter().needImplementation();
+ } else {
+ generateReceiver(codeStream);
+ }
+ } else {
+ codeStream.aconst_null();
+ }
+ }
+ break;
+ case LOCAL : // reading the first local variable
+ lastFieldBinding = null;
+ LocalVariableBinding localBinding = (LocalVariableBinding) binding;
+
+ // regular local variable read
+ if (localBinding.constant != NotAConstant) {
+ codeStream.generateConstant(localBinding.constant, 0);
+ // no implicit conversion
+ } else {
+ // outer local?
+ if ((bits & DepthMASK) != 0) {
+ // outer local can be reached either through a synthetic arg or a synthetic field
+ VariableBinding[] path = currentScope.getEmulationPath(localBinding);
+ if (path == null) {
+ // emulation was not possible (should not happen per construction)
+ currentScope.problemReporter().needImplementation();
+ } else {
+ codeStream.generateOuterAccess(path, this, currentScope);
+ }
+ } else {
+ codeStream.load(localBinding);
+ }
+ }
+ }
+ } else {
+ lastFieldBinding = null;
+ }
+ // all intermediate field accesses are read accesses
+ // only the last field binding is a write access
+ if (otherBindings != null) {
+ int start = indexOfFirstValueRequired == 0 ? 0 : indexOfFirstValueRequired - 1;
+ for (int i = start; i < otherBindingsCount; i++) {
+ if (lastFieldBinding != null) {
+ if (lastFieldBinding
+ .canBeSeenBy(getReceiverType(currentScope), this, currentScope)) {
+ if (lastFieldBinding.isStatic())
+ codeStream.getstatic(lastFieldBinding);
+ else
+ codeStream.getfield(lastFieldBinding);
+ } else {
+ ((CodeSnippetCodeStream) codeStream).generateEmulatedReadAccessForField(
+ lastFieldBinding);
+ }
+ }
+
+ lastFieldBinding = otherBindings[i];
+ if (lastFieldBinding != null
+ && !lastFieldBinding.canBeSeenBy(
+ getReceiverType(currentScope),
+ this,
+ currentScope)) {
+ if (lastFieldBinding.isStatic()) {
+ codeStream.aconst_null();
+ }
+ }
+ }
+ }
+ }
+
+ public void generateReceiver(CodeStream codeStream) {
+ codeStream.aload_0();
+ if (delegateThis != null)
+ codeStream.getfield(delegateThis); // delegated field access
+ }
+
+ public TypeBinding getOtherFieldBindings(BlockScope scope) {
+ // At this point restrictiveFlag may ONLY have two potential value : FIELD LOCAL (i.e cast <<(VariableBinding) binding>> is valid)
+
+ if ((bits & FIELD) != 0) {
+ if (!((FieldBinding) binding).isStatic()) {
+ //must check for the static status....
+ if (indexOfFirstFieldBinding == 1) {
+ //the field is the first token of the qualified reference....
+ if (scope.methodScope().isStatic) {
+ scope.problemReporter().staticFieldAccessToNonStaticVariable(
+ this,
+ (FieldBinding) binding);
+ return null;
+ }
+ } else { //accessing to a field using a type as "receiver" is allowed only with static field
+ scope.problemReporter().staticFieldAccessToNonStaticVariable(
+ this,
+ (FieldBinding) binding);
+ return null;
+ }
+ }
+ if (isFieldUseDeprecated((FieldBinding) binding, scope))
+ scope.problemReporter().deprecatedField((FieldBinding) binding, this);
+
+ // if the binding declaring class is not visible, need special action
+ // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
+ FieldBinding fieldBinding = (FieldBinding) binding;
+ if (delegateThis == null) {
+ if (fieldBinding.declaringClass != null
+ && fieldBinding.constant == NotAConstant
+ && !fieldBinding.declaringClass.canBeSeenBy(scope))
+ binding = new FieldBinding(fieldBinding, (ReferenceBinding) delegateThis.type);
+ } else {
+ CodeSnippetScope localScope = new CodeSnippetScope(scope);
+ if (fieldBinding.declaringClass != null
+ && fieldBinding.constant == NotAConstant
+ && !localScope.canBeSeenByForCodeSnippet(
+ fieldBinding.declaringClass,
+ (ReferenceBinding) delegateThis.type))
+ binding = new FieldBinding(fieldBinding, (ReferenceBinding) delegateThis.type);
+ }
+ }
+
+ TypeBinding type = ((VariableBinding) binding).type;
+ int index = indexOfFirstFieldBinding;
+ int length = tokens.length;
+ if (index == length) { // restrictiveFlag == FIELD
+ constant =
+ FieldReference.getConstantFor((FieldBinding) binding, false, this, index - 1);
+ return type;
+ }
+
+ // allocation of the fieldBindings array and its respective constants
+ int otherBindingsLength = length - index;
+ otherBindings = new FieldBinding[otherBindingsLength];
+
+ // fill the first constant (the one of the binding)
+ constant =
+ ((bits & FIELD) != 0)
+ ? FieldReference.getConstantFor((FieldBinding) binding, false, this, index - 1)
+ : ((VariableBinding) binding).constant;
+
+ // iteration on each field
+ while (index < length) {
+ char[] token = tokens[index];
+ if (type == null)
+ return null; // could not resolve type prior to this point
+ FieldBinding field = scope.getField(type, token, this);
+ int place = index - indexOfFirstFieldBinding;
+ otherBindings[place] = field;
+ if (!field.isValidBinding()) {
+ // try to retrieve the field as private field
+ CodeSnippetScope localScope = new CodeSnippetScope(scope);
+ if (delegateThis == null) {
+ if (this.evaluationContext.declaringTypeName != null) {
+ delegateThis = scope.getField(scope.enclosingSourceType(), DELEGATE_THIS, this);
+ if (delegateThis == null) {
+ ; // if not found then internal error, field should have been found
+ return super.reportError(scope);
+ }
+ } else {
+ return super.reportError(scope);
+ }
+ }
+ field = localScope.getFieldForCodeSnippet(delegateThis.type, token, this);
+ otherBindings[place] = field;
+ }
+ if (field.isValidBinding()) {
+ if (isFieldUseDeprecated(field, scope))
+ scope.problemReporter().deprecatedField(field, this);
+ Constant someConstant =
+ FieldReference.getConstantFor(field, false, this, place);
+ // constant propagation can only be performed as long as the previous one is a constant too.
+ if (constant != NotAConstant) {
+ constant = someConstant;
+ }
+ // if the binding declaring class is not visible, need special action
+ // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
+ if (delegateThis == null) {
+ CodeSnippetScope localScope = new CodeSnippetScope(scope);
+ if (field.declaringClass != type
+ && field.declaringClass != null // array.length
+ && field.constant == NotAConstant
+ && !field.declaringClass.canBeSeenBy(scope))
+ otherBindings[place] = new FieldBinding(field, (ReferenceBinding) type);
+ } else {
+ CodeSnippetScope localScope = new CodeSnippetScope(scope);
+ if (field.declaringClass != type
+ && field.declaringClass != null // array.length
+ && field.constant == NotAConstant
+ && !localScope.canBeSeenByForCodeSnippet(
+ field.declaringClass,
+ (ReferenceBinding) delegateThis.type))
+ otherBindings[place] = new FieldBinding(field, (ReferenceBinding) type);
+ }
+ type = field.type;
+ index++;
+ } else {
+ constant = NotAConstant; //don't fill other constants slots...
+ scope.problemReporter().invalidField(this, field, index, type);
+ return null;
+ }
+ }
+ return (otherBindings[otherBindingsLength - 1]).type;
+ }
+
+ /**
+ * Check and/or redirect the field access to the delegate receiver if any
+ */
+ public TypeBinding getReceiverType(BlockScope currentScope) {
+ if (receiverType != null)
+ return receiverType;
+ Scope scope = currentScope.parent;
+ while (true) {
+ switch (scope.kind) {
+ case Scope.CLASS_SCOPE :
+ return receiverType = ((ClassScope) scope).referenceContext.binding;
+ default :
+ scope = scope.parent;
+ }
+ }
+ }
+
+ public void manageSyntheticReadAccessIfNecessary(
+ BlockScope currentScope,
+ FieldBinding fieldBinding,
+ int index) {
+ // nothing to do the code generation will take care of private access
+ }
+
+ /*
+ * No need to emulate access to protected fields since not implicitly accessed
+ */
+ public void manageSyntheticWriteAccessIfNecessary(
+ BlockScope currentScope,
+ FieldBinding fieldBinding) {
+ // nothing to do the code generation will take care of private access
+ }
+
+ /**
+ * Normal field binding did not work, try to bind to a field of the delegate receiver.
+ */
+ public TypeBinding reportError(BlockScope scope) {
+
+ if (this.evaluationContext.declaringTypeName != null) {
+ delegateThis = scope.getField(scope.enclosingSourceType(), DELEGATE_THIS, this);
+ if (delegateThis == null) {
+ ; // if not found then internal error, field should have been found
+ return super.reportError(scope);
+ }
+ } else {
+ return super.reportError(scope);
+ }
+
+ if (binding instanceof ProblemFieldBinding
+ && ((ProblemFieldBinding) binding).problemId() == NotFound) {
+ // will not support innerclass emulation inside delegate
+ binding = scope.getField(delegateThis.type, this.tokens[0], this);
+ if (!binding.isValidBinding())
+ return super.reportError(scope);
+ return checkFieldAccess(scope);
+ }
+
+ if (binding instanceof ProblemBinding
+ && ((ProblemBinding) binding).problemId() == NotFound) {
+ // will not support innerclass emulation inside delegate
+ FieldBinding fieldBinding =
+ scope.getField(delegateThis.type, this.tokens[0], this);
+ if (!fieldBinding.isValidBinding())
+ return super.reportError(scope);
+ binding = fieldBinding;
+ return checkFieldAccess(scope);
+ }
+
+ TypeBinding result;
+ if (binding instanceof ProblemFieldBinding
+ && ((ProblemFieldBinding) binding).problemId() == NotVisible) {
+ result = resolveTypeVisibility(scope);
+ if (result == null)
+ return super.reportError(scope);
+ if (result.isValidBinding()) {
+ return result;
+ }
+ }
+
+ return super.reportError(scope);
+ }
+
+ public TypeBinding resolveTypeVisibility(BlockScope scope) {
+ // field and/or local are done before type lookups
+
+ // the only available value for the restrictiveFlag BEFORE
+ // the TC is Flag_Type Flag_LocalField and Flag_TypeLocalField
+
+ CodeSnippetScope localScope = new CodeSnippetScope(scope);
+ if ((binding =
+ localScope.getBinding(
+ tokens,
+ bits & RestrictiveFlagMASK,
+ this,
+ (ReferenceBinding) delegateThis.type))
+ .isValidBinding()) {
+ bits &= ~RestrictiveFlagMASK; // clear bits
+ bits |= FIELD;
+ return getOtherFieldBindings(scope);
+ }
+ //========error cases===============
+ return super.reportError(scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetReturnStatement.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetReturnStatement.java
new file mode 100644
index 0000000000..928e62e171
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetReturnStatement.java
@@ -0,0 +1,146 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.ast.Expression;
+import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.impl.NullConstant;
+
+/**
+ * A return statement inside a code snippet. During the code gen,
+ * it uses a macro to set the result of the code snippet instead
+ * of returning it.
+ */
+public class CodeSnippetReturnStatement
+ extends ReturnStatement
+ implements InvocationSite, EvaluationConstants {
+ MethodBinding setResultMethod;
+ public CodeSnippetReturnStatement(
+ Expression expr,
+ int s,
+ int e,
+ EvaluationContext evaluationContext) {
+ super(expr, s, e);
+ }
+
+ /**
+ * Dump the suitable return bytecode for a return statement
+ *
+ */
+ public void generateReturnBytecode(
+ BlockScope currentScope,
+ CodeStream codeStream) {
+
+ // output the return bytecode
+ codeStream.return_();
+ }
+
+ public void generateStoreSaveValueIfNecessary(
+ BlockScope currentScope,
+ CodeStream codeStream) {
+
+ // push receiver
+ codeStream.aload_0();
+
+ // push the 2 parameters of "setResult(Object, Class)"
+ if (this.expression == null
+ || this.expressionType == VoidBinding) {
+ // expressionType == VoidBinding if code snippet is the expression "System.out.println()"
+ // push null
+ codeStream.aconst_null();
+
+ // void.class
+ codeStream.generateClassLiteralAccessForType(VoidBinding, null);
+ } else {
+ // swap with expression
+ int valueTypeID = this.expressionType.id;
+ if (valueTypeID == T_long || valueTypeID == T_double) {
+ codeStream.dup_x2();
+ codeStream.pop();
+ } else {
+ codeStream.swap();
+ }
+
+ // generate wrapper if needed
+ if (this.expressionType.isBaseType()) {
+ codeStream.generateObjectWrapperForType(this.expressionType);
+ }
+
+ // generate the expression type
+ codeStream.generateClassLiteralAccessForType(this.expressionType, null);
+ }
+
+ // generate the invoke virtual to "setResult(Object,Class)"
+ codeStream.invokevirtual(this.setResultMethod);
+ }
+
+ public boolean isSuperAccess() {
+ return false;
+ }
+
+ public boolean isTypeAccess() {
+ return false;
+ }
+
+ public boolean needValue() {
+ return true;
+ }
+
+ public void prepareSaveValueLocation(BlockScope currentScope) {
+
+ // do nothing: no storage is necessary for snippets
+ }
+
+ public void resolve(BlockScope scope) {
+ if (this.expression != null) {
+ if ((this.expressionType = this.expression.resolveType(scope)) != null) {
+ TypeBinding javaLangClass = scope.getJavaLangClass();
+ if (!javaLangClass.isValidBinding()) {
+ scope.problemReporter().codeSnippetMissingClass(
+ "java.lang.Class",
+ this.sourceStart,
+ this.sourceEnd);
+ return;
+ }
+ TypeBinding javaLangObject = scope.getJavaLangObject();
+ if (!javaLangObject.isValidBinding()) {
+ scope.problemReporter().codeSnippetMissingClass(
+ "java.lang.Object",
+ this.sourceStart,
+ this.sourceEnd);
+ return;
+ }
+ TypeBinding[] argumentTypes =
+ new TypeBinding[] { javaLangObject, javaLangClass };
+ this.setResultMethod =
+ scope.getImplicitMethod(SETRESULT_SELECTOR, argumentTypes, this);
+ if (!this.setResultMethod.isValidBinding()) {
+ scope.problemReporter().codeSnippetMissingMethod(
+ ROOT_FULL_CLASS_NAME,
+ new String(SETRESULT_SELECTOR),
+ new String(SETRESULT_ARGUMENTS),
+ this.sourceStart,
+ this.sourceEnd);
+ return;
+ }
+ // in constant case, the implicit conversion cannot be left uninitialized
+ if (this.expression.constant != NotAConstant) {
+ // fake 'no implicit conversion' (the return type is always void)
+ this.expression.implicitConversion = this.expression.constant.typeID() << 4;
+ }
+ }
+ }
+ }
+
+ public void setDepth(int depth) {
+ }
+
+ public void setFieldIndex(int depth) {
+ }
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetScope.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetScope.java
new file mode 100644
index 0000000000..ef59e5abc1
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetScope.java
@@ -0,0 +1,968 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+import org.eclipse.jdt.internal.compiler.util.ObjectVector;
+import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
+
+/**
+ * This scope is used for code snippet lookup to emulate private, protected and default access.
+ * These accesses inside inner classes are not managed yet.
+ */
+public class CodeSnippetScope extends BlockScope {
+ /**
+ * CodeSnippetScope constructor comment.
+ * @param kind int
+ * @param parent org.eclipse.jdt.internal.compiler.lookup.Scope
+ */
+ protected CodeSnippetScope(int kind, Scope parent) {
+ super(kind, parent);
+ }
+
+ /**
+ * CodeSnippetScope constructor comment.
+ * @param parent org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ */
+ public CodeSnippetScope(BlockScope parent) {
+ super(parent);
+ }
+
+ /**
+ * CodeSnippetScope constructor comment.
+ * @param parent org.eclipse.jdt.internal.compiler.lookup.BlockScope
+ * @param variableCount int
+ */
+ public CodeSnippetScope(BlockScope parent, int variableCount) {
+ super(parent, variableCount);
+ }
+
+ /* 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.
+ *
+ * NOTE: Cannot invoke this method with a compilation unit scope.
+ */
+
+ public final boolean canBeSeenByForCodeSnippet(
+ FieldBinding fieldBinding,
+ TypeBinding receiverType,
+ InvocationSite invocationSite,
+ Scope scope) {
+ if (fieldBinding.isPublic())
+ return true;
+
+ ReferenceBinding invocationType = (ReferenceBinding) receiverType;
+ if (invocationType == fieldBinding.declaringClass)
+ return true;
+
+ if (fieldBinding.isProtected()) {
+ // answer true if the invocationType is the declaringClass or they are in the same package
+ // OR the invocationType is a subclass of the declaringClass
+ // AND the receiverType is the invocationType or its subclass
+ // OR the field is a static field accessed directly through a type
+ if (invocationType == fieldBinding.declaringClass)
+ return true;
+ if (invocationType.fPackage == fieldBinding.declaringClass.fPackage)
+ return true;
+ if (fieldBinding.declaringClass.isSuperclassOf(invocationType)) {
+ if (invocationSite.isSuperAccess())
+ return true;
+ // receiverType can be an array binding in one case... see if you can change it
+ if (receiverType instanceof ArrayBinding)
+ return false;
+ if (invocationType == receiverType
+ || invocationType.isSuperclassOf((ReferenceBinding) receiverType))
+ return true;
+ if (fieldBinding.isStatic())
+ return true; // see 1FMEPDL - return invocationSite.isTypeAccess();
+ }
+ return false;
+ }
+
+ if (fieldBinding.isPrivate()) {
+ // answer true if the receiverType is the declaringClass
+ // AND the invocationType and the declaringClass have a common enclosingType
+ if (receiverType != fieldBinding.declaringClass)
+ return false;
+
+ if (invocationType != fieldBinding.declaringClass) {
+ ReferenceBinding outerInvocationType = invocationType;
+ ReferenceBinding temp = outerInvocationType.enclosingType();
+ while (temp != null) {
+ outerInvocationType = temp;
+ temp = temp.enclosingType();
+ }
+
+ ReferenceBinding outerDeclaringClass = fieldBinding.declaringClass;
+ temp = outerDeclaringClass.enclosingType();
+ while (temp != null) {
+ outerDeclaringClass = temp;
+ temp = temp.enclosingType();
+ }
+ if (outerInvocationType != outerDeclaringClass)
+ return false;
+ }
+ return true;
+ }
+
+ // isDefault()
+ if (invocationType.fPackage != fieldBinding.declaringClass.fPackage)
+ return false;
+
+ // receiverType can be an array binding in one case... see if you can change it
+ if (receiverType instanceof ArrayBinding)
+ return false;
+ ReferenceBinding type = (ReferenceBinding) receiverType;
+ PackageBinding declaringPackage = fieldBinding.declaringClass.fPackage;
+ do {
+ if (fieldBinding.declaringClass == type)
+ return true;
+ if (declaringPackage != type.fPackage)
+ return false;
+ } while ((type = type.superclass()) != null);
+ return false;
+ }
+
+ /* 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.
+ *
+ * NOTE: Cannot invoke this method with a compilation unit scope.
+ */
+ public final boolean canBeSeenByForCodeSnippet(
+ MethodBinding methodBinding,
+ TypeBinding receiverType,
+ InvocationSite invocationSite,
+ Scope scope) {
+ if (methodBinding.isPublic())
+ return true;
+
+ ReferenceBinding invocationType = (ReferenceBinding) receiverType;
+ if (invocationType == methodBinding.declaringClass
+ && invocationType == receiverType)
+ return true;
+
+ if (methodBinding.isProtected()) {
+ // answer true if the invocationType is the declaringClass or they are in the same package
+ // OR the invocationType is a subclass of the declaringClass
+ // AND the receiverType is the invocationType or its subclass
+ // OR the method is a static method accessed directly through a type
+ if (invocationType == methodBinding.declaringClass)
+ return true;
+ if (invocationType.fPackage == methodBinding.declaringClass.fPackage)
+ return true;
+ if (methodBinding.declaringClass.isSuperclassOf(invocationType)) {
+ if (invocationSite.isSuperAccess())
+ return true;
+ // receiverType can be an array binding in one case... see if you can change it
+ if (receiverType instanceof ArrayBinding)
+ return false;
+ if (invocationType == receiverType
+ || invocationType.isSuperclassOf((ReferenceBinding) receiverType))
+ return true;
+ if (methodBinding.isStatic())
+ return true; // see 1FMEPDL - return invocationSite.isTypeAccess();
+ }
+ return false;
+ }
+
+ if (methodBinding.isPrivate()) {
+ // answer true if the receiverType is the declaringClass
+ // AND the invocationType and the declaringClass have a common enclosingType
+ if (receiverType != methodBinding.declaringClass)
+ return false;
+
+ if (invocationType != methodBinding.declaringClass) {
+ ReferenceBinding outerInvocationType = invocationType;
+ ReferenceBinding temp = outerInvocationType.enclosingType();
+ while (temp != null) {
+ outerInvocationType = temp;
+ temp = temp.enclosingType();
+ }
+
+ ReferenceBinding outerDeclaringClass = methodBinding.declaringClass;
+ temp = outerDeclaringClass.enclosingType();
+ while (temp != null) {
+ outerDeclaringClass = temp;
+ temp = temp.enclosingType();
+ }
+ if (outerInvocationType != outerDeclaringClass)
+ return false;
+ }
+ return true;
+ }
+
+ // isDefault()
+ if (invocationType.fPackage != methodBinding.declaringClass.fPackage)
+ return false;
+
+ // receiverType can be an array binding in one case... see if you can change it
+ if (receiverType instanceof ArrayBinding)
+ return false;
+ ReferenceBinding type = (ReferenceBinding) receiverType;
+ PackageBinding declaringPackage = methodBinding.declaringClass.fPackage;
+ do {
+ if (methodBinding.declaringClass == type)
+ return true;
+ if (declaringPackage != type.fPackage)
+ return false;
+ } while ((type = type.superclass()) != null);
+ return false;
+ }
+
+ /* 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.
+ *
+ * NOTE: Cannot invoke this method with a compilation unit scope.
+ */
+
+ public final boolean canBeSeenByForCodeSnippet(
+ ReferenceBinding referenceBinding,
+ ReferenceBinding receiverType) {
+ if (referenceBinding.isPublic())
+ return true;
+
+ if (receiverType == referenceBinding)
+ return true;
+
+ if (referenceBinding.isProtected()) {
+ // answer true if the receiver (or its enclosing type) is the superclass
+ // of the receiverType or in the same package
+ return receiverType.fPackage == referenceBinding.fPackage
+ || referenceBinding.isSuperclassOf(receiverType)
+ || referenceBinding.enclosingType().isSuperclassOf(receiverType);
+ // protected types always have an enclosing one
+ }
+
+ if (referenceBinding.isPrivate()) {
+ // answer true if the receiver and the receiverType have a common enclosingType
+ // already know they are not the identical type
+ ReferenceBinding outerInvocationType = receiverType;
+ ReferenceBinding temp = outerInvocationType.enclosingType();
+ while (temp != null) {
+ outerInvocationType = temp;
+ temp = temp.enclosingType();
+ }
+
+ ReferenceBinding outerDeclaringClass = referenceBinding;
+ temp = outerDeclaringClass.enclosingType();
+ while (temp != null) {
+ outerDeclaringClass = temp;
+ temp = temp.enclosingType();
+ }
+ return outerInvocationType == outerDeclaringClass;
+ }
+
+ // isDefault()
+ return receiverType.fPackage == referenceBinding.fPackage;
+ }
+
+ // Internal use only
+ public MethodBinding findExactMethod(
+ ReferenceBinding receiverType,
+ char[] selector,
+ TypeBinding[] argumentTypes,
+ InvocationSite invocationSite) {
+ compilationUnitScope().addTypeReference(receiverType);
+ MethodBinding exactMethod =
+ receiverType.getExactMethod(selector, argumentTypes);
+ if (exactMethod != null) {
+ compilationUnitScope().addTypeReferences(exactMethod.thrownExceptions);
+ if (receiverType.isInterface()
+ || canBeSeenByForCodeSnippet(exactMethod, receiverType, invocationSite, this))
+ return exactMethod;
+ }
+ return null;
+ }
+
+ // Internal use only
+
+ /* Answer the field binding that corresponds to fieldName.
+ Start the lookup at the receiverType.
+ InvocationSite implements
+ isSuperAccess(); this is used to determine if the discovered field is visible.
+ Only fields defined by the receiverType or its supertypes are answered;
+ a field of an enclosing type will not be found using this API.
+
+ If no visible field is discovered, null is answered.
+ */
+
+ public FieldBinding findFieldForCodeSnippet(
+ TypeBinding receiverType,
+ char[] fieldName,
+ InvocationSite invocationSite) {
+ if (receiverType.isBaseType())
+ return null;
+ if (receiverType.isArrayType()) {
+ if (CharOperation.equals(fieldName, LENGTH))
+ return ArrayBinding.LengthField;
+ return null;
+ }
+
+ ReferenceBinding currentType = (ReferenceBinding) receiverType;
+ if (!currentType.canBeSeenBy(this))
+ return new ProblemFieldBinding(fieldName, NotVisible);
+ // *** Need a new problem id - TypeNotVisible?
+
+ compilationUnitScope().addTypeReference(currentType);
+ FieldBinding field = currentType.getField(fieldName);
+ if (field != null) {
+ if (canBeSeenByForCodeSnippet(field, currentType, invocationSite, this))
+ return field;
+ else
+ return new ProblemFieldBinding(fieldName, NotVisible);
+ }
+
+ // collect all superinterfaces of receiverType until the field is found in a supertype
+ ReferenceBinding[][] interfacesToVisit = null;
+ int lastPosition = -1;
+ FieldBinding visibleField = null;
+ boolean keepLooking = true;
+ boolean notVisible = false;
+ // we could hold onto the not visible field for extra error reporting
+ while (keepLooking) {
+ ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (interfacesToVisit == null)
+ interfacesToVisit = new ReferenceBinding[5][];
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(
+ interfacesToVisit,
+ 0,
+ interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
+ 0,
+ lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+ if ((currentType = currentType.superclass()) == null)
+ break;
+
+ if ((field = currentType.getField(fieldName)) != null) {
+ keepLooking = false;
+ if (canBeSeenByForCodeSnippet(field, receiverType, invocationSite, this)) {
+ if (visibleField == null)
+ visibleField = field;
+ else
+ return new ProblemFieldBinding(fieldName, Ambiguous);
+ } else {
+ notVisible = true;
+ }
+ }
+ }
+
+ // walk all visible interfaces to find ambiguous references
+ if (interfacesToVisit != null) {
+ ProblemFieldBinding ambiguous = null;
+ done : for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++) {
+ ReferenceBinding anInterface = interfaces[j];
+ if ((anInterface.tagBits & InterfaceVisited) == 0) {
+ // if interface as not already been visited
+ anInterface.tagBits |= InterfaceVisited;
+ if ((field = anInterface.getField(fieldName)) != null) {
+ if (visibleField == null) {
+ visibleField = field;
+ } else {
+ ambiguous = new ProblemFieldBinding(fieldName, Ambiguous);
+ break done;
+ }
+ } else {
+ ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(
+ interfacesToVisit,
+ 0,
+ interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
+ 0,
+ lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+ }
+ }
+ }
+ }
+
+ // bit reinitialization
+ for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++)
+ interfaces[j].tagBits &= ~InterfaceVisited;
+ }
+ if (ambiguous != null)
+ return ambiguous;
+ }
+
+ if (visibleField != null)
+ return visibleField;
+ if (notVisible)
+ return new ProblemFieldBinding(fieldName, NotVisible);
+ return null;
+ }
+
+ // Internal use only
+ public MethodBinding findMethod(
+ ReferenceBinding receiverType,
+ char[] selector,
+ TypeBinding[] argumentTypes,
+ InvocationSite invocationSite) {
+ ReferenceBinding currentType = receiverType;
+ MethodBinding matchingMethod = null;
+ ObjectVector found = null;
+
+ compilationUnitScope().addTypeReference(currentType);
+ if (currentType.isInterface()) {
+ MethodBinding[] currentMethods = currentType.getMethods(selector);
+ int currentLength = currentMethods.length;
+ if (currentLength == 1) {
+ matchingMethod = currentMethods[0];
+ } else
+ if (currentLength > 1) {
+ found = new ObjectVector();
+ for (int f = 0; f < currentLength; f++)
+ found.add(currentMethods[f]);
+ }
+
+ ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][];
+ int lastPosition = -1;
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(
+ interfacesToVisit,
+ 0,
+ interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
+ 0,
+ lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+
+ for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++) {
+ currentType = interfaces[j];
+ if ((currentType.tagBits & InterfaceVisited) == 0) {
+ // if interface as not already been visited
+ currentType.tagBits |= InterfaceVisited;
+
+ currentMethods = currentType.getMethods(selector);
+ if ((currentLength = currentMethods.length) == 1
+ && matchingMethod == null
+ && found == null) {
+ matchingMethod = currentMethods[0];
+ } else
+ if (currentLength > 0) {
+ if (found == null) {
+ found = new ObjectVector();
+ if (matchingMethod != null)
+ found.add(matchingMethod);
+ }
+ for (int f = 0; f < currentLength; f++)
+ found.add(currentMethods[f]);
+ }
+
+ itsInterfaces = currentType.superInterfaces();
+ if (itsInterfaces != NoSuperInterfaces) {
+ if (++lastPosition == interfacesToVisit.length)
+ System.arraycopy(
+ interfacesToVisit,
+ 0,
+ interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
+ 0,
+ lastPosition);
+ interfacesToVisit[lastPosition] = itsInterfaces;
+ }
+ }
+ }
+ }
+
+ // bit reinitialization
+ for (int i = 0; i <= lastPosition; i++) {
+ ReferenceBinding[] interfaces = interfacesToVisit[i];
+ for (int j = 0, length = interfaces.length; j < length; j++)
+ interfaces[j].tagBits &= ~InterfaceVisited;
+ }
+ }
+ currentType =
+ (matchingMethod == null && found == null) ? getJavaLangObject() : null;
+ }
+
+ while (currentType != null) {
+ MethodBinding[] currentMethods = currentType.getMethods(selector);
+ int currentLength = currentMethods.length;
+ if (currentLength == 1 && matchingMethod == null && found == null) {
+ matchingMethod = currentMethods[0];
+ } else
+ if (currentLength > 0) {
+ if (found == null) {
+ found = new ObjectVector();
+ if (matchingMethod != null)
+ found.add(matchingMethod);
+ }
+ for (int f = 0; f < currentLength; f++)
+ found.add(currentMethods[f]);
+ }
+ currentType = currentType.superclass();
+ }
+
+ if (found == null)
+ return matchingMethod;
+ // may be null - have not checked arg types or visibility
+
+ int foundSize = found.size;
+ MethodBinding[] compatible = new MethodBinding[foundSize];
+ int compatibleIndex = 0;
+ for (int i = 0; i < foundSize; i++) {
+ MethodBinding methodBinding = (MethodBinding) found.elementAt(i);
+ if (areParametersAssignable(methodBinding.parameters, argumentTypes))
+ compatible[compatibleIndex++] = methodBinding;
+ }
+ if (compatibleIndex == 1)
+ return compatible[0]; // have not checked visibility
+ if (compatibleIndex == 0)
+ return (MethodBinding) found.elementAt(0);
+ // no good match so just use the first one found
+
+ MethodBinding[] visible = new MethodBinding[compatibleIndex];
+ int visibleIndex = 0;
+ for (int i = 0; i < compatibleIndex; i++) {
+ MethodBinding methodBinding = compatible[i];
+ if (canBeSeenByForCodeSnippet(methodBinding,
+ receiverType,
+ invocationSite,
+ this))
+ visible[visibleIndex++] = methodBinding;
+ }
+ if (visibleIndex == 1) {
+ compilationUnitScope().addTypeReferences(visible[0].thrownExceptions);
+ return visible[0];
+ }
+ if (visibleIndex == 0)
+ return new ProblemMethodBinding(
+ compatible[0].selector,
+ argumentTypes,
+ compatible[0].declaringClass,
+ NotVisible);
+ if (visible[0].declaringClass.isClass())
+ return mostSpecificClassMethodBinding(visible, visibleIndex);
+ else
+ return mostSpecificInterfaceMethodBinding(visible, visibleIndex);
+ }
+
+ // Internal use only
+ public MethodBinding findMethodForArray(
+ ArrayBinding receiverType,
+ char[] selector,
+ TypeBinding[] argumentTypes,
+ InvocationSite invocationSite) {
+ ReferenceBinding object = getJavaLangObject();
+ MethodBinding methodBinding = object.getExactMethod(selector, argumentTypes);
+ if (methodBinding != null) {
+ // handle the method clone() specially... cannot be protected or throw exceptions
+ if (argumentTypes == NoParameters && CharOperation.equals(selector, CLONE))
+ return new MethodBinding(
+ (methodBinding.modifiers ^ AccProtected) | AccPublic,
+ CLONE,
+ methodBinding.returnType,
+ argumentTypes,
+ null,
+ object);
+ if (canBeSeenByForCodeSnippet(methodBinding,
+ receiverType,
+ invocationSite,
+ this))
+ return methodBinding;
+ }
+
+ // answers closest approximation, may not check argumentTypes or visibility
+ methodBinding = findMethod(object, selector, argumentTypes, invocationSite);
+ if (methodBinding == null)
+ return new ProblemMethodBinding(selector, argumentTypes, NotFound);
+ if (methodBinding.isValidBinding()) {
+ if (!areParametersAssignable(methodBinding.parameters, argumentTypes))
+ return new ProblemMethodBinding(
+ methodBinding,
+ selector,
+ argumentTypes,
+ NotFound);
+ if (!canBeSeenByForCodeSnippet(methodBinding,
+ receiverType,
+ invocationSite,
+ this))
+ return new ProblemMethodBinding(
+ selector,
+ argumentTypes,
+ methodBinding.declaringClass,
+ NotVisible);
+ }
+ return methodBinding;
+ }
+
+ /* API
+ flag is a mask of the following values VARIABLE (= FIELD or LOCAL), TYPE.
+ Only bindings corresponding to the mask will be answered.
+
+ if the VARIABLE mask is set then
+ If the first name provided is a field (or local) then the field (or local) is answered
+ Otherwise, package names and type names are consumed until a field is found.
+ In this case, the field is answered.
+
+ if the TYPE mask is set,
+ package names and type names are consumed until the end of the input.
+ Only if all of the input is consumed is the type answered
+
+ All other conditions are errors, and a problem binding is returned.
+
+ NOTE: If a problem binding is returned, senders should extract the compound name
+ from the binding & not assume the problem applies to the entire compoundName.
+
+ The VARIABLE mask has precedence over the TYPE mask.
+
+ InvocationSite implements
+ isSuperAccess(); this is used to determine if the discovered field is visible.
+ setFieldIndex(int); this is used to record the number of names that were consumed.
+
+ For example, getBinding({"foo","y","q", VARIABLE, site) will answer
+ the binding for the field or local named "foo" (or an error binding if none exists).
+ In addition, setFieldIndex(1) will be sent to the invocation site.
+ If a type named "foo" exists, it will not be detected (and an error binding will be answered)
+
+ IMPORTANT NOTE: This method is written under the assumption that compoundName is longer than length 1.
+ */
+
+ public Binding getBinding(
+ char[][] compoundName,
+ int mask,
+ InvocationSite invocationSite,
+ ReferenceBinding receiverType) {
+ Binding binding =
+ getBinding(compoundName[0], mask | TYPE | PACKAGE, invocationSite);
+ invocationSite.setFieldIndex(1);
+ if (!binding.isValidBinding() || binding instanceof VariableBinding)
+ return binding;
+
+ int length = compoundName.length;
+ int currentIndex = 1;
+ foundType : if (binding instanceof PackageBinding) {
+ PackageBinding packageBinding = (PackageBinding) binding;
+ compilationUnitScope().addNamespaceReference(packageBinding);
+
+ while (currentIndex < length) {
+ binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++]);
+ invocationSite.setFieldIndex(currentIndex);
+ if (binding == null) {
+ if (currentIndex == length)
+ // must be a type if its the last name, otherwise we have no idea if its a package or type
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ NotFound);
+ else
+ return new ProblemBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ NotFound);
+ }
+ if (binding instanceof ReferenceBinding) {
+ if (!binding.isValidBinding())
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ binding.problemId());
+ compilationUnitScope().addTypeReference((ReferenceBinding) binding);
+ if (!this.canBeSeenByForCodeSnippet((ReferenceBinding) binding, receiverType))
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ NotVisible);
+ break foundType;
+ }
+ packageBinding = (PackageBinding) binding;
+ compilationUnitScope().addNamespaceReference(packageBinding);
+ }
+
+ // It is illegal to request a PACKAGE from this method.
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ NotFound);
+ }
+
+ // know binding is now a ReferenceBinding
+ while (currentIndex < length) {
+ ReferenceBinding typeBinding = (ReferenceBinding) binding;
+ char[] nextName = compoundName[currentIndex++];
+ invocationSite.setFieldIndex(currentIndex);
+ if ((binding = findFieldForCodeSnippet(typeBinding, nextName, invocationSite))
+ != null) {
+ if (!binding.isValidBinding())
+ return new ProblemFieldBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ binding.problemId());
+ break; // binding is now a field
+ }
+ if ((binding = findMemberType(nextName, typeBinding)) == null)
+ return new ProblemBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ typeBinding,
+ NotFound);
+ if (!binding.isValidBinding())
+ return new ProblemReferenceBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ binding.problemId());
+ }
+
+ if ((mask & FIELD) != 0
+ && (binding instanceof FieldBinding)) {
+ // was looking for a field and found a field
+ FieldBinding field = (FieldBinding) binding;
+ if (!field.isStatic())
+ return new ProblemFieldBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ NonStaticReferenceInStaticContext);
+ return binding;
+ }
+ if ((mask & TYPE) != 0
+ && (binding instanceof ReferenceBinding)) {
+ // was looking for a type and found a type
+ return binding;
+ }
+
+ // handle the case when a field or type was asked for but we resolved the compoundName to a type or field
+ return new ProblemBinding(
+ CharOperation.subarray(compoundName, 0, currentIndex),
+ NotFound);
+ }
+
+ /* API
+
+ Answer the constructor binding that corresponds to receiverType, argumentTypes.
+
+ InvocationSite implements
+ isSuperAccess(); this is used to determine if the discovered constructor is visible.
+
+ If no visible constructor is discovered, an error binding is answered.
+ */
+
+ public MethodBinding getConstructor(
+ ReferenceBinding receiverType,
+ TypeBinding[] argumentTypes,
+ InvocationSite invocationSite) {
+ MethodBinding methodBinding = receiverType.getExactConstructor(argumentTypes);
+ if (methodBinding != null)
+ if (canBeSeenByForCodeSnippet(methodBinding,
+ receiverType,
+ invocationSite,
+ this))
+ return methodBinding;
+
+ MethodBinding[] methods =
+ receiverType.getMethods(ConstructorDeclaration.ConstantPoolName);
+ if (methods == NoMethods)
+ return new ProblemMethodBinding(
+ ConstructorDeclaration.ConstantPoolName,
+ argumentTypes,
+ NotFound);
+
+ MethodBinding[] compatible = new MethodBinding[methods.length];
+ int compatibleIndex = 0;
+ for (int i = 0, length = methods.length; i < length; i++)
+ if (areParametersAssignable(methods[i].parameters, argumentTypes))
+ compatible[compatibleIndex++] = methods[i];
+ if (compatibleIndex == 0)
+ return new ProblemMethodBinding(
+ ConstructorDeclaration.ConstantPoolName,
+ argumentTypes,
+ NotFound);
+ // need a more descriptive error... cannot convert from X to Y
+
+ MethodBinding[] visible = new MethodBinding[compatibleIndex];
+ int visibleIndex = 0;
+ for (int i = 0; i < compatibleIndex; i++) {
+ MethodBinding method = compatible[i];
+ if (canBeSeenByForCodeSnippet(method, receiverType, invocationSite, this))
+ visible[visibleIndex++] = method;
+ }
+ if (visibleIndex == 1)
+ return visible[0];
+ if (visibleIndex == 0)
+ return new ProblemMethodBinding(
+ ConstructorDeclaration.ConstantPoolName,
+ argumentTypes,
+ NotVisible);
+ return mostSpecificClassMethodBinding(visible, visibleIndex);
+ }
+
+ /* API
+
+ Answer the field binding that corresponds to fieldName.
+ Start the lookup at the receiverType.
+ InvocationSite implements
+ isSuperAccess(); this is used to determine if the discovered field is visible.
+ Only fields defined by the receiverType or its supertypes are answered;
+ a field of an enclosing type will not be found using this API.
+
+ If no visible field is discovered, an error binding is answered.
+ */
+
+ public FieldBinding getFieldForCodeSnippet(
+ TypeBinding receiverType,
+ char[] fieldName,
+ InvocationSite invocationSite) {
+ FieldBinding field =
+ findFieldForCodeSnippet(receiverType, fieldName, invocationSite);
+ if (field == null)
+ return new ProblemFieldBinding(fieldName, NotFound);
+ else
+ return field;
+ }
+
+ /* API
+
+ Answer the method binding that corresponds to selector, argumentTypes.
+ Start the lookup at the enclosing type of the receiver.
+ InvocationSite implements
+ isSuperAccess(); this is used to determine if the discovered method is visible.
+ setDepth(int); this is used to record the depth of the discovered method
+ relative to the enclosing type of the receiver. (If the method is defined
+ in the enclosing type of the receiver, the depth is 0; in the next enclosing
+ type, the depth is 1; and so on
+
+ If no visible method is discovered, an error binding is answered.
+ */
+
+ public MethodBinding getImplicitMethod(
+ ReferenceBinding receiverType,
+ char[] selector,
+ TypeBinding[] argumentTypes,
+ InvocationSite invocationSite) {
+ boolean insideStaticContext = false;
+ boolean insideConstructorCall = false;
+ MethodBinding foundMethod = null;
+ ProblemMethodBinding foundFuzzyProblem = null;
+ // the weird method lookup case (matches method name in scope, then arg types, then visibility)
+ ProblemMethodBinding foundInsideProblem = null;
+ // inside Constructor call or inside static context
+ Scope scope = this;
+ boolean isExactMatch = true;
+ // retrieve an exact visible match (if possible)
+ MethodBinding methodBinding =
+ (foundMethod == null)
+ ? findExactMethod(receiverType, selector, argumentTypes, invocationSite)
+ : findExactMethod(
+ receiverType,
+ foundMethod.selector,
+ foundMethod.parameters,
+ invocationSite);
+ // ? findExactMethod(receiverType, selector, argumentTypes, invocationSite)
+ // : findExactMethod(receiverType, foundMethod.selector, foundMethod.parameters, invocationSite);
+ if (methodBinding == null && foundMethod == null) {
+ // answers closest approximation, may not check argumentTypes or visibility
+ isExactMatch = false;
+ methodBinding =
+ findMethod(receiverType, selector, argumentTypes, invocationSite);
+ // methodBinding = findMethod(receiverType, selector, argumentTypes, invocationSite);
+ }
+ if (methodBinding != null) { // skip it if we did not find anything
+ if (methodBinding.problemId() == Ambiguous) {
+ if (foundMethod == null || foundMethod.problemId() == NotVisible)
+ // supercedes any potential InheritedNameHidesEnclosingName problem
+ return methodBinding;
+ else
+ // make the user qualify the method, likely wants the first inherited method (javac generates an ambiguous error instead)
+ return new ProblemMethodBinding(
+ selector,
+ argumentTypes,
+ InheritedNameHidesEnclosingName);
+ }
+
+ ProblemMethodBinding fuzzyProblem = null;
+ ProblemMethodBinding insideProblem = null;
+ if (methodBinding.isValidBinding()) {
+ if (!isExactMatch) {
+ if (!areParametersAssignable(methodBinding.parameters, argumentTypes)) {
+ fuzzyProblem =
+ new ProblemMethodBinding(methodBinding, selector, argumentTypes, NotFound);
+ } else
+ if (!canBeSeenByForCodeSnippet(methodBinding,
+ receiverType,
+ invocationSite,
+ this)) {
+ // using <classScope> instead of <this> for visibility check does grant all access to innerclass
+ fuzzyProblem =
+ new ProblemMethodBinding(
+ selector,
+ argumentTypes,
+ methodBinding.declaringClass,
+ NotVisible);
+ }
+ }
+ if (fuzzyProblem == null && !methodBinding.isStatic()) {
+ if (insideConstructorCall) {
+ insideProblem =
+ new ProblemMethodBinding(
+ methodBinding.selector,
+ methodBinding.parameters,
+ NonStaticReferenceInConstructorInvocation);
+ } else
+ if (insideStaticContext) {
+ insideProblem =
+ new ProblemMethodBinding(
+ methodBinding.selector,
+ methodBinding.parameters,
+ NonStaticReferenceInStaticContext);
+ }
+ }
+ if (receiverType == methodBinding.declaringClass
+ || (receiverType.getMethods(selector)) != NoMethods) {
+ // found a valid method in the 'immediate' scope (ie. not inherited)
+ // OR the receiverType implemented a method with the correct name
+ if (foundMethod == null) {
+ // return the methodBinding if it is not declared in a superclass of the scope's binding (i.e. "inherited")
+ if (fuzzyProblem != null)
+ return fuzzyProblem;
+ if (insideProblem != null)
+ return insideProblem;
+ return methodBinding;
+ }
+ // if a method was found, complain when another is found in an 'immediate' enclosing type (ie. not inherited)
+ // NOTE: Unlike fields, a non visible method hides a visible method
+ if (foundMethod.declaringClass != methodBinding.declaringClass)
+ // ie. have we found the same method - do not trust field identity yet
+ return new ProblemMethodBinding(
+ methodBinding.selector,
+ methodBinding.parameters,
+ InheritedNameHidesEnclosingName);
+ }
+ }
+
+ if (foundMethod == null
+ || (foundMethod.problemId() == NotVisible
+ && methodBinding.problemId() != NotVisible)) {
+ // only remember the methodBinding if its the first one found or the previous one was not visible & methodBinding is...
+ // remember that private methods are visible if defined directly by an enclosing class
+ foundFuzzyProblem = fuzzyProblem;
+ foundInsideProblem = insideProblem;
+ if (fuzzyProblem == null)
+ foundMethod = methodBinding; // only keep it if no error was found
+ }
+ }
+ insideStaticContext |= receiverType.isStatic();
+ // 1EX5I8Z - accessing outer fields within a constructor call is permitted
+ // in order to do so, we change the flag as we exit from the type, not the method
+ // itself, because the class scope is used to retrieve the fields.
+ MethodScope enclosingMethodScope = scope.methodScope();
+ insideConstructorCall =
+ enclosingMethodScope == null ? false : enclosingMethodScope.isConstructorCall;
+
+ if (foundFuzzyProblem != null)
+ return foundFuzzyProblem;
+ if (foundInsideProblem != null)
+ return foundInsideProblem;
+ if (foundMethod != null)
+ return foundMethod;
+ return new ProblemMethodBinding(selector, argumentTypes, NotFound);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetSingleNameReference.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetSingleNameReference.java
new file mode 100644
index 0000000000..54896650ad
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetSingleNameReference.java
@@ -0,0 +1,697 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+/**
+ * A single name reference inside a code snippet can denote a field of a remote
+ * receiver object (i.e. the one of the context in the stack frame)
+ */
+public class CodeSnippetSingleNameReference
+ extends SingleNameReference
+ implements EvaluationConstants, InvocationSite, ProblemReasons {
+
+ EvaluationContext evaluationContext;
+ FieldBinding delegateThis;
+ TypeBinding receiverType;
+ public CodeSnippetSingleNameReference(
+ char[] source,
+ long pos,
+ EvaluationContext evaluationContext) {
+ super(source, pos);
+ this.evaluationContext = evaluationContext;
+ }
+
+ public FlowInfo analyseCode(
+ BlockScope currentScope,
+ FlowContext flowContext,
+ FlowInfo flowInfo,
+ boolean valueRequired) {
+ switch (bits & RestrictiveFlagMASK) {
+ case FIELD : // reading a field
+ // check if reading a final blank field
+ FieldBinding fieldBinding;
+ if ((fieldBinding = (FieldBinding) binding).isFinal()
+ && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
+ if (!flowInfo.isDefinitelyAssigned(fieldBinding)) {
+ currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
+ }
+ }
+ break;
+ case LOCAL : // reading a local variable
+ LocalVariableBinding localBinding;
+ if (!flowInfo
+ .isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
+ currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
+ }
+ if (!flowInfo.isFakeReachable())
+ localBinding.used = true;
+ }
+ return flowInfo;
+ }
+
+ /**
+ * Check and/or redirect the field access to the delegate receiver if any
+ */
+ public TypeBinding checkFieldAccess(BlockScope scope) {
+
+ if (delegateThis == null)
+ return super.checkFieldAccess(scope);
+
+ FieldBinding fieldBinding = (FieldBinding) binding;
+ bits &= ~RestrictiveFlagMASK; // clear bits
+ bits |= FIELD;
+ if (!fieldBinding.isStatic()) {
+ // must check for the static status....
+ if (this.evaluationContext.isStatic) {
+ scope.problemReporter().staticFieldAccessToNonStaticVariable(
+ this,
+ fieldBinding);
+ constant = NotAConstant;
+ return null;
+ }
+ }
+ constant = FieldReference.getConstantFor(fieldBinding, true, this, 0);
+ if (isFieldUseDeprecated(fieldBinding, scope))
+ scope.problemReporter().deprecatedField(fieldBinding, this);
+ // if the binding declaring class is not visible, need special action
+ // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
+ if (fieldBinding.declaringClass != null
+ && fieldBinding.constant == NotAConstant
+ && !fieldBinding.declaringClass.canBeSeenBy(scope)) {
+ binding = new FieldBinding(fieldBinding, scope.enclosingSourceType());
+ }
+ return fieldBinding.type;
+
+ }
+
+ public void generateAssignment(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ Assignment assignment,
+ boolean valueRequired) {
+
+ // optimizing assignment like: i = i + 1 or i = 1 + i
+ if (assignment.expression.isCompactableOperation()) {
+ BinaryExpression operation = (BinaryExpression) assignment.expression;
+ SingleNameReference variableReference;
+ if ((operation.left instanceof SingleNameReference)
+ && ((variableReference = (SingleNameReference) operation.left).binding
+ == binding)) {
+ // i = i + value, then use the variable on the right hand side, since it has the correct implicit conversion
+ variableReference.generateCompoundAssignment(
+ currentScope,
+ codeStream,
+ syntheticAccessors == null ? null : syntheticAccessors[WRITE],
+ operation.right,
+ (operation.bits & OperatorMASK) >> OperatorSHIFT,
+ operation.left.implicitConversion /*should be equivalent to no conversion*/,
+ valueRequired);
+ return;
+ }
+ int operator = (operation.bits & OperatorMASK) >> OperatorSHIFT;
+ if ((operation.right instanceof SingleNameReference)
+ && ((operator == PLUS)
+ || (operator == MULTIPLY)) // only commutative operations
+ && ((variableReference = (SingleNameReference) operation.right).binding
+ == binding)
+ && (operation.left.constant != NotAConstant)
+ // exclude non constant expressions, since could have side-effect
+ && ((operation.implicitConversion >> 4) != T_String)) {
+ // exclude string concatenation which would occur backwards
+ // i = value + i, then use the variable on the right hand side, since it has the correct implicit conversion
+ variableReference.generateCompoundAssignment(
+ currentScope,
+ codeStream,
+ syntheticAccessors == null ? null : syntheticAccessors[WRITE],
+ operation.left,
+ operator,
+ operation.right.implicitConversion /*should be equivalent to no conversion*/,
+ valueRequired);
+ return;
+ }
+ }
+ switch (bits & RestrictiveFlagMASK) {
+ case FIELD : // assigning to a field
+ FieldBinding fieldBinding = (FieldBinding) binding;
+ if (fieldBinding
+ .canBeSeenBy(getReceiverType(currentScope), this, currentScope)) {
+ if (!fieldBinding.isStatic()) { // need a receiver?
+ if ((bits & DepthMASK) != 0) {
+ Object[] emulationPath =
+ currentScope.getExactEmulationPath(
+ currentScope.enclosingSourceType().enclosingTypeAt(
+ (bits & DepthMASK) >> DepthSHIFT));
+ if (emulationPath == null) {
+ // internal error, per construction we should have found it
+ currentScope.problemReporter().needImplementation();
+ } else {
+ codeStream.generateOuterAccess(emulationPath, this, currentScope);
+ }
+ } else {
+ this.generateReceiver(codeStream);
+ }
+ }
+ assignment.expression.generateCode(currentScope, codeStream, true);
+ fieldStore(codeStream, fieldBinding, null, valueRequired);
+ if (valueRequired) {
+ codeStream.generateImplicitConversion(assignment.implicitConversion);
+ }
+ } else {
+ ((CodeSnippetCodeStream) codeStream).generateEmulationForField(fieldBinding);
+ if (!fieldBinding.isStatic()) { // need a receiver?
+ if ((bits & DepthMASK) != 0) {
+ // internal error, per construction we should have found it
+ // not yet supported
+ currentScope.problemReporter().needImplementation();
+ } else {
+ this.generateReceiver(codeStream);
+ }
+ } else {
+ codeStream.aconst_null();
+ }
+ assignment.expression.generateCode(currentScope, codeStream, true);
+ if (valueRequired) {
+ if ((fieldBinding.type == LongBinding)
+ || (fieldBinding.type == DoubleBinding)) {
+ codeStream.dup2_x2();
+ } else {
+ codeStream.dup_x2();
+ }
+ }
+ ((CodeSnippetCodeStream) codeStream).generateEmulatedWriteAccessForField(
+ fieldBinding);
+ if (valueRequired) {
+ codeStream.generateImplicitConversion(assignment.implicitConversion);
+ }
+ }
+ return;
+ case LOCAL : // assigning to a local variable
+ LocalVariableBinding localBinding = (LocalVariableBinding) binding;
+ if (localBinding.resolvedPosition != -1) {
+ assignment.expression.generateCode(currentScope, codeStream, true);
+ } else {
+ if (assignment.expression.constant != NotAConstant) {
+ // assigning an unused local to a constant value = no actual assignment is necessary
+ if (valueRequired) {
+ codeStream.generateConstant(
+ assignment.expression.constant,
+ assignment.implicitConversion);
+ }
+ } else {
+ assignment.expression.generateCode(currentScope, codeStream, true);
+ /* Even though the value may not be required, we force it to be produced, and discard it later
+ on if it was actually not necessary, so as to provide the same behavior as JDK1.2beta3. */
+ if (valueRequired) {
+ codeStream.generateImplicitConversion(assignment.implicitConversion);
+ // implicit conversion
+ } else {
+ if ((localBinding.type == LongBinding)
+ || (localBinding.type == DoubleBinding)) {
+ codeStream.pop2();
+ } else {
+ codeStream.pop();
+ }
+ }
+ }
+ return;
+ }
+ // normal local assignment (since cannot store in outer local which are final locations)
+ codeStream.store(localBinding, valueRequired);
+ if ((bits & FirstAssignmentToLocalMASK) != 0) {
+ // for local variable debug attributes
+ localBinding.recordInitializationStartPC(codeStream.position);
+ }
+ // implicit conversion
+ if (valueRequired) {
+ codeStream.generateImplicitConversion(assignment.implicitConversion);
+ }
+ }
+ }
+
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ if (constant != NotAConstant) {
+ if (valueRequired) {
+ codeStream.generateConstant(constant, implicitConversion);
+ }
+ } else {
+ switch (bits & RestrictiveFlagMASK) {
+ case FIELD : // reading a field
+ FieldBinding fieldBinding;
+ if (valueRequired) {
+ if ((fieldBinding = (FieldBinding) binding).constant == NotAConstant) {
+ // directly use inlined value for constant fields
+ if (fieldBinding
+ .canBeSeenBy(getReceiverType(currentScope), this, currentScope)) {
+ // directly use inlined value for constant fields
+ boolean isStatic;
+ if (!(isStatic = fieldBinding.isStatic())) {
+ if ((bits & DepthMASK) != 0) {
+ Object[] emulationPath =
+ currentScope.getExactEmulationPath(
+ currentScope.enclosingSourceType().enclosingTypeAt(
+ (bits & DepthMASK) >> DepthSHIFT));
+ if (emulationPath == null) {
+ // internal error, per construction we should have found it
+ currentScope.problemReporter().needImplementation();
+ } else {
+ codeStream.generateOuterAccess(emulationPath, this, currentScope);
+ }
+ } else {
+ generateReceiver(codeStream);
+ }
+ }
+ // managing private access
+ if (isStatic) {
+ codeStream.getstatic(fieldBinding);
+ } else {
+ codeStream.getfield(fieldBinding);
+ }
+ } else {
+ // managing private access
+ if (!fieldBinding.isStatic()) {
+ if ((bits & DepthMASK) != 0) {
+ // internal error, per construction we should have found it
+ // not yet supported
+ currentScope.problemReporter().needImplementation();
+ } else {
+ generateReceiver(codeStream);
+ }
+ } else {
+ codeStream.aconst_null();
+ }
+ ((CodeSnippetCodeStream) codeStream).generateEmulatedReadAccessForField(
+ fieldBinding);
+ }
+ codeStream.generateImplicitConversion(implicitConversion);
+ } else { // directly use the inlined value
+ codeStream.generateConstant(fieldBinding.constant, implicitConversion);
+ }
+ }
+ break;
+ case LOCAL : // reading a local
+ LocalVariableBinding localBinding = (LocalVariableBinding) binding;
+ if (valueRequired) {
+ // outer local?
+ if ((bits & DepthMASK) != 0) {
+ // outer local can be reached either through a synthetic arg or a synthetic field
+ VariableBinding[] path = currentScope.getEmulationPath(localBinding);
+ if (path == null) {
+ // emulation was not possible (should not happen per construction)
+ currentScope.problemReporter().needImplementation();
+ } else {
+ codeStream.generateOuterAccess(path, this, currentScope);
+ }
+ } else {
+ // regular local variable read
+ codeStream.load(localBinding);
+ }
+ codeStream.generateImplicitConversion(implicitConversion);
+ }
+ }
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ /*
+ * The APIs with an extra argument is used whenever there are two references to the same variable which
+ * are optimized in one access: e.g "a = a + 1" optimized into "a++".
+ */
+ public void generateCompoundAssignment(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ MethodBinding writeAccessor,
+ Expression expression,
+ int operator,
+ int assignmentImplicitConversion,
+ boolean valueRequired) {
+ switch (bits & RestrictiveFlagMASK) {
+ case FIELD : // assigning to a field
+ FieldBinding fieldBinding = (FieldBinding) binding;
+ if (fieldBinding.isStatic()) {
+ if (fieldBinding
+ .canBeSeenBy(getReceiverType(currentScope), this, currentScope)) {
+ codeStream.getstatic(fieldBinding);
+ } else {
+ // used to store the value
+ ((CodeSnippetCodeStream) codeStream).generateEmulationForField(fieldBinding);
+ codeStream.aconst_null();
+
+ // used to retrieve the actual value
+ codeStream.aconst_null();
+ ((CodeSnippetCodeStream) codeStream).generateEmulatedReadAccessForField(
+ fieldBinding);
+ }
+ } else {
+ if (fieldBinding
+ .canBeSeenBy(getReceiverType(currentScope), this, currentScope)) {
+ if ((bits & DepthMASK) != 0) {
+ Object[] emulationPath =
+ currentScope.getExactEmulationPath(
+ currentScope.enclosingSourceType().enclosingTypeAt(
+ (bits & DepthMASK) >> DepthSHIFT));
+ if (emulationPath == null) {
+ // internal error, per construction we should have found it
+ currentScope.problemReporter().needImplementation();
+ } else {
+ codeStream.generateOuterAccess(emulationPath, this, currentScope);
+ }
+ } else {
+ generateReceiver(codeStream);
+ }
+ codeStream.dup();
+ codeStream.getfield(fieldBinding);
+ } else {
+ if ((bits & DepthMASK) != 0) {
+ // internal error, per construction we should have found it
+ // not yet supported
+ currentScope.problemReporter().needImplementation();
+ }
+ // used to store the value
+ ((CodeSnippetCodeStream) codeStream).generateEmulationForField(fieldBinding);
+ generateReceiver(codeStream);
+
+ // used to retrieve the actual value
+ codeStream.dup();
+ ((CodeSnippetCodeStream) codeStream).generateEmulatedReadAccessForField(
+ fieldBinding);
+ }
+ }
+ break;
+ case LOCAL : // assigning to a local variable (cannot assign to outer local)
+ LocalVariableBinding localBinding = (LocalVariableBinding) binding;
+ Constant assignConstant;
+ int increment;
+ // using incr bytecode if possible
+ switch (localBinding.type.id) {
+ case T_String :
+ codeStream.generateStringAppend(currentScope, this, expression);
+ if (valueRequired) {
+ codeStream.dup();
+ }
+ codeStream.store(localBinding, false);
+ return;
+ case T_int :
+ if (((assignConstant = expression.constant) != NotAConstant)
+ && ((increment = assignConstant.intValue()) == (short) increment)) {
+ // 16 bits value
+ switch (operator) {
+ case PLUS :
+ codeStream.iinc(localBinding.resolvedPosition, increment);
+ if (valueRequired) {
+ codeStream.load(localBinding);
+ }
+ return;
+ case MINUS :
+ codeStream.iinc(localBinding.resolvedPosition, -increment);
+ if (valueRequired) {
+ codeStream.load(localBinding);
+ }
+ return;
+ }
+ }
+ default :
+ codeStream.load(localBinding);
+ }
+ }
+ // perform the actual compound operation
+ int operationTypeID;
+ if ((operationTypeID = implicitConversion >> 4) == T_String) {
+ codeStream.generateStringAppend(currentScope, null, expression);
+ } else {
+ // promote the array reference to the suitable operation type
+ codeStream.generateImplicitConversion(implicitConversion);
+ // generate the increment value (will by itself be promoted to the operation value)
+ if (expression == IntLiteral.One) { // prefix operation
+ codeStream.generateConstant(expression.constant, implicitConversion);
+ } else {
+ expression.generateCode(currentScope, codeStream, true);
+ }
+ // perform the operation
+ codeStream.sendOperator(operator, operationTypeID);
+ // cast the value back to the array reference type
+ codeStream.generateImplicitConversion(assignmentImplicitConversion);
+ }
+ // store the result back into the variable
+ switch (bits & RestrictiveFlagMASK) {
+ case FIELD : // assigning to a field
+ FieldBinding fieldBinding = (FieldBinding) binding;
+ if (fieldBinding
+ .canBeSeenBy(getReceiverType(currentScope), this, currentScope)) {
+ fieldStore(codeStream, (FieldBinding) binding, writeAccessor, valueRequired);
+ } else {
+ // current stack is:
+ // field receiver value
+ if (valueRequired) {
+ if ((fieldBinding.type == LongBinding)
+ || (fieldBinding.type == DoubleBinding)) {
+ codeStream.dup2_x2();
+ } else {
+ codeStream.dup_x2();
+ }
+ }
+ // current stack is:
+ // value field receiver value
+ ((CodeSnippetCodeStream) codeStream).generateEmulatedWriteAccessForField(
+ fieldBinding);
+ }
+ return;
+ case LOCAL : // assigning to a local variable
+ LocalVariableBinding localBinding = (LocalVariableBinding) binding;
+ if (valueRequired) {
+ if ((localBinding.type == LongBinding)
+ || (localBinding.type == DoubleBinding)) {
+ codeStream.dup2();
+ } else {
+ codeStream.dup();
+ }
+ }
+ codeStream.store(localBinding, false);
+ }
+ }
+
+ public void generatePostIncrement(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ CompoundAssignment postIncrement,
+ boolean valueRequired) {
+ switch (bits & RestrictiveFlagMASK) {
+ case FIELD : // assigning to a field
+ FieldBinding fieldBinding = (FieldBinding) binding;
+ if (fieldBinding
+ .canBeSeenBy(getReceiverType(currentScope), this, currentScope)) {
+ if (fieldBinding.isStatic()) {
+ codeStream.getstatic(fieldBinding);
+ } else {
+ if ((bits & DepthMASK) != 0) {
+ Object[] emulationPath =
+ currentScope.getExactEmulationPath(
+ currentScope.enclosingSourceType().enclosingTypeAt(
+ (bits & DepthMASK) >> DepthSHIFT));
+ if (emulationPath == null) {
+ // internal error, per construction we should have found it
+ currentScope.problemReporter().needImplementation();
+ } else {
+ codeStream.generateOuterAccess(emulationPath, this, currentScope);
+ }
+ } else {
+ generateReceiver(codeStream);
+ }
+ codeStream.dup();
+ codeStream.getfield(fieldBinding);
+ }
+ if (valueRequired) {
+ if (fieldBinding.isStatic()) {
+ if ((fieldBinding.type == LongBinding)
+ || (fieldBinding.type == DoubleBinding)) {
+ codeStream.dup2();
+ } else {
+ codeStream.dup();
+ }
+ } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value]
+ if ((fieldBinding.type == LongBinding)
+ || (fieldBinding.type == DoubleBinding)) {
+ codeStream.dup2_x1();
+ } else {
+ codeStream.dup_x1();
+ }
+ }
+ }
+ codeStream.generateConstant(
+ postIncrement.expression.constant,
+ implicitConversion);
+ codeStream.sendOperator(postIncrement.operator, fieldBinding.type.id);
+ codeStream.generateImplicitConversion(
+ postIncrement.assignmentImplicitConversion);
+ fieldStore(codeStream, fieldBinding, null, false);
+ } else {
+ if (fieldBinding.isStatic()) {
+ codeStream.aconst_null();
+ } else {
+ if ((bits & DepthMASK) != 0) {
+ // internal error, per construction we should have found it
+ // not yet supported
+ currentScope.problemReporter().needImplementation();
+ } else {
+ generateReceiver(codeStream);
+ }
+ }
+ ((CodeSnippetCodeStream) codeStream).generateEmulatedReadAccessForField(
+ fieldBinding);
+ if (valueRequired) {
+ if ((fieldBinding.type == LongBinding)
+ || (fieldBinding.type == DoubleBinding)) {
+ codeStream.dup2();
+ } else {
+ codeStream.dup();
+ }
+ }
+ ((CodeSnippetCodeStream) codeStream).generateEmulationForField(fieldBinding);
+ if ((fieldBinding.type == LongBinding)
+ || (fieldBinding.type == DoubleBinding)) {
+ codeStream.dup_x2();
+ codeStream.pop();
+ if (fieldBinding.isStatic()) {
+ codeStream.aconst_null();
+ } else {
+ generateReceiver(codeStream);
+ }
+ codeStream.dup_x2();
+ codeStream.pop();
+ } else {
+ codeStream.dup_x1();
+ codeStream.pop();
+ if (fieldBinding.isStatic()) {
+ codeStream.aconst_null();
+ } else {
+ generateReceiver(codeStream);
+ }
+ codeStream.dup_x1();
+ codeStream.pop();
+ }
+ codeStream.generateConstant(
+ postIncrement.expression.constant,
+ implicitConversion);
+ codeStream.sendOperator(postIncrement.operator, fieldBinding.type.id);
+ codeStream.generateImplicitConversion(
+ postIncrement.assignmentImplicitConversion);
+ ((CodeSnippetCodeStream) codeStream).generateEmulatedWriteAccessForField(
+ fieldBinding);
+ }
+ return;
+ case LOCAL : // assigning to a local variable
+ LocalVariableBinding localBinding = (LocalVariableBinding) binding;
+ // using incr bytecode if possible
+ if (localBinding.type == IntBinding) {
+ if (valueRequired) {
+ codeStream.load(localBinding);
+ }
+ if (postIncrement.operator == PLUS) {
+ codeStream.iinc(localBinding.resolvedPosition, 1);
+ } else {
+ codeStream.iinc(localBinding.resolvedPosition, -1);
+ }
+ } else {
+ codeStream.load(localBinding);
+ if (valueRequired) {
+ if ((localBinding.type == LongBinding)
+ || (localBinding.type == DoubleBinding)) {
+ codeStream.dup2();
+ } else {
+ codeStream.dup();
+ }
+ }
+ codeStream.generateConstant(
+ postIncrement.expression.constant,
+ implicitConversion);
+ codeStream.sendOperator(postIncrement.operator, localBinding.type.id);
+ codeStream.generateImplicitConversion(
+ postIncrement.assignmentImplicitConversion);
+
+ codeStream.store(localBinding, false);
+ }
+ }
+ }
+
+ public void generateReceiver(CodeStream codeStream) {
+ codeStream.aload_0();
+ if (delegateThis != null)
+ codeStream.getfield(delegateThis); // delegated field access
+ }
+
+ /**
+ * Check and/or redirect the field access to the delegate receiver if any
+ */
+ public TypeBinding getReceiverType(BlockScope currentScope) {
+ if (receiverType != null)
+ return receiverType;
+ Scope scope = currentScope.parent;
+ while (true) {
+ switch (scope.kind) {
+ case Scope.CLASS_SCOPE :
+ return receiverType = ((ClassScope) scope).referenceContext.binding;
+ default :
+ scope = scope.parent;
+ }
+ }
+ }
+
+ /**
+ * Normal field binding did not work, try to bind to a field of the delegate receiver.
+ */
+ public TypeBinding reportError(BlockScope scope) {
+
+ constant = Constant.NotAConstant;
+ if (binding instanceof ProblemFieldBinding
+ && ((ProblemFieldBinding) binding).problemId() == NotFound) {
+ if (this.evaluationContext.declaringTypeName != null) {
+ delegateThis = scope.getField(scope.enclosingSourceType(), DELEGATE_THIS, this);
+ if (delegateThis != null) {
+ ; // if not found then internal error, field should have been found
+ // will not support innerclass emulation inside delegate
+ binding = scope.getField(delegateThis.type, this.token, this);
+ if (!binding.isValidBinding())
+ return super.reportError(scope);
+ return checkFieldAccess(scope);
+ }
+ }
+ }
+ if (binding instanceof ProblemBinding
+ && ((ProblemBinding) binding).problemId() == NotFound) {
+ if (this.evaluationContext.declaringTypeName != null) {
+ delegateThis = scope.getField(scope.enclosingSourceType(), DELEGATE_THIS, this);
+ if (delegateThis != null) {
+ ; // if not found then internal error, field should have been found
+ // will not support innerclass emulation inside delegate
+ FieldBinding fieldBinding = scope.getField(delegateThis.type, this.token, this);
+ if (!fieldBinding.isValidBinding()) {
+ if (((ProblemFieldBinding) fieldBinding).problemId() == NotVisible) {
+ // manage the access to a private field of the enclosing type
+ CodeSnippetScope localScope = new CodeSnippetScope(scope);
+ binding =
+ localScope.getFieldForCodeSnippet(delegateThis.type, this.token, this);
+ return checkFieldAccess(scope);
+ } else {
+ return super.reportError(scope);
+ }
+ }
+ binding = fieldBinding;
+ return checkFieldAccess(scope);
+ }
+ }
+ }
+ return super.reportError(scope);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetSkeleton.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetSkeleton.java
new file mode 100644
index 0000000000..0bd225da26
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetSkeleton.java
@@ -0,0 +1,134 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+
+/**
+ * The skeleton of the class 'org.eclipse.jdt.internal.eval.target.CodeSnippet'
+ * used at compile time. Note that the method run() is declared to
+ * throw Throwable so that the user can write a code snipet that
+ * throws checked exceptio without having to catch those.
+ */
+public class CodeSnippetSkeleton implements IBinaryType, EvaluationConstants {
+ IBinaryMethod[] methods =
+ new IBinaryMethod[] { new BinaryMethodSkeleton(
+ "<init>".toCharArray(),
+ "()V".toCharArray(),
+ new char[][] {
+ },
+ true),
+ new BinaryMethodSkeleton(
+ "run".toCharArray(),
+ "()V".toCharArray(),
+ new char[][] { "java/lang/Throwable".toCharArray()},
+ false),
+ new BinaryMethodSkeleton(
+ "setResult".toCharArray(),
+ "(Ljava/lang/Object;Ljava/lang/Class;)V".toCharArray(),
+ new char[][] {
+ }, false)
+ };
+
+ public class BinaryMethodSkeleton implements IBinaryMethod {
+ char[][] exceptionTypeNames;
+ char[] methodDescriptor;
+ char[] selector;
+ boolean isConstructor;
+
+ public BinaryMethodSkeleton(
+ char[] selector,
+ char[] methodDescriptor,
+ char[][] exceptionTypeNames,
+ boolean isConstructor) {
+ this.selector = selector;
+ this.methodDescriptor = methodDescriptor;
+ this.exceptionTypeNames = exceptionTypeNames;
+ this.isConstructor = this.isConstructor;
+ }
+
+ public char[][] getExceptionTypeNames() {
+ return this.exceptionTypeNames;
+ }
+
+ public char[] getMethodDescriptor() {
+ return this.methodDescriptor;
+ }
+
+ public int getModifiers() {
+ return IConstants.AccPublic;
+ }
+
+ public char[] getSelector() {
+ return this.selector;
+ }
+
+ public boolean isClinit() {
+ return false;
+ }
+
+ public boolean isConstructor() {
+ return this.isConstructor;
+ }
+ }
+
+ /**
+ * CodeSnippetSkeleton constructor comment.
+ */
+ public CodeSnippetSkeleton() {
+ super();
+ }
+
+ public char[] getEnclosingTypeName() {
+ return null;
+ }
+
+ public IBinaryField[] getFields() {
+ return null;
+ }
+
+ public char[] getFileName() {
+ return CharOperation.concat(CODE_SNIPPET_NAME, ".java".toCharArray());
+ }
+
+ public char[][] getInterfaceNames() {
+ return null;
+ }
+
+ public IBinaryNestedType[] getMemberTypes() {
+ return null;
+ }
+
+ public IBinaryMethod[] getMethods() {
+ return this.methods;
+ }
+
+ public int getModifiers() {
+ return IConstants.AccPublic;
+ }
+
+ public char[] getName() {
+ return CODE_SNIPPET_NAME;
+ }
+
+ public char[] getSuperclassName() {
+ return null;
+ }
+
+ public boolean isBinaryType() {
+ return true;
+ }
+
+ public boolean isClass() {
+ return true;
+ }
+
+ public boolean isInterface() {
+ return false;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetThisReference.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetThisReference.java
new file mode 100644
index 0000000000..c17fbbccb4
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetThisReference.java
@@ -0,0 +1,103 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+/**
+ * A this reference inside a code snippet denotes a remote
+ * receiver object (i.e. the one of the context in the stack
+ * frame)
+ */
+public class CodeSnippetThisReference
+ extends ThisReference
+ implements EvaluationConstants, InvocationSite {
+ EvaluationContext evaluationContext;
+ FieldBinding delegateThis;
+ boolean isImplicit;
+ /**
+ * CodeSnippetThisReference constructor comment.
+ * @param s int
+ * @param sourceEnd int
+ */
+ public CodeSnippetThisReference(
+ int s,
+ int sourceEnd,
+ EvaluationContext evaluationContext,
+ boolean isImplicit) {
+ super(s, sourceEnd);
+ this.evaluationContext = evaluationContext;
+ this.isImplicit = isImplicit;
+ }
+
+ protected boolean checkAccess(MethodScope methodScope) {
+ // this/super cannot be used in constructor call
+ if (evaluationContext.isConstructorCall) {
+ methodScope.problemReporter().fieldsOrThisBeforeConstructorInvocation(this);
+ return false;
+ }
+
+ // static may not refer to this/super
+ if (this.evaluationContext.declaringTypeName == null
+ || evaluationContext.isStatic) {
+ methodScope.problemReporter().errorThisSuperInStatic(this);
+ return false;
+ }
+ return true;
+ }
+
+ public void generateCode(
+ BlockScope currentScope,
+ CodeStream codeStream,
+ boolean valueRequired) {
+ int pc = codeStream.position;
+ if (valueRequired) {
+ codeStream.aload_0();
+ codeStream.getfield(delegateThis);
+ }
+ codeStream.recordPositionsFrom(pc, this);
+ }
+
+ public boolean isSuperAccess() {
+ return false;
+ }
+
+ public boolean isTypeAccess() {
+ return false;
+ }
+
+ public TypeBinding resolveType(BlockScope scope) {
+
+ // implicit this
+ constant = NotAConstant;
+ TypeBinding snippetType = null;
+ if (this.isImplicit || checkAccess(scope.methodScope())) {
+ snippetType = scope.enclosingSourceType();
+ }
+ if (snippetType == null)
+ return null;
+
+ delegateThis = scope.getField(snippetType, DELEGATE_THIS, this);
+ if (delegateThis == null)
+ return null; // internal error, field should have been found
+ return delegateThis.type;
+ }
+
+ public void setDepth(int depth) {
+ }
+
+ public void setFieldIndex(int index) {
+ }
+
+ public String toStringExpression() {
+ char[] declaringType = this.evaluationContext.declaringTypeName;
+ return "("
+ + (declaringType == null ? "<NO DECLARING TYPE>" : new String(declaringType))
+ + ")this";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetToCuMapper.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetToCuMapper.java
new file mode 100644
index 0000000000..2a24db35d6
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetToCuMapper.java
@@ -0,0 +1,435 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.codeassist.*;
+import org.eclipse.jdt.internal.compiler.IProblem;
+import org.eclipse.jdt.internal.compiler.env.IConstants;
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+import org.eclipse.jdt.internal.core.JavaModelManager;
+
+/**
+ * Maps back and forth a code snippet to a compilation unit.
+ * The structure of the compilation unit is as follows:
+ * [package <package name>;]
+ * [import <import name>;]*
+ * public class <code snippet class name> extends <global variable class name> {
+ * public void run() {
+ * <code snippet>
+ * }
+ * }
+ */
+class CodeSnippetToCuMapper implements EvaluationConstants {
+ /**
+ * The generated compilation unit.
+ */
+ public char[] cuSource;
+
+ /**
+ * Where the code snippet starts in the generated compilation unit.
+ */
+ public int lineNumberOffset = 0;
+ public int startPosOffset = 0;
+
+ // Internal fields
+ private char[] codeSnippet;
+ private char[] packageName;
+ private char[][] imports;
+ char[] className;
+ // NB: Make it package default visibility to optimize access from inner classes
+ private char[] varClassName;
+
+ // Mapping of external local variables
+ private char[][] localVarNames;
+ private char[][] localVarTypeNames;
+ private int[] localVarModifiers;
+ private char[] declaringTypeName;
+
+ /**
+ * Rebuild source in presence of external local variables
+ */
+ public CodeSnippetToCuMapper(
+ char[] codeSnippet,
+ char[] packageName,
+ char[][] imports,
+ char[] className,
+ char[] varClassName,
+ char[][] localVarNames,
+ char[][] localVarTypeNames,
+ int[] localVarModifiers,
+ char[] declaringTypeName) {
+ this.codeSnippet = codeSnippet;
+ this.packageName = packageName;
+ this.imports = imports;
+ this.className = className;
+ this.varClassName = varClassName;
+ this.localVarNames = localVarNames;
+ this.localVarTypeNames = localVarTypeNames;
+ this.localVarModifiers = localVarModifiers;
+ this.declaringTypeName = declaringTypeName;
+ this.buildCUSource();
+ }
+
+ private void buildCUSource() {
+ StringBuffer buffer = new StringBuffer();
+
+ // package declaration
+ if (this.packageName != null && this.packageName.length != 0) {
+ buffer.append("package ");
+ buffer.append(this.packageName);
+ buffer.append(";").append(JavaModelManager.LINE_SEPARATOR);
+ this.lineNumberOffset++;
+ }
+
+ // import declarations
+ char[][] imports = this.imports;
+ for (int i = 0; i < imports.length; i++) {
+ buffer.append("import ");
+ buffer.append(imports[i]);
+ buffer.append(';').append(JavaModelManager.LINE_SEPARATOR);
+ this.lineNumberOffset++;
+ }
+
+ // class declaration
+ buffer.append("public class ");
+ buffer.append(this.className);
+
+ // super class is either a global variable class or the CodeSnippet class
+ if (this.varClassName != null) {
+ buffer.append(" extends ");
+ buffer.append(this.varClassName);
+ } else {
+ buffer.append(" extends ");
+ buffer.append(PACKAGE_NAME);
+ buffer.append(".");
+ buffer.append(ROOT_CLASS_NAME);
+ }
+ buffer.append(" {").append(JavaModelManager.LINE_SEPARATOR);
+ this.lineNumberOffset++;
+
+ if (this.declaringTypeName != null) {
+ buffer.append(" ");
+ buffer.append(this.declaringTypeName);
+ buffer.append(" ");
+ buffer.append(DELEGATE_THIS); // val$this
+ buffer.append(';').append(JavaModelManager.LINE_SEPARATOR);
+ this.lineNumberOffset++;
+ }
+ // add some storage location for local variable persisted state
+ if (localVarNames != null) {
+ for (int i = 0, max = localVarNames.length; i < max; i++) {
+ buffer.append(" ");
+ buffer.append(localVarTypeNames[i]);
+ buffer.append(" ");
+ buffer.append(LOCAL_VAR_PREFIX); // val$...
+ buffer.append(localVarNames[i]);
+ buffer.append(';').append(JavaModelManager.LINE_SEPARATOR);
+ this.lineNumberOffset++;
+ }
+ }
+ // run() method declaration
+ buffer.append("public void run() throws Throwable {").append(
+ JavaModelManager.LINE_SEPARATOR);
+ this.lineNumberOffset++;
+ startPosOffset = buffer.length();
+ buffer.append(codeSnippet);
+ buffer.append('}').append(JavaModelManager.LINE_SEPARATOR);
+
+ // end of class declaration
+ buffer.append('}').append(JavaModelManager.LINE_SEPARATOR);
+
+ // store result
+ int length = buffer.length();
+ this.cuSource = new char[length];
+ buffer.getChars(0, length, this.cuSource, 0);
+ }
+
+ /**
+ * Returns a completion requestor that wraps the given requestor and shift the results
+ * according to the start offset and line number offset of the code snippet in the generated compilation unit.
+ */
+ public ICompletionRequestor getCompletionRequestor(final ICompletionRequestor originalRequestor) {
+ final int startPosOffset = this.startPosOffset;
+ final int lineNumberOffset = this.lineNumberOffset;
+ return new ICompletionRequestor() {
+ public void acceptClass(
+ char[] packageName,
+ char[] className,
+ char[] completionName,
+ int modifiers,
+ int completionStart,
+ int completionEnd) {
+ // Remove completion on generated class name or generated global variable class name
+ if (CharOperation.equals(packageName, CodeSnippetToCuMapper.this.packageName)
+ && (CharOperation.equals(className, CodeSnippetToCuMapper.this.className)
+ || CharOperation.equals(className, CodeSnippetToCuMapper.this.varClassName)))
+ return;
+ originalRequestor.acceptClass(
+ packageName,
+ className,
+ completionName,
+ modifiers,
+ completionStart - startPosOffset,
+ completionEnd - startPosOffset);
+ }
+ public void acceptError(IProblem error) {
+ error.setSourceLineNumber(error.getSourceLineNumber() - lineNumberOffset);
+ error.setSourceStart(error.getSourceStart() - startPosOffset);
+ error.setSourceEnd(error.getSourceEnd() - startPosOffset);
+ originalRequestor.acceptError(error);
+ }
+ public void acceptField(
+ char[] declaringTypePackageName,
+ char[] declaringTypeName,
+ char[] name,
+ char[] typePackageName,
+ char[] typeName,
+ char[] completionName,
+ int modifiers,
+ int completionStart,
+ int completionEnd) {
+ originalRequestor.acceptField(
+ declaringTypePackageName,
+ declaringTypeName,
+ name,
+ typePackageName,
+ typeName,
+ completionName,
+ modifiers,
+ completionStart - startPosOffset,
+ completionEnd - startPosOffset);
+ }
+ public void acceptInterface(
+ char[] packageName,
+ char[] interfaceName,
+ char[] completionName,
+ int modifiers,
+ int completionStart,
+ int completionEnd) {
+ originalRequestor.acceptInterface(
+ packageName,
+ interfaceName,
+ completionName,
+ modifiers,
+ completionStart - startPosOffset,
+ completionEnd - startPosOffset);
+ }
+ public void acceptKeyword(
+ char[] keywordName,
+ int completionStart,
+ int completionEnd) {
+ originalRequestor.acceptKeyword(
+ keywordName,
+ completionStart - startPosOffset,
+ completionEnd - startPosOffset);
+ }
+ public void acceptLabel(
+ char[] labelName,
+ int completionStart,
+ int completionEnd) {
+ originalRequestor.acceptLabel(
+ labelName,
+ completionStart - startPosOffset,
+ completionEnd - startPosOffset);
+ }
+ public void acceptLocalVariable(
+ char[] name,
+ char[] typePackageName,
+ char[] typeName,
+ int modifiers,
+ int completionStart,
+ int completionEnd) {
+ originalRequestor.acceptLocalVariable(
+ name,
+ typePackageName,
+ typeName,
+ modifiers,
+ completionStart - startPosOffset,
+ completionEnd - startPosOffset);
+ }
+ public void acceptMethod(
+ char[] declaringTypePackageName,
+ char[] declaringTypeName,
+ char[] selector,
+ char[][] parameterPackageNames,
+ char[][] parameterTypeNames,
+ char[] returnTypePackageName,
+ char[] returnTypeName,
+ char[] completionName,
+ int modifiers,
+ int completionStart,
+ int completionEnd) {
+ // Remove completion on generated method
+ if (CharOperation
+ .equals(declaringTypePackageName, CodeSnippetToCuMapper.this.packageName)
+ && CharOperation.equals(declaringTypeName, CodeSnippetToCuMapper.this.className)
+ && CharOperation.equals(selector, "run".toCharArray()))
+ return;
+ originalRequestor.acceptMethod(
+ declaringTypePackageName,
+ declaringTypeName,
+ selector,
+ parameterPackageNames,
+ parameterTypeNames,
+ returnTypePackageName,
+ returnTypeName,
+ completionName,
+ modifiers,
+ completionStart - startPosOffset,
+ completionEnd - startPosOffset);
+ }
+ public void acceptModifier(
+ char[] modifierName,
+ int completionStart,
+ int completionEnd) {
+ originalRequestor.acceptModifier(
+ modifierName,
+ completionStart - startPosOffset,
+ completionEnd - startPosOffset);
+ }
+ public void acceptPackage(
+ char[] packageName,
+ char[] completionName,
+ int completionStart,
+ int completionEnd) {
+ originalRequestor.acceptPackage(
+ packageName,
+ completionName,
+ completionStart - startPosOffset,
+ completionEnd - startPosOffset);
+ }
+ public void acceptType(
+ char[] packageName,
+ char[] typeName,
+ char[] completionName,
+ int completionStart,
+ int completionEnd) {
+ // Remove completion on generated class name or generated global variable class name
+ if (CharOperation.equals(packageName, CodeSnippetToCuMapper.this.packageName)
+ && (CharOperation.equals(className, CodeSnippetToCuMapper.this.className)
+ || CharOperation.equals(className, CodeSnippetToCuMapper.this.varClassName)))
+ return;
+ originalRequestor.acceptType(
+ packageName,
+ typeName,
+ completionName,
+ completionStart - startPosOffset,
+ completionEnd - startPosOffset);
+ }
+ };
+ }
+
+ public char[] getCUSource() {
+ if (this.cuSource == null) {
+ buildCUSource();
+ }
+ return this.cuSource;
+ }
+
+ /**
+ * Returns the type of evaluation that corresponds to the given line number in the generated compilation unit.
+ */
+ public int getEvaluationType(int lineNumber) {
+ int currentLine = 1;
+
+ // check package declaration
+ if (this.packageName != null && this.packageName.length != 0) {
+ if (lineNumber == 1) {
+ return EvaluationResult.T_PACKAGE;
+ }
+ currentLine++;
+ }
+
+ // check imports
+ char[][] imports = this.imports;
+ if ((currentLine <= lineNumber)
+ && (lineNumber < (currentLine + imports.length))) {
+ return EvaluationResult.T_IMPORT;
+ }
+ currentLine += imports.length + 1; // + 1 to skip the class declaration line
+
+ // check generated fields
+ currentLine += (this.declaringTypeName == null ? 0 : 1)
+ + (this.localVarNames == null ? 0 : this.localVarNames.length);
+ if (currentLine > lineNumber) {
+ return EvaluationResult.T_INTERNAL;
+ }
+ currentLine++; // + 1 to skip the method declaration line
+
+ // check code snippet
+ if (currentLine >= this.lineNumberOffset) {
+ return EvaluationResult.T_CODE_SNIPPET;
+ }
+
+ // default
+ return EvaluationResult.T_INTERNAL;
+ }
+
+ /**
+ * Returns the import defined at the given line number.
+ */
+ public char[] getImport(int lineNumber) {
+ int importStartLine = this.lineNumberOffset - 2 - this.imports.length;
+ return this.imports[lineNumber - importStartLine];
+ }
+
+ /**
+ * Returns a selection requestor that wraps the given requestor and shift the problems
+ * according to the start offset and line number offset of the code snippet in the generated compilation unit.
+ */
+ public ISelectionRequestor getSelectionRequestor(final ISelectionRequestor originalRequestor) {
+ final int startPosOffset = this.startPosOffset;
+ final int lineNumberOffset = this.lineNumberOffset;
+ return new ISelectionRequestor() {
+ public void acceptClass(
+ char[] packageName,
+ char[] className,
+ boolean needQualification) {
+ originalRequestor.acceptClass(packageName, className, needQualification);
+ }
+ public void acceptError(IProblem error) {
+ error.setSourceLineNumber(error.getSourceLineNumber() - lineNumberOffset);
+ error.setSourceStart(error.getSourceStart() - startPosOffset);
+ error.setSourceEnd(error.getSourceEnd() - startPosOffset);
+ originalRequestor.acceptError(error);
+ }
+ public void acceptField(
+ char[] declaringTypePackageName,
+ char[] declaringTypeName,
+ char[] name) {
+ originalRequestor.acceptField(
+ declaringTypePackageName,
+ declaringTypeName,
+ name);
+ }
+ public void acceptInterface(
+ char[] packageName,
+ char[] interfaceName,
+ boolean needQualification) {
+ originalRequestor.acceptInterface(
+ packageName,
+ interfaceName,
+ needQualification);
+ }
+ public void acceptMethod(
+ char[] declaringTypePackageName,
+ char[] declaringTypeName,
+ char[] selector,
+ char[][] parameterPackageNames,
+ char[][] parameterTypeNames) {
+ originalRequestor.acceptMethod(
+ declaringTypePackageName,
+ declaringTypeName,
+ selector,
+ parameterPackageNames,
+ parameterTypeNames);
+ }
+ public void acceptPackage(char[] packageName) {
+ originalRequestor.acceptPackage(packageName);
+ }
+ };
+ }
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetTypeDeclaration.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetTypeDeclaration.java
new file mode 100644
index 0000000000..22a88f2722
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetTypeDeclaration.java
@@ -0,0 +1,77 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.ClassFile;
+import org.eclipse.jdt.internal.compiler.problem.AbortType;
+
+public class CodeSnippetTypeDeclaration extends TypeDeclaration {
+ /**
+ * Generic bytecode generation for type
+ */
+ public void generateCode(ClassFile enclosingClassFile) {
+ if (ignoreFurtherInvestigation) {
+ if (binding == null)
+ return;
+ CodeSnippetClassFile.createProblemType(
+ this,
+ scope.referenceCompilationUnit().compilationResult);
+ return;
+ }
+ try {
+ // create the result for a compiled type
+ ClassFile classFile =
+ new CodeSnippetClassFile(binding, enclosingClassFile, false);
+ // generate all fiels
+ classFile.addFieldInfos();
+
+ // record the inner type inside its own .class file to be able
+ // to generate inner classes attributes
+ if (binding.isMemberType())
+ classFile.recordEnclosingTypeAttributes(binding);
+ if (binding.isLocalType()) {
+ enclosingClassFile.recordNestedLocalAttribute(binding);
+ classFile.recordNestedLocalAttribute(binding);
+ }
+ if (memberTypes != null) {
+ for (int i = 0, max = memberTypes.length; i < max; i++) {
+ // record the inner type inside its own .class file to be able
+ // to generate inner classes attributes
+ classFile.recordNestedMemberAttribute(memberTypes[i].binding);
+ memberTypes[i].generateCode(scope, classFile);
+ }
+ }
+ // generate all methods
+ classFile.setForMethodInfos();
+ if (methods != null) {
+ for (int i = 0, max = methods.length; i < max; i++) {
+ methods[i].generateCode(scope, classFile);
+ }
+ }
+
+ // generate all methods
+ classFile.addSpecialMethods();
+
+ if (ignoreFurtherInvestigation) { // trigger problem type generation for code gen errors
+ throw new AbortType(scope.referenceCompilationUnit().compilationResult);
+ }
+
+ // finalize the compiled type result
+ classFile.addAttributes();
+ scope.referenceCompilationUnit().compilationResult.record(
+ binding.constantPoolName(),
+ classFile);
+ } catch (AbortType e) {
+ if (binding == null)
+ return;
+ CodeSnippetClassFile.createProblemType(
+ this,
+ scope.referenceCompilationUnit().compilationResult);
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/EvaluationConstants.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/EvaluationConstants.java
new file mode 100644
index 0000000000..fe91dc0b05
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/EvaluationConstants.java
@@ -0,0 +1,34 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+
+public interface EvaluationConstants {
+ public static final char[] CODE_SNIPPET_CLASS_NAME_PREFIX =
+ "CodeSnippet_".toCharArray();
+ public static final char[] GLOBAL_VARS_CLASS_NAME_PREFIX =
+ "GlobalVariables_".toCharArray();
+ public static final char[] PACKAGE_NAME =
+ "org.eclipse.jdt.internal.eval.target".toCharArray();
+ public static final char[] CODE_SNIPPET_NAME =
+ "org/eclipse/jdt/internal/eval/target/CodeSnippet".toCharArray();
+ public static final char[] ROOT_CLASS_NAME = "CodeSnippet".toCharArray();
+ public static final String ROOT_FULL_CLASS_NAME =
+ new String(PACKAGE_NAME) + "." + new String(ROOT_CLASS_NAME);
+ public static final char[] SETRESULT_SELECTOR = "setResult".toCharArray();
+ public static final char[] SETRESULT_ARGUMENTS =
+ "Ljava.lang.Object;Ljava.lang.Class;".toCharArray();
+ public static final char[][] ROOT_COMPOUND_NAME =
+ CharOperation.arrayConcat(
+ CharOperation.splitOn('.', PACKAGE_NAME),
+ ROOT_CLASS_NAME);
+ public static final String RUN_METHOD = "run";
+ public static final String RESULT_VALUE_FIELD = "resultValue";
+ public static final String RESULT_TYPE_FIELD = "resultType";
+ public final static char[] LOCAL_VAR_PREFIX = "val$".toCharArray();
+ public final static char[] DELEGATE_THIS = "val$this".toCharArray();
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/EvaluationContext.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/EvaluationContext.java
new file mode 100644
index 0000000000..2c133205cd
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/EvaluationContext.java
@@ -0,0 +1,1396 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.codeassist.*;
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.classfmt.*;
+import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
+import org.eclipse.jdt.internal.compiler.problem.ProblemIrritants;
+import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+import java.io.*;
+import java.util.*;
+import java.util.zip.*;
+
+/**
+ * @see org.eclipse.jdt.core.eval.IEvaluationContext
+ */
+public class EvaluationContext implements EvaluationConstants {
+ /**
+ * Whether timing information should be output to the stdout
+ */
+ static final boolean TIMING = false;
+
+ /**
+ * Global counters so that several evaluation context can deploy on the same runtime.
+ */
+ static int VAR_CLASS_COUNTER = 0;
+ static int CODE_SNIPPET_COUNTER = 0;
+
+ GlobalVariable[] variables = new GlobalVariable[5];
+ int variableCount = 0;
+ char[][] imports = new char[0][];
+ char[] packageName = new char[0];
+ boolean varsChanged = true;
+ VariablesInfo installedVars;
+ IBinaryType codeSnippetBinary;
+
+ /* do names implicitly refer to a given type */
+ char[] declaringTypeName;
+ int[] localVariableModifiers;
+ char[][] localVariableTypeNames;
+ char[][] localVariableNames;
+
+ /* can 'this' be used in this context */
+ boolean isStatic = true;
+ boolean isConstructorCall = false;
+ /**
+ * Creates a new evaluation context.
+ */
+ public EvaluationContext() {
+ }
+
+ /**
+ * Returns the global variables of this evaluation context in the order they were created in.
+ */
+ public GlobalVariable[] allVariables() {
+ GlobalVariable[] result = new GlobalVariable[this.variableCount];
+ System.arraycopy(this.variables, 0, result, 0, this.variableCount);
+ return result;
+ }
+
+ /**
+ * Computes a completion at the specified position of the given code snippet.
+ * (Note that this evaluation context's VM doesn't need to be running.)
+ *
+ * @param environment com.ibm.codeassist.java.api.ISearchableNameEnvironment
+ * used to resolve type/package references and search for types/packages
+ * based on partial names.
+ *
+ * @param requestor com.ibm.codeassist.java.api.ICompletionRequestor
+ * since the engine might produce answers of various forms, the engine
+ * is associated with a requestor able to accept all possible completions.
+ *
+ * @param options com.ibm.compiler.java.api.ConfigurableOptions
+ * set of options used to configure the code assist engine.
+ */
+ public void complete(
+ char[] codeSnippet,
+ int completionPosition,
+ ISearchableNameEnvironment environment,
+ ICompletionRequestor requestor,
+ ConfigurableOption[] options) {
+ final char[] className = "CodeSnippetCompletion".toCharArray();
+ final CodeSnippetToCuMapper mapper =
+ new CodeSnippetToCuMapper(
+ codeSnippet,
+ this.packageName,
+ this.imports,
+ className,
+ this.installedVars == null ? null : this.installedVars.className,
+ this.localVariableNames,
+ this.localVariableTypeNames,
+ this.localVariableModifiers,
+ this.declaringTypeName);
+ ICompilationUnit sourceUnit = new ICompilationUnit() {
+ public char[] getFileName() {
+ return CharOperation.concat(className, "java".toCharArray(), '.');
+ }
+ public char[] getContents() {
+ return mapper.getCUSource();
+ }
+ public char[] getMainTypeName() {
+ return className;
+ }
+ };
+ CompletionEngine engine =
+ new CompletionEngine(
+ environment,
+ mapper.getCompletionRequestor(requestor),
+ options);
+ engine.complete(sourceUnit, mapper.startPosOffset + completionPosition);
+ }
+
+ /**
+ * Deletes the given variable from this evaluation context. This will take effect in the target VM only
+ * the next time global variables are installed.
+ */
+ public void deleteVariable(GlobalVariable variable) {
+ GlobalVariable[] vars = this.variables;
+ int index = -1;
+ for (int i = 0; i < this.variableCount; i++) {
+ if (vars[i].equals(variable)) {
+ index = i;
+ break;
+ }
+ }
+ if (index == -1) {
+ return;
+ }
+ int elementCount = this.variableCount--;
+ int j = elementCount - index - 1;
+ if (j > 0) {
+ System.arraycopy(vars, index + 1, vars, index, j);
+ }
+ vars[elementCount - 1] = null;
+ this.varsChanged = true;
+ }
+
+ private void deployCodeSnippetClassIfNeeded(IRequestor requestor) {
+ if (this.codeSnippetBinary == null) {
+ // Deploy CodeSnippet class (only once)
+ requestor
+ .acceptClassFiles(
+ new ClassFile[] {
+ new ClassFile() { public byte[] getBytes() { return getCodeSnippetBytes();
+ }
+ public char[][] getCompoundName() {
+ return EvaluationConstants.ROOT_COMPOUND_NAME;
+ }
+ }
+ }, null);
+ }
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.eval.IEvaluationContext
+ * @exception org.eclipse.jdt.internal.eval.InstallException if the code snippet class files could not be deployed.
+ */
+ public void evaluate(
+ char[] codeSnippet,
+ char[][] localVariableTypeNames,
+ char[][] localVariableNames,
+ int[] localVariableModifiers,
+ char[] declaringTypeName,
+ boolean isStatic,
+ boolean isConstructorCall,
+ INameEnvironment environment,
+ ConfigurableOption[] options,
+ final IRequestor requestor,
+ IProblemFactory problemFactory)
+ throws InstallException {
+
+ // Initialialize context
+ this.localVariableTypeNames = localVariableTypeNames;
+ this.localVariableNames = localVariableNames;
+ this.localVariableModifiers = localVariableModifiers;
+ this.declaringTypeName = declaringTypeName;
+ this.isStatic = isStatic;
+ this.isConstructorCall = isConstructorCall;
+
+ this.deployCodeSnippetClassIfNeeded(requestor);
+
+ try {
+ // Install new variables if needed
+ class ForwardingRequestor implements IRequestor {
+ boolean hasErrors = false;
+ public boolean acceptClassFiles(
+ ClassFile[] classFiles,
+ char[] codeSnippetClassName) {
+ return requestor.acceptClassFiles(classFiles, codeSnippetClassName);
+ }
+ public void acceptProblem(
+ IProblem problem,
+ char[] fragmentSource,
+ int fragmentKind) {
+ requestor.acceptProblem(problem, fragmentSource, fragmentKind);
+ if (problem.isError()) {
+ hasErrors = true;
+ }
+ }
+ };
+ ForwardingRequestor forwardingRequestor = new ForwardingRequestor();
+ if (this.varsChanged) {
+ evaluateVariables(environment, options, forwardingRequestor, problemFactory);
+ }
+
+ // Compile code snippet if there was no errors while evaluating the variables
+ if (!forwardingRequestor.hasErrors) {
+ Evaluator evaluator =
+ new CodeSnippetEvaluator(
+ codeSnippet,
+ this,
+ environment,
+ options,
+ requestor,
+ problemFactory);
+ ClassFile[] classes = null;
+ if (TIMING) {
+ long start = System.currentTimeMillis();
+ classes = evaluator.getClasses();
+ System.out.println(
+ "Time to compile ["
+ + new String(codeSnippet)
+ + "] was "
+ + (System.currentTimeMillis() - start)
+ + "ms");
+ } else {
+ classes = evaluator.getClasses();
+ }
+ // Send code snippet on target
+ if (classes != null && classes.length > 0) {
+ char[] simpleClassName = evaluator.getClassName();
+ char[] packageName = this.getPackageName();
+ char[] qualifiedClassName =
+ packageName.length == 0
+ ? simpleClassName
+ : CharOperation.concat(packageName, simpleClassName, '.');
+ CODE_SNIPPET_COUNTER++;
+ requestor.acceptClassFiles(classes, qualifiedClassName);
+ }
+ }
+ } finally {
+ // Reinitialize context to default values
+ this.localVariableTypeNames = null;
+ this.localVariableNames = null;
+ this.localVariableModifiers = null;
+ this.declaringTypeName = null;
+ this.isStatic = true;
+ this.isConstructorCall = false;
+ }
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.eval.IEvaluationContext
+ * @exception org.eclipse.jdt.internal.eval.InstallException if the code snippet class files could not be deployed.
+ */
+ public void evaluate(
+ char[] codeSnippet,
+ INameEnvironment environment,
+ ConfigurableOption[] options,
+ final IRequestor requestor,
+ IProblemFactory problemFactory)
+ throws InstallException {
+ this.evaluate(
+ codeSnippet,
+ null,
+ null,
+ null,
+ null,
+ true,
+ false,
+ environment,
+ options,
+ requestor,
+ problemFactory);
+ }
+
+ /**
+ * @see org.eclipse.jdt.core.eval.IEvaluationContext
+ */
+ public void evaluateImports(
+ INameEnvironment environment,
+ IRequestor requestor,
+ IProblemFactory problemFactory) {
+ for (int i = 0; i < this.imports.length; i++) {
+ IProblem[] problems = new IProblem[] { null };
+ char[] importDeclaration = this.imports[i];
+ char[][] splitDeclaration = CharOperation.splitOn('.', importDeclaration);
+ int splitLength = splitDeclaration.length;
+ if (splitLength > 0) {
+ char[] packageName = splitDeclaration[splitLength - 1];
+ if (packageName.length == 1 && packageName[0] == '*') {
+ char[][] parentName;
+ switch (splitLength) {
+ case 1 :
+ parentName = null;
+ break;
+ case 2 :
+ parentName = null;
+ packageName = splitDeclaration[splitLength - 2];
+ break;
+ default :
+ parentName = CharOperation.subarray(splitDeclaration, 0, splitLength - 2);
+ packageName = splitDeclaration[splitLength - 2];
+ }
+ if (!environment.isPackage(parentName, packageName)) {
+ problems[0] =
+ problemFactory.createProblem(
+ importDeclaration,
+ ProblemIrritants.ImportProblemBase + ProblemReasons.NotFound,
+ new String[] { new String(importDeclaration)},
+ ProblemSeverities.Warning,
+ 0,
+ importDeclaration.length - 1,
+ i);
+ }
+ } else {
+ if (environment.findType(splitDeclaration) == null) {
+ problems[0] =
+ problemFactory.createProblem(
+ importDeclaration,
+ ProblemIrritants.ImportProblemBase + ProblemReasons.NotFound,
+ new String[] { new String(importDeclaration)},
+ ProblemSeverities.Warning,
+ 0,
+ importDeclaration.length - 1,
+ i);
+ }
+ }
+ } else {
+ problems[0] =
+ problemFactory.createProblem(
+ importDeclaration,
+ ProblemIrritants.ImportProblemBase + ProblemReasons.NotFound,
+ new String[] { new String(importDeclaration)},
+ ProblemSeverities.Warning,
+ 0,
+ importDeclaration.length - 1,
+ i);
+ }
+ if (problems[0] != null) {
+ requestor.acceptProblem(
+ problems[0],
+ importDeclaration,
+ EvaluationResult.T_IMPORT);
+ }
+ }
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.eval.IEvaluationContext
+ * @exception org.eclipse.jdt.internal.eval.InstallException if the code snippet class files could not be deployed.
+ * @exception java.lang.IllegalArgumentException if the global has not been installed yet.
+ */
+ public void evaluateVariable(
+ GlobalVariable variable,
+ INameEnvironment environment,
+ ConfigurableOption[] options,
+ IRequestor requestor,
+ IProblemFactory problemFactory)
+ throws InstallException {
+ this.evaluate(
+ variable.getName(),
+ environment,
+ options,
+ requestor,
+ problemFactory);
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.eval.IEvaluationContext
+ * @exception org.eclipse.jdt.internal.eval.InstallException if the code snippet class files could not be deployed.
+ */
+ public void evaluateVariables(
+ INameEnvironment environment,
+ ConfigurableOption[] options,
+ IRequestor requestor,
+ IProblemFactory problemFactory)
+ throws InstallException {
+ this.deployCodeSnippetClassIfNeeded(requestor);
+ VariablesEvaluator evaluator =
+ new VariablesEvaluator(this, environment, options, requestor, problemFactory);
+ ClassFile[] classes = evaluator.getClasses();
+ if (classes != null) {
+ if (classes.length > 0) {
+ // Send classes
+ if (!requestor.acceptClassFiles(classes, null)) {
+ throw new InstallException("Could not deploy classes for global variables");
+ }
+
+ // Remember that the variables have been installed
+ int variableCount = this.variableCount;
+ GlobalVariable[] variablesCopy = new GlobalVariable[variableCount];
+ System.arraycopy(this.variables, 0, variablesCopy, 0, variableCount);
+ this.installedVars =
+ new VariablesInfo(
+ evaluator.getPackageName(),
+ evaluator.getClassName(),
+ classes,
+ variablesCopy,
+ variableCount);
+ VAR_CLASS_COUNTER++;
+ }
+ this.varsChanged = false;
+ }
+ }
+
+ /**
+ * Returns the bytes of the CodeSnippet class.
+ * Generated using the following code snippet:
+ [java.io.BufferedWriter writer = new java.io.BufferedWriter(new java.io.FileWriter("d:/temp/CodeSnippet.java"));
+ writer.write(org.eclipse.jdt.internal.eval.EvaluationContext.getCodeSnippetSource());
+ writer.close();
+ org.eclipse.jdt.internal.compiler.batch.Main.compile(
+ "d:/temp/CodeSnippet.java -d d:/temp -classpath d:/jdk1.2.2/jre/lib/rt.jar -verbose");
+ java.io.FileInputStream reader = new java.io.FileInputStream("d:/temp/org/eclipse/jdt/internal/eval/target/CodeSnippet.class");
+ byte[] bytes = org.eclipse.jdt.internal.core.Util.readContentsAsBytes(reader);
+ reader.close();
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("private byte[] getCodeSnippetBytes() {\n");
+ buffer.append(" return new byte[] {\n");
+ buffer.append(" ");
+ for (int i = 0; i < bytes.length; i++) {
+ buffer.append(bytes[i]);
+ if (i == bytes.length - 1) {
+ buffer.append("\n");
+ } else {
+ buffer.append(", ");
+ }
+ }
+
+ buffer.append(" };\n");
+ buffer.append("}");
+ buffer.toString()
+ ]
+ */
+ private byte[] getCodeSnippetBytes() {
+ return new byte[] {
+ -54,
+ -2,
+ -70,
+ -66,
+ 0,
+ 3,
+ 0,
+ 45,
+ 0,
+ 35,
+ 1,
+ 0,
+ 48,
+ 111,
+ 114,
+ 103,
+ 47,
+ 101,
+ 99,
+ 108,
+ 105,
+ 112,
+ 115,
+ 101,
+ 47,
+ 106,
+ 100,
+ 116,
+ 47,
+ 105,
+ 110,
+ 116,
+ 101,
+ 114,
+ 110,
+ 97,
+ 108,
+ 47,
+ 101,
+ 118,
+ 97,
+ 108,
+ 47,
+ 116,
+ 97,
+ 114,
+ 103,
+ 101,
+ 116,
+ 47,
+ 67,
+ 111,
+ 100,
+ 101,
+ 83,
+ 110,
+ 105,
+ 112,
+ 112,
+ 101,
+ 116,
+ 7,
+ 0,
+ 1,
+ 1,
+ 0,
+ 16,
+ 106,
+ 97,
+ 118,
+ 97,
+ 47,
+ 108,
+ 97,
+ 110,
+ 103,
+ 47,
+ 79,
+ 98,
+ 106,
+ 101,
+ 99,
+ 116,
+ 7,
+ 0,
+ 3,
+ 1,
+ 0,
+ 10,
+ 114,
+ 101,
+ 115,
+ 117,
+ 108,
+ 116,
+ 84,
+ 121,
+ 112,
+ 101,
+ 1,
+ 0,
+ 17,
+ 76,
+ 106,
+ 97,
+ 118,
+ 97,
+ 47,
+ 108,
+ 97,
+ 110,
+ 103,
+ 47,
+ 67,
+ 108,
+ 97,
+ 115,
+ 115,
+ 59,
+ 1,
+ 0,
+ 11,
+ 114,
+ 101,
+ 115,
+ 117,
+ 108,
+ 116,
+ 86,
+ 97,
+ 108,
+ 117,
+ 101,
+ 1,
+ 0,
+ 18,
+ 76,
+ 106,
+ 97,
+ 118,
+ 97,
+ 47,
+ 108,
+ 97,
+ 110,
+ 103,
+ 47,
+ 79,
+ 98,
+ 106,
+ 101,
+ 99,
+ 116,
+ 59,
+ 1,
+ 0,
+ 7,
+ 99,
+ 108,
+ 97,
+ 115,
+ 115,
+ 36,
+ 48,
+ 1,
+ 0,
+ 9,
+ 83,
+ 121,
+ 110,
+ 116,
+ 104,
+ 101,
+ 116,
+ 105,
+ 99,
+ 1,
+ 0,
+ 6,
+ 60,
+ 105,
+ 110,
+ 105,
+ 116,
+ 62,
+ 1,
+ 0,
+ 3,
+ 40,
+ 41,
+ 86,
+ 1,
+ 0,
+ 4,
+ 67,
+ 111,
+ 100,
+ 101,
+ 12,
+ 0,
+ 11,
+ 0,
+ 12,
+ 10,
+ 0,
+ 4,
+ 0,
+ 14,
+ 1,
+ 0,
+ 14,
+ 106,
+ 97,
+ 118,
+ 97,
+ 47,
+ 108,
+ 97,
+ 110,
+ 103,
+ 47,
+ 86,
+ 111,
+ 105,
+ 100,
+ 7,
+ 0,
+ 16,
+ 1,
+ 0,
+ 4,
+ 84,
+ 89,
+ 80,
+ 69,
+ 12,
+ 0,
+ 18,
+ 0,
+ 6,
+ 9,
+ 0,
+ 17,
+ 0,
+ 19,
+ 12,
+ 0,
+ 5,
+ 0,
+ 6,
+ 9,
+ 0,
+ 2,
+ 0,
+ 21,
+ 12,
+ 0,
+ 7,
+ 0,
+ 8,
+ 9,
+ 0,
+ 2,
+ 0,
+ 23,
+ 1,
+ 0,
+ 15,
+ 76,
+ 105,
+ 110,
+ 101,
+ 78,
+ 117,
+ 109,
+ 98,
+ 101,
+ 114,
+ 84,
+ 97,
+ 98,
+ 108,
+ 101,
+ 1,
+ 0,
+ 13,
+ 103,
+ 101,
+ 116,
+ 82,
+ 101,
+ 115,
+ 117,
+ 108,
+ 116,
+ 84,
+ 121,
+ 112,
+ 101,
+ 1,
+ 0,
+ 19,
+ 40,
+ 41,
+ 76,
+ 106,
+ 97,
+ 118,
+ 97,
+ 47,
+ 108,
+ 97,
+ 110,
+ 103,
+ 47,
+ 67,
+ 108,
+ 97,
+ 115,
+ 115,
+ 59,
+ 1,
+ 0,
+ 14,
+ 103,
+ 101,
+ 116,
+ 82,
+ 101,
+ 115,
+ 117,
+ 108,
+ 116,
+ 86,
+ 97,
+ 108,
+ 117,
+ 101,
+ 1,
+ 0,
+ 20,
+ 40,
+ 41,
+ 76,
+ 106,
+ 97,
+ 118,
+ 97,
+ 47,
+ 108,
+ 97,
+ 110,
+ 103,
+ 47,
+ 79,
+ 98,
+ 106,
+ 101,
+ 99,
+ 116,
+ 59,
+ 1,
+ 0,
+ 3,
+ 114,
+ 117,
+ 110,
+ 1,
+ 0,
+ 9,
+ 115,
+ 101,
+ 116,
+ 82,
+ 101,
+ 115,
+ 117,
+ 108,
+ 116,
+ 1,
+ 0,
+ 38,
+ 40,
+ 76,
+ 106,
+ 97,
+ 118,
+ 97,
+ 47,
+ 108,
+ 97,
+ 110,
+ 103,
+ 47,
+ 79,
+ 98,
+ 106,
+ 101,
+ 99,
+ 116,
+ 59,
+ 76,
+ 106,
+ 97,
+ 118,
+ 97,
+ 47,
+ 108,
+ 97,
+ 110,
+ 103,
+ 47,
+ 67,
+ 108,
+ 97,
+ 115,
+ 115,
+ 59,
+ 41,
+ 86,
+ 1,
+ 0,
+ 10,
+ 83,
+ 111,
+ 117,
+ 114,
+ 99,
+ 101,
+ 70,
+ 105,
+ 108,
+ 101,
+ 1,
+ 0,
+ 16,
+ 67,
+ 111,
+ 100,
+ 101,
+ 83,
+ 110,
+ 105,
+ 112,
+ 112,
+ 101,
+ 116,
+ 46,
+ 106,
+ 97,
+ 118,
+ 97,
+ 0,
+ 33,
+ 0,
+ 2,
+ 0,
+ 4,
+ 0,
+ 0,
+ 0,
+ 3,
+ 0,
+ 2,
+ 0,
+ 5,
+ 0,
+ 6,
+ 0,
+ 0,
+ 0,
+ 2,
+ 0,
+ 7,
+ 0,
+ 8,
+ 0,
+ 0,
+ 0,
+ 8,
+ 0,
+ 9,
+ 0,
+ 6,
+ 0,
+ 1,
+ 0,
+ 10,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5,
+ 0,
+ 1,
+ 0,
+ 11,
+ 0,
+ 12,
+ 0,
+ 1,
+ 0,
+ 13,
+ 0,
+ 0,
+ 0,
+ 53,
+ 0,
+ 2,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0,
+ 17,
+ 42,
+ -73,
+ 0,
+ 15,
+ 42,
+ -78,
+ 0,
+ 20,
+ -75,
+ 0,
+ 22,
+ 42,
+ 1,
+ -75,
+ 0,
+ 24,
+ -79,
+ 0,
+ 0,
+ 0,
+ 1,
+ 0,
+ 25,
+ 0,
+ 0,
+ 0,
+ 18,
+ 0,
+ 4,
+ 0,
+ 0,
+ 0,
+ 17,
+ 0,
+ 4,
+ 0,
+ 18,
+ 0,
+ 11,
+ 0,
+ 19,
+ 0,
+ 16,
+ 0,
+ 17,
+ 0,
+ 1,
+ 0,
+ 26,
+ 0,
+ 27,
+ 0,
+ 1,
+ 0,
+ 13,
+ 0,
+ 0,
+ 0,
+ 29,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0,
+ 5,
+ 42,
+ -76,
+ 0,
+ 22,
+ -80,
+ 0,
+ 0,
+ 0,
+ 1,
+ 0,
+ 25,
+ 0,
+ 0,
+ 0,
+ 6,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0,
+ 24,
+ 0,
+ 1,
+ 0,
+ 28,
+ 0,
+ 29,
+ 0,
+ 1,
+ 0,
+ 13,
+ 0,
+ 0,
+ 0,
+ 29,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0,
+ 5,
+ 42,
+ -76,
+ 0,
+ 24,
+ -80,
+ 0,
+ 0,
+ 0,
+ 1,
+ 0,
+ 25,
+ 0,
+ 0,
+ 0,
+ 6,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0,
+ 30,
+ 0,
+ 1,
+ 0,
+ 30,
+ 0,
+ 12,
+ 0,
+ 1,
+ 0,
+ 13,
+ 0,
+ 0,
+ 0,
+ 25,
+ 0,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0,
+ 1,
+ -79,
+ 0,
+ 0,
+ 0,
+ 1,
+ 0,
+ 25,
+ 0,
+ 0,
+ 0,
+ 6,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0,
+ 36,
+ 0,
+ 1,
+ 0,
+ 31,
+ 0,
+ 32,
+ 0,
+ 1,
+ 0,
+ 13,
+ 0,
+ 0,
+ 0,
+ 43,
+ 0,
+ 2,
+ 0,
+ 3,
+ 0,
+ 0,
+ 0,
+ 11,
+ 42,
+ 43,
+ -75,
+ 0,
+ 24,
+ 42,
+ 44,
+ -75,
+ 0,
+ 22,
+ -79,
+ 0,
+ 0,
+ 0,
+ 1,
+ 0,
+ 25,
+ 0,
+ 0,
+ 0,
+ 14,
+ 0,
+ 3,
+ 0,
+ 0,
+ 0,
+ 42,
+ 0,
+ 5,
+ 0,
+ 43,
+ 0,
+ 10,
+ 0,
+ 41,
+ 0,
+ 1,
+ 0,
+ 33,
+ 0,
+ 0,
+ 0,
+ 2,
+ 0,
+ 34 };
+ }
+
+ /**
+ * Returns the source of the CodeSnippet class.
+ * This is used to generate the binary of the CodeSnippetClass
+ * @see getCodeSnippetBytes
+ */
+ public static String getCodeSnippetSource() {
+ return "package org.eclipse.jdt.internal.eval.target;\n"
+ + "\n"
+ + "/*\n"
+ + " * (c) Copyright IBM Corp. 2000, 2001.\n"
+ + " * All Rights Reserved.\n"
+ + " */\n"
+ + "/**\n"
+ + " * The root of all code snippet classes. Code snippet classes\n"
+ + " * are supposed to overide the run() method.\n"
+ + " * <p>\n"
+ + " * IMPORTANT NOTE:\n"
+ + " * All methods in this class must be public since this class is going to be loaded by the\n"
+ + " * bootstrap class loader, and the other code snippet support classes might be loaded by \n"
+ + " * another class loader (so their runtime packages are going to be different).\n"
+ + " */\n"
+ + "public class CodeSnippet {\n"
+ + " private Class resultType = void.class;\n"
+ + " private Object resultValue = null;\n"
+ + "/**\n"
+ + " * Returns the result type of the code snippet evaluation.\n"
+ + " */\n"
+ + "public Class getResultType() {\n"
+ + " return this.resultType;\n"
+ + "}\n"
+ + "/**\n"
+ + " * Returns the result value of the code snippet evaluation.\n"
+ + " */\n"
+ + "public Object getResultValue() {\n"
+ + " return this.resultValue;\n"
+ + "}\n"
+ + "/**\n"
+ + " * The code snippet. Subclasses must override this method with a transformed code snippet\n"
+ + " * that stores the result using setResult(Class, Object).\n"
+ + " */\n"
+ + "public void run() {\n"
+ + "}\n"
+ + "/**\n"
+ + " * Stores the result type and value of the code snippet evaluation.\n"
+ + " */\n"
+ + "public void setResult(Object resultValue, Class resultType) {\n"
+ + " this.resultValue = resultValue;\n"
+ + " this.resultType = resultType;\n"
+ + "}\n"
+ + "}\n";
+ }
+
+ /**
+ * Returns the imports of this evaluation context. An import is the name of a package
+ * or the fully qualified name of a type as defined in the import statement of
+ * a compilation unit.
+ */
+ public char[][] getImports() {
+ return this.imports;
+ }
+
+ /**
+ * Returns the dot-separated name of the package code snippets are run into.
+ * Returns an empty array for the default package. This is the default if
+ * the package name has never been set.
+ */
+ public char[] getPackageName() {
+ return this.packageName;
+ }
+
+ /**
+ * Return the binary for the root code snippet class (ie. org.eclipse.jdt.internal.eval.target.CodeSnippet).
+ */
+ IBinaryType getRootCodeSnippetBinary() {
+ if (codeSnippetBinary == null) {
+ this.codeSnippetBinary = new CodeSnippetSkeleton();
+ }
+ return this.codeSnippetBinary;
+ }
+
+ /**
+ * Returns the name of the file (including the package name) of the given class file.
+ * The simple name doesn't contain the extension ".class".
+ * The returned name doesn't start with a "/"
+ */
+ private String getSupportClassFileName(String simpleName) {
+ char separator = File.separatorChar;
+ char[][] compoundPackageName = CharOperation.splitOn('.', PACKAGE_NAME);
+ return new String(CharOperation.concatWith(compoundPackageName, separator))
+ + separator
+ + simpleName
+ + ".class";
+ }
+
+ /**
+ * Creates a new global variable with the given name, type and initializer.
+ * If the variable is not initialized, the initializer can be null.
+ * Note that this doesn't install it to this evaluation context's VM.
+ *
+ * @see GlobalVariable
+ */
+ public GlobalVariable newVariable(
+ char[] typeName,
+ char[] name,
+ char[] initializer) {
+ GlobalVariable var = new GlobalVariable(typeName, name, initializer);
+ try {
+ this.variables[this.variableCount++] = var;
+ } catch (ArrayIndexOutOfBoundsException e) {
+ int index = this.variableCount - 1;
+ GlobalVariable[] oldVars = this.variables;
+ GlobalVariable[] newVars = new GlobalVariable[index * 2];
+ System.arraycopy(oldVars, 0, newVars, 0, index);
+ newVars[index] = var;
+ this.variables = newVars;
+ }
+ this.varsChanged = true;
+ return var;
+ }
+
+ /**
+ * Computes the selection at the specified positions of the given code snippet.
+ * (Note that this evaluation context's VM doesn't need to be running.)
+ *
+ * @param environment com.ibm.codeassist.java.api.ISearchableNameEnvironment
+ * used to resolve type/package references and search for types/packages
+ * based on partial names.
+ *
+ * @param requestor com.ibm.codeassist.java.api.ISelectionRequestor
+ * since the engine might produce answers of various forms, the engine
+ * is associated with a requestor able to accept all possible selections.
+ *
+ * @param options com.ibm.compiler.java.api.ConfigurableOptions
+ * set of options used to configure the code assist engine.
+ */
+ public void select(
+ char[] codeSnippet,
+ int selectionSourceStart,
+ int selectionSourceEnd,
+ ISearchableNameEnvironment environment,
+ ISelectionRequestor requestor,
+ ConfigurableOption[] options) {
+
+ final char[] className = "CodeSnippetSelection".toCharArray();
+ final CodeSnippetToCuMapper mapper =
+ new CodeSnippetToCuMapper(
+ codeSnippet,
+ this.packageName,
+ this.imports,
+ className,
+ this.installedVars == null ? null : this.installedVars.className,
+ this.localVariableNames,
+ this.localVariableTypeNames,
+ this.localVariableModifiers,
+ this.declaringTypeName);
+ ICompilationUnit sourceUnit = new ICompilationUnit() {
+ public char[] getFileName() {
+ return CharOperation.concat(className, "java".toCharArray(), '.');
+ }
+ public char[] getContents() {
+ return mapper.getCUSource();
+ }
+ public char[] getMainTypeName() {
+ return className;
+ }
+ };
+ SelectionEngine engine =
+ new SelectionEngine(
+ environment,
+ mapper.getSelectionRequestor(requestor),
+ options);
+ engine.select(
+ sourceUnit,
+ mapper.startPosOffset + selectionSourceStart,
+ mapper.startPosOffset + selectionSourceEnd);
+ }
+
+ /**
+ * Sets the imports of this evaluation context. An import is the name of a package
+ * or the fully qualified name of a type as defined in the import statement of
+ * a compilation unit (see the Java Language Specifications for more details).
+ */
+ public void setImports(char[][] imports) {
+ this.imports = imports;
+ this.varsChanged = true;
+ // this may change the visibility of the variable's types
+ }
+
+ /**
+ * Sets the dot-separated name of the package code snippets are ran into.
+ * The default package name is an empty array.
+ */
+ public void setPackageName(char[] packageName) {
+ this.packageName = packageName;
+ this.varsChanged = true;
+ // this may change the visibility of the variable's types
+ }
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/EvaluationResult.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/EvaluationResult.java
new file mode 100644
index 0000000000..c0bb8f0993
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/EvaluationResult.java
@@ -0,0 +1,246 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IProblem;
+
+/**
+ * An EvaluationResult is the result of a code snippet evaluation, a global
+ * variable evaluation or it is used to report problems against imports and
+ * package declaration.
+ * It primarily contains the representation of the resulting value (eg. its
+ * toString() representation). However if the code snippet, a global variable
+ * definition, an import or the package declaration could not be compiled, it
+ * contains the corresponding compilation problems.
+ */
+public class EvaluationResult {
+ static final IProblem[] NO_PROBLEMS = new IProblem[0];
+
+ char[] evaluationID;
+ int evaluationType;
+ IProblem[] problems;
+ char[] displayString;
+ char[] typeName;
+
+ /**
+ * The evaluation result contains the value of a variable or
+ * it reports a problem on a variable. Note that if the problem is
+ * on the type of the variable, the source line number is -1. If the
+ * problem is on the name of the variable, the source line number is 0.
+ * Otherwise the source line number is relative to the initializer code.
+ */
+ public static final int T_VARIABLE = 1;
+
+ /**
+ * The evaluation result contains the value of a code snippet or
+ * it reports a problem on a code snippet.
+ */
+ public static final int T_CODE_SNIPPET = 2;
+
+ /**
+ * The evaluation result reports a problem on an import declaration.
+ */
+ public static final int T_IMPORT = 3;
+
+ /**
+ * The evaluation result reports a problem on a package declaration.
+ */
+ public static final int T_PACKAGE = 4;
+
+ /**
+ * The evaluation result reports an internal problem.
+ */
+ public static final int T_INTERNAL = 5;
+
+ public EvaluationResult(
+ char[] evaluationID,
+ int evaluationType,
+ char[] displayString,
+ char[] typeName) {
+ this.evaluationID = evaluationID;
+ this.evaluationType = evaluationType;
+ this.displayString = displayString;
+ this.typeName = typeName;
+ this.problems = NO_PROBLEMS;
+ }
+
+ public EvaluationResult(
+ char[] evaluationID,
+ int evaluationType,
+ IProblem[] problems) {
+ this.evaluationID = evaluationID;
+ this.evaluationType = evaluationType;
+ this.problems = problems;
+ }
+
+ /**
+ * Adds the given problem to the list of problems of this evaluation result.
+ */
+ void addProblem(IProblem problem) {
+ IProblem[] existingProblems = this.problems;
+ int existingLength = existingProblems.length;
+ this.problems = new IProblem[existingLength + 1];
+ System.arraycopy(existingProblems, 0, this.problems, 0, existingLength);
+ this.problems[existingLength] = problem;
+ }
+
+ /**
+ * Returns the ID of the evaluation.
+ * If the result is about a global variable, returns the name of the variable.
+ * If the result is about a code snippet, returns the code snippet.
+ * If the result is about an import, returns the import.
+ * If the result is about a package declaration, returns the package declaration.
+ */
+ public char[] getEvaluationID() {
+ return this.evaluationID;
+ }
+
+ /**
+ * Returns the type of evaluation this result is about.
+ * This indicates if the result is about a global variable,
+ * a code snippet, an import or a package declaration.
+ * Use getEvaluationID() to get the object itself.
+ */
+ public int getEvaluationType() {
+ return this.evaluationType;
+ }
+
+ /**
+ * Returns an array of problems (errors and warnings) encountered
+ * during the compilation of a code snippet or a global variable definition,
+ * or during the analysis of a package name or an import.
+ * Returns an empty array if there are no problems.
+ */
+ public IProblem[] getProblems() {
+ return this.problems;
+ }
+
+ /**
+ * Returns a proxy object on this result's value.
+ * Returns null if the result's value is null.
+ * The returned value is undefined if there is no result.
+ * The proxy object is expected to answer questions like:
+ * - What is the proxy type for this object?
+ * - What is the toString() representation for this object?
+ * - What are the field names of this object?
+ * - What is the value for a given field name?
+ * Special proxy objects are expected if the value is a primitive type.
+ */
+ public Object getValue() {
+ return null; // Not yet implemented
+ }
+
+ /**
+ * Returns the displayable representation of this result's value.
+ * This is obtained by sending toString() to the result object on the target side
+ * if it is not a primitive value. If it is a primitive value, the corresponding
+ * static toString(...) is used, eg. Integer.toString(int n) if it is an int.
+ * Returns null if there is no value.
+ */
+ public char[] getValueDisplayString() {
+ return this.displayString;
+ }
+
+ /**
+ * Returns the dot-separated fully qualified name of this result's value type.
+ * If the value is a primitive value, returns the toString() representation of its type
+ * (eg. "int", "boolean", etc.)
+ * Returns null if there is no value.
+ */
+ public char[] getValueTypeName() {
+ return this.typeName;
+ }
+
+ /**
+ * Returns whether there are errors in the code snippet or the global variable definition.
+ */
+ public boolean hasErrors() {
+ if (this.problems == null) {
+ return false;
+ } else {
+ for (int i = 0; i < this.problems.length; i++) {
+ if (this.problems[i].isError()) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Returns whether there are problems in the code snippet or the global variable definition.
+ */
+ public boolean hasProblems() {
+ return (this.problems != null) && (this.problems.length != 0);
+ }
+
+ /**
+ * Returns whether this result has a value.
+ */
+ public boolean hasValue() {
+ return this.displayString != null;
+ }
+
+ /**
+ * Returns whether there are warnings in the code snippet or the global variable definition.
+ */
+ public boolean hasWarnings() {
+ if (this.problems == null) {
+ return false;
+ } else {
+ for (int i = 0; i < this.problems.length; i++) {
+ if (this.problems[i].isWarning()) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Returns a readable representation of this result.
+ * This is for debugging purpose only.
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ switch (this.evaluationType) {
+ case T_CODE_SNIPPET :
+ buffer.append("Code snippet");
+ break;
+ case T_IMPORT :
+ buffer.append("Import");
+ break;
+ case T_INTERNAL :
+ buffer.append("Internal problem");
+ break;
+ case T_PACKAGE :
+ buffer.append("Package");
+ break;
+ case T_VARIABLE :
+ buffer.append("Global variable");
+ break;
+ }
+ buffer.append(": ");
+ buffer.append(this.evaluationID);
+ buffer.append("\n");
+ if (hasProblems()) {
+ buffer.append("Problems:\n");
+ for (int i = 0; i < this.problems.length; i++) {
+ buffer.append(this.problems[i].toString());
+ }
+ } else {
+ if (hasValue()) {
+ buffer.append("(");
+ buffer.append(this.typeName);
+ buffer.append(") ");
+ buffer.append(this.displayString);
+ } else {
+ buffer.append("(No explicit return value)");
+ }
+ }
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/Evaluator.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/Evaluator.java
new file mode 100644
index 0000000000..ee0a13dc8b
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/Evaluator.java
@@ -0,0 +1,175 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+import java.util.*;
+
+/**
+ * A evaluator builds a compilation unit and compiles it into class files.
+ * If the compilation unit has problems, reports the problems using the
+ * requestor.
+ */
+public abstract class Evaluator {
+ EvaluationContext context;
+ INameEnvironment environment;
+ ConfigurableOption[] options;
+ IRequestor requestor;
+ IProblemFactory problemFactory;
+ /**
+ * Creates a new evaluator.
+ */
+ Evaluator(
+ EvaluationContext context,
+ INameEnvironment environment,
+ ConfigurableOption[] options,
+ IRequestor requestor,
+ IProblemFactory problemFactory) {
+ this.context = context;
+ this.environment = environment;
+ this.options = options;
+ this.requestor = requestor;
+ this.problemFactory = problemFactory;
+ }
+
+ /**
+ * Adds the given problem to the corresponding evaluation result in the given table. If the evaluation
+ * result doesn't exist yet, adds it in the table. Its evaluation id and evaluation type
+ * are computed so that they correspond to the given problem. If it is found to be an internal problem,
+ * then the evaluation id of the result is the given compilation unit source.
+ */
+ abstract protected void addEvaluationResultForCompilationProblem(
+ Hashtable resultsByIDs,
+ IProblem problem,
+ char[] cuSource);
+ /**
+ * Returns the evaluation results that converts the given compilation result that has problems.
+ * If the compilation result has more than one problem, then the problems are broken down so that
+ * each evaluation result has the same evaluation id.
+ */
+ protected EvaluationResult[] evaluationResultsForCompilationProblems(
+ CompilationResult result,
+ char[] cuSource) {
+ // Break down the problems and group them by ids in evaluation results
+ IProblem[] problems = result.getProblems();
+ Hashtable resultsByIDs = new Hashtable(5);
+ for (int i = 0; i < problems.length; i++) {
+ addEvaluationResultForCompilationProblem(resultsByIDs, problems[i], cuSource);
+ }
+
+ // Copy results
+ int size = resultsByIDs.size();
+ EvaluationResult[] evalResults = new EvaluationResult[size];
+ Enumeration results = resultsByIDs.elements();
+ for (int i = 0; i < size; i++) {
+ evalResults[i] = (EvaluationResult) results.nextElement();
+ }
+
+ return evalResults;
+ }
+
+ /**
+ * Compiles and returns the class definitions for the current compilation unit.
+ * Returns null if there are any errors.
+ */
+ ClassFile[] getClasses() {
+ final char[] source = getSource();
+ final Vector classDefinitions = new Vector();
+
+ // The requestor collects the class definitions and problems
+ class CompilerRequestor implements ICompilerRequestor {
+ boolean hasErrors = false;
+ public void acceptResult(CompilationResult result) {
+ if (result.hasProblems()) {
+ EvaluationResult[] evalResults =
+ evaluationResultsForCompilationProblems(result, source);
+ for (int i = 0; i < evalResults.length; i++) {
+ EvaluationResult evalResult = evalResults[i];
+ IProblem[] problems = evalResult.getProblems();
+ for (int j = 0; j < problems.length; j++) {
+ Evaluator.this.requestor.acceptProblem(
+ problems[j],
+ evalResult.getEvaluationID(),
+ evalResult.getEvaluationType());
+ }
+ }
+ }
+ if (result.hasErrors()) {
+ hasErrors = true;
+ } else {
+ ClassFile[] classFiles = result.getClassFiles();
+ for (int i = 0; i < classFiles.length; i++) {
+ ClassFile classFile = classFiles[i];
+ /*
+
+ char[] filename = classFile.fileName();
+ int length = filename.length;
+ char[] relativeName = new char[length + 6];
+ System.arraycopy(filename, 0, relativeName, 0, length);
+ System.arraycopy(".class".toCharArray(), 0, relativeName, length, 6);
+ CharOperation.replace(relativeName, '/', java.io.File.separatorChar);
+ ClassFile.writeToDisk("d:/test/snippet", new String(relativeName), classFile.getBytes());
+ String str = "d:/test/snippet" + "/" + new String(relativeName);
+ System.out.println(com.ibm.compiler.java.classfmt.disassembler.ClassFileDisassembler.disassemble(str));
+ */
+ classDefinitions.addElement(classFile);
+ }
+ }
+ }
+ }
+
+ // Compile compilation unit
+ CompilerRequestor compilerRequestor = new CompilerRequestor();
+ Compiler compiler = getCompiler(compilerRequestor);
+ compiler
+ .compile(
+ new ICompilationUnit[] { new ICompilationUnit() { public char[] getFileName() {
+ // Name of class is name of CU
+ return CharOperation.concat(
+ Evaluator.this.getClassName(),
+ ".java".toCharArray());
+ }
+ public char[] getContents() {
+ return source;
+ }
+ public char[] getMainTypeName() {
+ return Evaluator.this.getClassName();
+ }
+ }
+ });
+ if (compilerRequestor.hasErrors) {
+ return null;
+ } else {
+ ClassFile[] result = new ClassFile[classDefinitions.size()];
+ classDefinitions.copyInto(result);
+ return result;
+ }
+ }
+
+ /**
+ * Returns the name of the current class. This is the simple name of the class.
+ * This doesn't include the extension ".java" nor the name of the package.
+ */
+ abstract protected char[] getClassName();
+ /**
+ * Creates and returns a compiler for this evaluator.
+ */
+ Compiler getCompiler(ICompilerRequestor requestor) {
+ return new Compiler(
+ this.environment,
+ DefaultErrorHandlingPolicies.exitAfterAllProblems(),
+ this.options,
+ requestor,
+ this.problemFactory);
+ }
+
+ /**
+ * Builds and returns the source for the current compilation unit.
+ */
+ abstract protected char[] getSource();
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/GlobalVariable.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/GlobalVariable.java
new file mode 100644
index 0000000000..8fd60802cc
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/GlobalVariable.java
@@ -0,0 +1,61 @@
+package org.eclipse.jdt.internal.eval;
+
+public class GlobalVariable {
+ char[] typeName;
+ char[] name;
+ char[] initializer;
+ int declarationStart = -1, initializerStart = -1, initExpressionStart;
+ // positions in the global variable class definition
+ int initializerLineStart = -1; // line in the global variable class definition
+ /**
+ * Creates a new global variable with the given type name, name and initializer.
+ * initializer can be null if there is none.
+ */
+ public GlobalVariable(char[] typeName, char[] name, char[] initializer) {
+ this.typeName = typeName;
+ this.name = name;
+ this.initializer = initializer;
+ }
+
+ /**
+ * Returns the initializer of this global variable. The initializer is a
+ * variable initializer (ie. an expression or an array initializer) as defined
+ * in the Java Language Specifications.
+ */
+ public char[] getInitializer() {
+ return this.initializer;
+ }
+
+ /**
+ * Returns the name of this global variable.
+ */
+ public char[] getName() {
+ return this.name;
+ }
+
+ /**
+ * Returns the dot separated fully qualified name of the type of this global variable,
+ * or its simple representation if it is a primitive type (eg. int, boolean, etc.)
+ */
+ public char[] getTypeName() {
+ return this.typeName;
+ }
+
+ /**
+ * Returns a readable representation of the receiver.
+ * This is for debugging purpose only.
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(this.typeName);
+ buffer.append(" ");
+ buffer.append(this.name);
+ if (this.initializer != null) {
+ buffer.append("= ");
+ buffer.append(this.initializer);
+ }
+ buffer.append(";");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/IRequestor.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/IRequestor.java
new file mode 100644
index 0000000000..56c820fe42
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/IRequestor.java
@@ -0,0 +1,22 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.ClassFile;
+import org.eclipse.jdt.internal.compiler.IProblem;
+
+/**
+ * A callback interface for receiving code snippet evaluation results.
+ */
+public interface IRequestor {
+ /**
+ * @see ICodeSnippetRequestor
+ */
+ boolean acceptClassFiles(ClassFile[] classFiles, char[] codeSnippetClassName);
+ /**
+ * @see ICodeSnippetRequestor
+ */
+ void acceptProblem(IProblem problem, char[] fragmentSource, int fragmentKind);
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/InstallException.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/InstallException.java
new file mode 100644
index 0000000000..b12801b14c
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/InstallException.java
@@ -0,0 +1,21 @@
+package org.eclipse.jdt.internal.eval;
+
+public class InstallException extends Exception {
+ /**
+ * Constructs a <code>InstallException</code> with no detail message.
+ */
+ public InstallException() {
+ super();
+ }
+
+ /**
+ * Constructs a <code>InstallException</code> with the specified
+ * detail message.
+ *
+ * @param s the detail message.
+ */
+ public InstallException(String s) {
+ super(s);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/VariablesEvaluator.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/VariablesEvaluator.java
new file mode 100644
index 0000000000..c4d99fa3b0
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/VariablesEvaluator.java
@@ -0,0 +1,327 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.classfmt.*;
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+import org.eclipse.jdt.internal.core.JavaModelManager;
+import java.util.*;
+
+/**
+ * A variables evaluator compiles the global variables of an evaluation context and returns
+ * the corresponding class files. Or it reports problems against these variables.
+ */
+public class VariablesEvaluator
+ extends Evaluator
+ implements EvaluationConstants {
+ int startPosOffset = 0;
+ /**
+ * Creates a new global variables evaluator.
+ */
+ VariablesEvaluator(
+ EvaluationContext context,
+ INameEnvironment environment,
+ ConfigurableOption[] options,
+ IRequestor requestor,
+ IProblemFactory problemFactory) {
+ super(context, environment, options, requestor, problemFactory);
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.eval.Evaluator
+ */
+ protected void addEvaluationResultForCompilationProblem(
+ Hashtable resultsByIDs,
+ IProblem problem,
+ char[] cuSource) {
+ // set evaluation id and type to an internal problem by default
+ char[] evaluationID = cuSource;
+ int evaluationType = EvaluationResult.T_INTERNAL;
+
+ int pbLine = problem.getSourceLineNumber();
+ int currentLine = 1;
+
+ // check package declaration
+ char[] packageName = getPackageName();
+ if (packageName.length > 0) {
+ if (pbLine == 1) {
+ // set evaluation id and type
+ evaluationID = packageName;
+ evaluationType = EvaluationResult.T_PACKAGE;
+
+ // shift line number, source start and source end
+ problem.setSourceLineNumber(1);
+ problem.setSourceStart(0);
+ problem.setSourceEnd(evaluationID.length - 1);
+ }
+ currentLine++;
+ }
+
+ // check imports
+ char[][] imports = this.context.imports;
+ if ((currentLine <= pbLine) && (pbLine < (currentLine + imports.length))) {
+ // set evaluation id and type
+ evaluationID = imports[pbLine - currentLine];
+ evaluationType = EvaluationResult.T_IMPORT;
+
+ // shift line number, source start and source end
+ problem.setSourceLineNumber(1);
+ problem.setSourceStart(0);
+ problem.setSourceEnd(evaluationID.length - 1);
+ }
+ currentLine += imports.length + 1; // + 1 to skip the class declaration line
+
+ // check variable declarations
+ int varCount = this.context.variableCount;
+ if ((currentLine <= pbLine) && (pbLine < currentLine + varCount)) {
+ GlobalVariable var = this.context.variables[pbLine - currentLine];
+
+ // set evaluation id and type
+ evaluationID = var.getName();
+ evaluationType = EvaluationResult.T_VARIABLE;
+
+ // shift line number, source start and source end
+ int pbStart = problem.getSourceStart() - var.declarationStart;
+ int pbEnd = problem.getSourceEnd() - var.declarationStart;
+ int typeLength = var.getTypeName().length;
+ if ((0 <= pbStart) && (pbEnd < typeLength)) {
+ // problem on the type of the variable
+ problem.setSourceLineNumber(-1);
+ } else {
+ // problem on the name of the variable
+ pbStart -= typeLength + 1; // type length + space
+ pbEnd -= typeLength + 1; // type length + space
+ problem.setSourceLineNumber(0);
+ }
+ problem.setSourceStart(pbStart);
+ problem.setSourceEnd(pbEnd);
+ }
+ currentLine = -1; // not needed any longer
+
+ // check variable initializers
+ for (int i = 0; i < varCount; i++) {
+ GlobalVariable var = this.context.variables[i];
+ char[] initializer = var.getInitializer();
+ int initializerLength = initializer == null ? 0 : initializer.length;
+ if ((var.initializerStart <= problem.getSourceStart())
+ && (problem.getSourceEnd() < var.initializerStart + var.name.length)) {
+ /* Problem with the variable name.
+ Ignore because it must have already been reported
+ when checking the declaration.
+ */
+ return;
+ } else
+ if ((var.initExpressionStart <= problem.getSourceStart())
+ && (problem.getSourceEnd() < var.initExpressionStart + initializerLength)) {
+ // set evaluation id and type
+ evaluationID = var.name;
+ evaluationType = EvaluationResult.T_VARIABLE;
+
+ // shift line number, source start and source end
+ problem.setSourceLineNumber(pbLine - var.initializerLineStart + 1);
+ problem.setSourceStart(problem.getSourceStart() - var.initExpressionStart);
+ problem.setSourceEnd(problem.getSourceEnd() - var.initExpressionStart);
+
+ break;
+ }
+ }
+
+ EvaluationResult result = (EvaluationResult) resultsByIDs.get(evaluationID);
+ if (result == null) {
+ resultsByIDs.put(
+ evaluationID,
+ new EvaluationResult(evaluationID, evaluationType, new IProblem[] { problem }));
+ } else {
+ result.addProblem(problem);
+ }
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.eval.Evaluator
+ */
+ protected char[] getClassName() {
+ return CharOperation.concat(
+ this.context.GLOBAL_VARS_CLASS_NAME_PREFIX,
+ Integer.toString(this.context.VAR_CLASS_COUNTER + 1).toCharArray());
+ }
+
+ /**
+ * Creates and returns a compiler for this evaluator.
+ */
+ Compiler getCompiler(ICompilerRequestor requestor) {
+ Compiler compiler = super.getCompiler(requestor);
+
+ // Initialize the compiler's lookup environment with the already compiled super class
+ IBinaryType binaryType = this.context.getRootCodeSnippetBinary();
+ if (binaryType != null) {
+ compiler.lookupEnvironment.cacheBinaryType(binaryType);
+ }
+
+ // and the installed global variable classes
+ VariablesInfo installedVars = this.context.installedVars;
+ if (installedVars != null) {
+ ClassFile[] classFiles = installedVars.classFiles;
+ for (int i = 0; i < classFiles.length; i++) {
+ ClassFile classFile = classFiles[i];
+ IBinaryType binary = null;
+ try {
+ binary = new ClassFileReader(classFile.getBytes(), null);
+ } catch (ClassFormatException e) {
+ e.printStackTrace(); // Should never happen since we compiled this type
+ }
+ compiler.lookupEnvironment.cacheBinaryType(binary);
+ }
+ }
+
+ return compiler;
+ }
+
+ /**
+ * Returns the name of package of the current compilation unit.
+ */
+ protected char[] getPackageName() {
+ return this.context.packageName;
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.eval.Evaluator
+ */
+ protected char[] getSource() {
+ StringBuffer buffer = new StringBuffer();
+ int lineNumberOffset = 1;
+
+ // package declaration
+ char[] packageName = getPackageName();
+ if (packageName.length != 0) {
+ buffer.append("package ");
+ buffer.append(packageName);
+ buffer.append(';').append(JavaModelManager.LINE_SEPARATOR);
+ lineNumberOffset++;
+ }
+
+ // import declarations
+ char[][] imports = this.context.imports;
+ for (int i = 0; i < imports.length; i++) {
+ buffer.append("import ");
+ buffer.append(imports[i]);
+ buffer.append(';').append(JavaModelManager.LINE_SEPARATOR);
+ lineNumberOffset++;
+ }
+
+ // class declaration
+ buffer.append("public class ");
+ buffer.append(getClassName());
+ buffer.append(" extends ");
+ buffer.append(PACKAGE_NAME);
+ buffer.append(".");
+ buffer.append(ROOT_CLASS_NAME);
+ buffer.append(" {").append(JavaModelManager.LINE_SEPARATOR);
+ lineNumberOffset++;
+ startPosOffset = buffer.length();
+
+ // field declarations
+ GlobalVariable[] vars = this.context.variables;
+ VariablesInfo installedVars = this.context.installedVars;
+ for (int i = 0; i < this.context.variableCount; i++) {
+ GlobalVariable var = vars[i];
+ buffer.append("\tpublic static ");
+ var.declarationStart = buffer.length();
+ buffer.append(var.typeName);
+ buffer.append(" ");
+ char[] varName = var.name;
+ buffer.append(varName);
+ buffer.append(';').append(JavaModelManager.LINE_SEPARATOR);
+ lineNumberOffset++;
+ }
+
+ // field initializations
+ buffer.append("\tstatic {").append(JavaModelManager.LINE_SEPARATOR);
+ lineNumberOffset++;
+ for (int i = 0; i < this.context.variableCount; i++) {
+ GlobalVariable var = vars[i];
+ char[] varName = var.name;
+ GlobalVariable installedVar =
+ installedVars == null ? null : installedVars.varNamed(varName);
+ if (installedVar == null
+ || !CharOperation.equals(installedVar.typeName, var.typeName)) {
+ // Initialize with initializer if there was no previous value
+ char[] initializer = var.initializer;
+ if (initializer != null) {
+ buffer.append("\t\ttry {").append(JavaModelManager.LINE_SEPARATOR);
+ lineNumberOffset++;
+ var.initializerLineStart = lineNumberOffset;
+ buffer.append("\t\t\t");
+ var.initializerStart = buffer.length();
+ buffer.append(varName);
+ buffer.append("= ");
+ var.initExpressionStart = buffer.length();
+ buffer.append(initializer);
+ lineNumberOffset += numberOfCRs(initializer);
+ buffer.append(';').append(JavaModelManager.LINE_SEPARATOR);
+ buffer.append("\t\t} catch (Throwable e) {").append(
+ JavaModelManager.LINE_SEPARATOR);
+ buffer.append("\t\t\te.printStackTrace();").append(
+ JavaModelManager.LINE_SEPARATOR);
+ buffer.append("\t\t}").append(JavaModelManager.LINE_SEPARATOR);
+ lineNumberOffset += 4; // 4 CRs
+ }
+ } else {
+ // Initialize with previous value if name and type are the same
+ buffer.append("\t\t");
+ buffer.append(varName);
+ buffer.append("= ");
+ char[] installedPackageName = installedVars.packageName;
+ if (installedPackageName != null && installedPackageName.length != 0) {
+ buffer.append(installedPackageName);
+ buffer.append(".");
+ }
+ buffer.append(installedVars.className);
+ buffer.append(".");
+ buffer.append(varName);
+ buffer.append(';').append(JavaModelManager.LINE_SEPARATOR);
+ lineNumberOffset++;
+ }
+ }
+ buffer.append("\t}").append(JavaModelManager.LINE_SEPARATOR);
+
+ // end of class declaration
+ buffer.append('}').append(JavaModelManager.LINE_SEPARATOR);
+
+ // return result
+ int length = buffer.length();
+ char[] result = new char[length];
+ buffer.getChars(0, length, result, 0);
+ return result;
+ }
+
+ /**
+ * Returns the number of cariage returns included in the given source.
+ */
+ private int numberOfCRs(char[] source) {
+ int numberOfCRs = 0;
+ boolean lastWasCR = false;
+ for (int i = 0; i < source.length; i++) {
+ char currentChar = source[i];
+ switch (currentChar) {
+ case '\r' :
+ lastWasCR = true;
+ numberOfCRs++;
+ break;
+ case '\n' :
+ if (!lastWasCR)
+ numberOfCRs++; // merge CR-LF
+ lastWasCR = false;
+ break;
+ default :
+ lastWasCR = false;
+ }
+ }
+ return numberOfCRs;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/VariablesInfo.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/VariablesInfo.java
new file mode 100644
index 0000000000..f31afbbb74
--- /dev/null
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/VariablesInfo.java
@@ -0,0 +1,68 @@
+package org.eclipse.jdt.internal.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.ClassFile;
+import org.eclipse.jdt.internal.compiler.util.*;
+import java.util.*;
+
+/**
+ * This contains information about the installed variables such as
+ * their names, their types, the name of the class that defines them,
+ * the binary of the class (to be passed to the name environment when
+ * compiling the code snippet).
+ */
+public class VariablesInfo {
+ GlobalVariable[] variables;
+ ;
+ int variableCount;
+ char[] packageName;
+ char[] className;
+ ClassFile[] classFiles;
+ /**
+ * Creates a new variables info.
+ * The name of the global variable class is the simple name of this class.
+ * The package name can be null if the variables have been defined in the default package.
+ */
+ public VariablesInfo(
+ char[] packageName,
+ char[] className,
+ ClassFile[] classFiles,
+ GlobalVariable[] variables,
+ int variableCount) {
+ this.packageName = packageName;
+ this.className = className;
+ this.classFiles = classFiles;
+ this.variables = variables;
+ this.variableCount = variableCount;
+ }
+
+ /**
+ * Returns the index of the given variable.
+ * Returns -1 if not found.
+ */
+ int indexOf(GlobalVariable var) {
+ for (int i = 0; i < this.variableCount; i++) {
+ if (var.equals(this.variables[i]))
+ return i;
+ };
+ return -1;
+ }
+
+ /**
+ * Returns the variable with the given name.
+ * Returns null if not found.
+ */
+ GlobalVariable varNamed(char[] name) {
+ GlobalVariable[] vars = this.variables;
+ for (int i = 0; i < this.variableCount; i++) {
+ GlobalVariable var = vars[i];
+ if (CharOperation.equals(name, var.name))
+ return var;
+ };
+ return null;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CodeFormatter.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CodeFormatter.java
new file mode 100644
index 0000000000..bc2b004b80
--- /dev/null
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CodeFormatter.java
@@ -0,0 +1,2415 @@
+package org.eclipse.jdt.internal.formatter;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.parser.*;
+import org.eclipse.jdt.internal.formatter.impl.*;
+import java.util.*;
+
+/** <h2>How to format a piece of code ?</h2>
+ * <ul><li>Create an instance of <code>CodeFormatter</code>
+ * <li>Use the method <code>void format(aString)</code>
+ * on this instance to format <code>aString</code>.
+ * It will return the formatted string.</ul>
+*/
+
+public class CodeFormatter implements TerminalSymbols {
+
+ public FormatterOptions options;
+
+ /**
+ * Represents a block in the <code>constructions</code> stack.
+ */
+ public static final int BLOCK = TerminalSymbols.TokenNameLBRACE;
+ /**
+ * Represents a block following a control statement in the <code>constructions</code> stack.
+ */
+ public static final int NONINDENT_BLOCK = -100;
+ /**
+ * Contains the formatted output.
+ */
+ StringBuffer formattedSource;
+ /**
+ * Contains the current line.<br>
+ * Will be dumped at the next "newline"
+ */
+ StringBuffer currentLineBuffer;
+
+ /**
+ * Used during the formatting to get each token.
+ */
+ Scanner scanner;
+
+ /**
+ * Contains the tokens responsible for the current indentation level
+ * and the blocks not closed yet.
+ */
+ private int[] constructions;
+ /**
+ * Index in the <code>constructions</code> array.
+ */
+ private int constructionsCount;
+ /**
+ * Level of indentation of the current token (number of tab char put in front of it).
+ */
+ private int indentationLevel;
+
+ /**
+ * Regular level of indentation of all the lines
+ */
+ private int initialIndentationLevel;
+
+ /**
+ * Used to split a line.
+ */
+ Scanner splitScanner;
+ /**
+ * To remember the offset between the beginning of the line and the
+ * beginning of the comment.
+ */
+ int currentCommentOffset;
+ int currentLineIndentationLevel;
+ int maxLineSize = 30;
+ private boolean containsOpenCloseBraces;
+ private int indentationLevelForOpenCloseBraces;
+
+ /**
+ * Collections of positions to map
+ */
+ private int[] positionsToMap;
+
+ /**
+ * Collections of mapped positions
+ */
+ private int[] mappedPositions;
+
+ private int indexToMap;
+
+ private int indexInMap;
+
+ private int globalDelta;
+
+ private int lineDelta;
+
+ private int splitDelta;
+
+ private int beginningOfLineIndex;
+ /**
+ * Creates a new instance of Code Formatter using the FormattingOptions object
+ * given as argument
+ * @deprecated Use CodeFormatter(ConfigurableOption[]) instead
+ */
+ public CodeFormatter() {
+ this(null);
+ }
+
+ /**
+ * Creates a new instance of Code Formatter using the given settings.
+ */
+ public CodeFormatter(ConfigurableOption[] settings) {
+
+ // initialize internal state
+ constructionsCount = 0;
+ constructions = new int[10];
+ currentLineIndentationLevel = indentationLevel = initialIndentationLevel;
+ currentCommentOffset = -1;
+
+ // initialize primary and secondary scanners
+ scanner = new Scanner(true, true); // regular scanner for forming lines
+ scanner.recordLineSeparator = true;
+ // to remind of the position of the beginning of the line.
+ splitScanner = new Scanner(true, true);
+ // secondary scanner to split long lines formed by primary scanning
+
+ // initialize current line buffer
+ currentLineBuffer = new StringBuffer();
+ this.options = new FormatterOptions(settings);
+ }
+
+ /**
+ * Sets the behaviour of the formatter about the braces using the given flag.<br>
+ * <ul>
+ * <li>if true, the formatter add new line & indent before the opening brace.
+ * <li>if false, the formatter leaves the brace on the same line.
+ * </ul>
+ * @deprecated backward compatibility with VAJ
+ */
+
+ /** */
+ public void addNewLineOnOpeningBrace(boolean flag) {
+ options.setNewLineBeforeOpeningBraceMode(flag);
+ }
+
+ /**
+ * Returns true if a lineSeparator has to be inserted before <code>operator</code>
+ * false otherwise.
+ */
+ private static boolean breakLineBeforeOperator(int operator) {
+ switch (operator) {
+ case TokenNameCOMMA :
+ case TokenNameSEMICOLON :
+ case TokenNameEQUAL :
+ return false;
+ default :
+ return true;
+ }
+ }
+
+ /**
+ * Returns the end of the source code.
+ */
+ private final String copyRemainingSource() {
+ char str[] = scanner.source;
+ int startPosition = scanner.startPosition;
+ int length = str.length - startPosition;
+ StringBuffer bufr = new StringBuffer(length);
+ if (startPosition < str.length) {
+ bufr.append(str, startPosition, length);
+ }
+ return (bufr.toString());
+ }
+
+ /**
+ * Inserts <code>tabCount</code> tab character or their equivalent number of spaces.
+ */
+ private void dumpTab(int tabCount) {
+ if (options.indentWithTab) {
+ for (int j = 0; j < tabCount; j++) {
+ formattedSource.append('\t');
+ increaseSplitDelta(1);
+ }
+ } else {
+ for (int i = 0, max = options.tabSize * tabCount; i < max; i++) {
+ formattedSource.append(' ');
+ increaseSplitDelta(1);
+ }
+ }
+ }
+
+ /**
+ * Dumps <code>currentLineBuffer</code> into the formatted string.
+ */
+ private void flushBuffer() {
+ String currentString = currentLineBuffer.toString();
+ splitDelta = 0;
+ beginningOfLineIndex = formattedSource.length();
+ if (options.maxLineLength != 0) {
+ if (containsOpenCloseBraces) {
+ containsOpenCloseBraces = false;
+ outputLine(
+ currentString,
+ false,
+ indentationLevelForOpenCloseBraces,
+ 0,
+ -1,
+ null,
+ 0);
+ indentationLevelForOpenCloseBraces = currentLineIndentationLevel;
+ } else {
+ outputLine(currentString, false, currentLineIndentationLevel, 0, -1, null, 0);
+ }
+ } else {
+ formattedSource.append(currentString);
+ }
+ }
+
+ /**
+ * Formats the input string.
+ */
+ private void format() {
+ int token = 0;
+ int previousToken = 0;
+ int previousCompilableToken = 0;
+
+ int indentationOffset = 0;
+
+ int newLinesInWhitespace = 0;
+ // number of new lines in the previous whitespace token
+ // (used to leave blank lines before comments)
+ int pendingNewLines = 0;
+ boolean expectingOpenBrace = false;
+ boolean clearNonBlockIndents = false;
+ // true if all indentations till the 1st { (usefull after } or ;)
+ boolean pendingSpace = true;
+ boolean pendingNewlineAfterParen = false;
+ // true when a cr is to be put after a ) (in conditional statements)
+ boolean inAssignment = false;
+ boolean inArrayAssignment = false;
+ boolean inThrowsClause = false;
+ boolean inClassOrInterfaceHeader = false;
+
+ // openBracketCount is used to count the number of open brackets not closed yet.
+ int openBracketCount = 0;
+
+ int unarySignModifier = 0;
+
+ // openParenthesis[0] is used to count the parenthesis not belonging to a condition
+ // (eg foo();). parenthesis in for (...) are count elsewhere in the array.
+ int openParenthesisCount = 1;
+ int[] openParenthesis = new int[10];
+
+ // tokenBeforeColon is used to know what token goes along with the current :
+ // it can be case or ?
+ int tokenBeforeColonCount = 0;
+ int[] tokenBeforeColon = new int[10];
+
+ constructionsCount = 0; // initializes the constructions count.
+
+ // contains DO if in a DO..WHILE statement, UNITIALIZED otherwise.
+ int nlicsToken = 0;
+
+ // fix for 1FF17XY: LFCOM:ALL - Format problem on not matching } and else
+ boolean specialElse = false;
+
+ // OPTION (IndentationLevel): initial indentation level may be non-zero.
+ currentLineIndentationLevel += constructionsCount;
+
+ // An InvalidInputException exception might cause the termination of this loop.
+ try {
+ while (true) {
+ // Get the next token. Catch invalid input and output it
+ // with minimal formatting, also catch end of input and
+ // exit the loop.
+ try {
+ token = scanner.getNextToken();
+ } catch (InvalidInputException e) {
+ if (!handleInvalidToken(e)) {
+ throw e;
+ }
+ token = 0;
+ }
+ if (token == Scanner.TokenNameEOF)
+ break;
+
+ /* ## MODIFYING the indentation level before generating new lines
+ and indentation in the output string
+ */
+
+ // Removes all the indentations made by statements not followed by a block
+ // except if the current token is ELSE, CATCH or if we are in a switch/case
+
+ if (clearNonBlockIndents && (token != Scanner.TokenNameWHITESPACE)) {
+
+ switch (token) {
+ case TokenNameelse :
+ if (constructionsCount > 0
+ && constructions[constructionsCount - 1] == TokenNameelse) {
+ pendingNewLines = 1;
+ specialElse = true;
+ }
+ indentationLevel += popInclusiveUntil(TokenNameif);
+ break;
+ case TokenNamecatch :
+ indentationLevel += popInclusiveUntil(TokenNamecatch);
+ break;
+ case TokenNamefinally :
+ indentationLevel += popInclusiveUntil(TokenNamecatch);
+ break;
+ case TokenNamewhile :
+ if (nlicsToken == TokenNamedo) {
+ indentationLevel += pop(TokenNamedo);
+ break;
+ }
+ default :
+ indentationLevel += popExclusiveUntilBlockOrCase();
+ // clear until a CASE, DEFAULT or BLOCK is encountered.
+ // Thus, the indentationLevel is correctly cleared either
+ // in a switch/case statement or in any other situation.
+ }
+ clearNonBlockIndents = false;
+ }
+
+ // returns to the indentation level created by the SWITCH keyword
+ // if the current token is a CASE or a DEFAULT
+
+ if (token == TokenNamecase || token == TokenNamedefault) {
+ indentationLevel += pop(TokenNamecase);
+ }
+
+ if (token == Scanner.TokenNamethrows) {
+ inThrowsClause = true;
+ }
+
+ if (token == Scanner.TokenNameclass || token == Scanner.TokenNameinterface) {
+ inClassOrInterfaceHeader = true;
+ }
+ /* ## APPEND newlines and indentations to the output string
+ */
+
+ // Do not add a new line between ELSE and IF, if the option elseIfOnSameLine is true.
+ // Fix for 1ETLWPZ: IVJCOM:ALL - incorrect "else if" formatting
+ if (pendingNewlineAfterParen
+ && previousCompilableToken == TokenNameelse
+ && token == TokenNameif
+ && options.compactElseIfMode) {
+ pendingNewlineAfterParen = false;
+ pendingNewLines = 0;
+ indentationLevel += pop(TokenNameelse);
+ // because else if is now one single statement,
+ // the indentation level after it is increased by one and not by 2
+ // (else = 1 indent, if = 1 indent, but else if = 1 indent, not 2).
+ }
+
+ // Add a newline & indent to the formatted source string if
+ // a for/if-else/while statement was scanned and there is no block
+ // following it.
+
+ pendingNewlineAfterParen =
+ pendingNewlineAfterParen
+ || (previousCompilableToken == TokenNameRPAREN && token == TokenNameLBRACE);
+ if (pendingNewlineAfterParen && token != Scanner.TokenNameWHITESPACE) {
+ pendingNewlineAfterParen = false;
+
+ // Do to add a newline & indent sequence if the current token is an
+ // open brace or a period or if the current token is a semi-colon and the
+ // previous token is a close paren.
+ // add a new line if a parenthesis belonging to a for() statement
+ // has been closed and the current token is not an opening brace
+
+ if (token != TokenNameLBRACE
+ && !isComment(token) // to avoid adding new line between else and a comment
+ && token != TokenNameDOT
+ && !(previousCompilableToken == TokenNameRPAREN && token == TokenNameSEMICOLON)) {
+ newLine(1);
+ currentLineIndentationLevel += indentationLevel;
+ pendingNewLines = 0;
+ pendingSpace = false;
+ } else {
+ if (token == TokenNameLBRACE && options.newLineBeforeOpeningBraceMode) {
+ newLine(1);
+ currentLineIndentationLevel = indentationLevel;
+ pendingNewLines = 0;
+ pendingSpace = false;
+ }
+ }
+ }
+
+ // see PR 1G5G8EC
+ if (token == TokenNameLBRACE && inThrowsClause) {
+ inThrowsClause = false;
+ if (options.newLineBeforeOpeningBraceMode) {
+ newLine(1);
+ currentLineIndentationLevel = indentationLevel;
+ pendingNewLines = 0;
+ pendingSpace = false;
+ }
+ }
+
+ // see PR 1G5G82G
+ if (token == TokenNameLBRACE && inClassOrInterfaceHeader) {
+ inClassOrInterfaceHeader = false;
+ if (options.newLineBeforeOpeningBraceMode) {
+ newLine(1);
+ currentLineIndentationLevel = indentationLevel;
+ pendingNewLines = 0;
+ pendingSpace = false;
+ }
+ }
+ // Add pending new lines to the formatted source string.
+ // Note: pending new lines are not added if the current token
+ // is a single line comment or whitespace.
+ // if the comment is between parenthesis, there is no blank line preservation
+ // (if it's a one-line comment, a blank line is added after it).
+
+ if (((pendingNewLines > 0 && (!isComment(token)))
+ || (newLinesInWhitespace > 0 && (openParenthesisCount <= 1 && isComment(token)))
+ || (previousCompilableToken == TokenNameLBRACE && token == TokenNameRBRACE))
+ && token != Scanner.TokenNameWHITESPACE) {
+
+ // Do not add newline & indent between an adjoining close brace and
+ // close paren. Anonymous inner classes may use this form.
+
+ boolean closeBraceAndCloseParen =
+ previousToken == TokenNameRBRACE && token == TokenNameRPAREN;
+
+ // OPTION (NewLineInCompoundStatement): do not add newline & indent
+ // between close brace and else, (do) while, catch, and finally if
+ // newlineInCompoundStatement is true.
+
+ boolean nlicsOption =
+ previousToken == TokenNameRBRACE
+ && !options.newlineInControlStatementMode
+ && (token == TokenNameelse
+ || (token == TokenNamewhile && nlicsToken == TokenNamedo)
+ || token == TokenNamecatch
+ || token == TokenNamefinally);
+
+ // Do not add a newline & indent between a close brace and semi-colon.
+
+ boolean semiColonAndCloseBrace =
+ previousToken == TokenNameRBRACE && token == TokenNameSEMICOLON;
+
+ // Do not add a new line & indent between a multiline comment and a opening brace
+
+ boolean commentAndOpenBrace =
+ previousToken == Scanner.TokenNameCOMMENT_BLOCK && token == TokenNameLBRACE;
+
+ // Do not add a newline & indent between a close brace and a colon (in array assignments, for example).
+
+ boolean commaAndCloseBrace =
+ previousToken == TokenNameRBRACE && token == TokenNameCOMMA;
+
+ // Add a newline and indent, if appropriate.
+
+ if (specialElse
+ || (!commentAndOpenBrace
+ && !closeBraceAndCloseParen
+ && !nlicsOption
+ && !semiColonAndCloseBrace
+ && !commaAndCloseBrace)) {
+ // if clearAllBlankLinesMode=false, leaves the blank lines
+ // inserted by the user
+ // if clearAllBlankLinesMode=true, removes all of then
+ // and insert only blank lines required by the formatting.
+ if (!options.clearAllBlankLinesMode) {
+ pendingNewLines = (pendingNewLines < newLinesInWhitespace)
+ // (isComment(token))
+ ? newLinesInWhitespace : pendingNewLines;
+ pendingNewLines = (pendingNewLines > 2) ? 2 : pendingNewLines;
+ }
+
+ if (previousCompilableToken == TokenNameLBRACE && token == TokenNameRBRACE) {
+ containsOpenCloseBraces = true;
+ indentationLevelForOpenCloseBraces = currentLineIndentationLevel;
+ if (isComment(previousToken)) {
+ newLine(pendingNewLines);
+ } else {
+ /* if (!(constructionsCount > 1
+ && constructions[constructionsCount-1] == NONINDENT_BLOCK
+ && (constructions[constructionsCount-2] == TokenNamefor
+ || constructions[constructionsCount-2] == TokenNamewhile))) {*/
+ if (options.newLineInEmptyBlockMode) {
+ if (inArrayAssignment) {
+ newLine(1); // array assigment with an empty block
+ } else {
+ newLine(pendingNewLines);
+ }
+ }
+ // }
+ }
+ } else {
+ // see PR 1FKKC3U: LFCOM:WINNT - Format problem with a comment before the ';'
+ if (!((previousToken == Scanner.TokenNameCOMMENT_BLOCK
+ || previousToken == Scanner.TokenNameCOMMENT_JAVADOC)
+ && token == TokenNameSEMICOLON)) {
+ newLine(pendingNewLines);
+ }
+ }
+ if (((previousCompilableToken == TokenNameSEMICOLON)
+ || (previousCompilableToken == TokenNameLBRACE)
+ || (previousCompilableToken == TokenNameRBRACE)
+ || (isComment(previousToken)))
+ && (token == TokenNameRBRACE)) {
+ indentationOffset = -1;
+ indentationLevel += popExclusiveUntilBlock();
+ }
+
+ if (previousToken == Scanner.TokenNameCOMMENT_LINE && inAssignment) {
+ // PR 1FI5IPO
+ currentLineIndentationLevel++;
+ } else {
+ currentLineIndentationLevel = indentationLevel + indentationOffset;
+ }
+
+ pendingSpace = false;
+ indentationOffset = 0;
+ }
+ pendingNewLines = 0;
+ newLinesInWhitespace = 0;
+ specialElse = false;
+
+ if (nlicsToken == TokenNamedo && token == TokenNamewhile) {
+ nlicsToken = 0;
+ }
+ }
+
+ switch (token) {
+ case TokenNameelse :
+ case TokenNamefinally :
+ expectingOpenBrace = true;
+ pendingNewlineAfterParen = true;
+ indentationLevel += pushControlStatement(token);
+ break;
+ case TokenNamecase :
+ case TokenNamedefault :
+ if (tokenBeforeColonCount == tokenBeforeColon.length) {
+ System.arraycopy(
+ tokenBeforeColon,
+ 0,
+ (tokenBeforeColon = new int[tokenBeforeColonCount * 2]),
+ 0,
+ tokenBeforeColonCount);
+ }
+ tokenBeforeColon[tokenBeforeColonCount++] = TokenNamecase;
+ indentationLevel += pushControlStatement(TokenNamecase);
+ break;
+ case TokenNameQUESTION :
+ if (tokenBeforeColonCount == tokenBeforeColon.length) {
+ System.arraycopy(
+ tokenBeforeColon,
+ 0,
+ (tokenBeforeColon = new int[tokenBeforeColonCount * 2]),
+ 0,
+ tokenBeforeColonCount);
+ }
+ tokenBeforeColon[tokenBeforeColonCount++] = token;
+ break;
+ case TokenNameswitch :
+ case TokenNamefor :
+ case TokenNameif :
+ case TokenNamewhile :
+ if (openParenthesisCount == openParenthesis.length) {
+ System.arraycopy(
+ openParenthesis,
+ 0,
+ (openParenthesis = new int[openParenthesisCount * 2]),
+ 0,
+ openParenthesisCount);
+ }
+ openParenthesis[openParenthesisCount++] = 0;
+ expectingOpenBrace = true;
+
+ indentationLevel += pushControlStatement(token);
+ break;
+ case TokenNametry :
+ pendingNewlineAfterParen = true;
+ case TokenNamecatch :
+ // several CATCH statements can be contiguous.
+ // a CATCH is encountered pop until first CATCH (if a CATCH follows a TRY it works the same way,
+ // as CATCH and TRY are the same token in the stack).
+ expectingOpenBrace = true;
+ indentationLevel += pushControlStatement(TokenNamecatch);
+ break;
+
+ case TokenNamedo :
+ expectingOpenBrace = true;
+ indentationLevel += pushControlStatement(token);
+ nlicsToken = token;
+ break;
+ case TokenNamenew :
+
+ // The flag inAssigment is used to properly format
+ // array assignments, and if a non-array assignment
+ // statement is in progress, it is no longer
+ // beneficial to know this, so set the flag to false.
+
+ /* if (!inArrayAssignment) {
+ inAssignment = false;
+ }*/
+ break;
+ case TokenNameLPAREN :
+
+ // Put a space between the previous and current token if the
+ // previous token was not a keyword, open paren, logical
+ // compliment (eg: !), semi-colon, open brace, close brace,
+ // super, or this.
+
+ if (previousCompilableToken != TokenNameLBRACKET
+ && previousToken != TokenNameIdentifier
+ && previousToken != 0
+ && previousToken != TokenNameNOT
+ && previousToken != TokenNameLPAREN
+ && previousToken != TokenNameTWIDDLE
+ && previousToken != TokenNameSEMICOLON
+ && previousToken != TokenNameLBRACE
+ && previousToken != TokenNameRBRACE
+ && previousToken != TokenNamesuper
+ && previousToken != TokenNamethis) {
+ space();
+ }
+
+ // If in a for/if/while statement, increase the parenthesis count
+ // for the current openParenthesisCount
+ // else increase the count for stand alone parenthesis.
+ if (openParenthesisCount > 0)
+ openParenthesis[openParenthesisCount - 1]++;
+ else
+ openParenthesis[0]++;
+
+ pendingSpace = false;
+ break;
+ case TokenNameRPAREN :
+
+ // Decrease the parenthesis count
+ // if there is no more unclosed parenthesis,
+ // a new line and indent may be append (depending on the next token).
+
+ if ((openParenthesisCount > 1)
+ && (openParenthesis[openParenthesisCount - 1] > 0)) {
+ openParenthesis[openParenthesisCount - 1]--;
+ if (openParenthesis[openParenthesisCount - 1] <= 0) {
+ pendingNewlineAfterParen = true;
+ inAssignment = false;
+ openParenthesisCount--;
+
+ }
+ } else {
+ openParenthesis[0]--;
+ }
+
+ pendingSpace = false;
+ break;
+ case TokenNameLBRACE :
+ if ((previousCompilableToken == TokenNameRBRACKET)
+ || (previousCompilableToken == TokenNameEQUAL)) {
+ // if (previousCompilableToken == TokenNameRBRACKET) {
+ inArrayAssignment = true;
+ inAssignment = false;
+ }
+ if (inArrayAssignment) {
+ indentationLevel += pushBlock();
+ } else {
+ // Add new line and increase indentation level after open brace.
+ pendingNewLines = 1;
+ indentationLevel += pushBlock();
+ }
+ break;
+ case TokenNameRBRACE :
+ if (previousCompilableToken == TokenNameRPAREN) {
+ pendingSpace = false;
+ }
+ if (inArrayAssignment) {
+ inArrayAssignment = false;
+ pendingNewLines = 1;
+ indentationLevel += popInclusiveUntilBlock();
+ } else {
+ pendingNewLines = 1;
+ indentationLevel += popInclusiveUntilBlock();
+
+ if (previousCompilableToken == TokenNameRPAREN) {
+ // fix for 1FGDDV6: LFCOM:WIN98 - Weird splitting on message expression
+ currentLineBuffer.append(options.lineSeparatorSequence);
+ increaseLineDelta(options.lineSeparatorSequence.length);
+ }
+
+ if (constructionsCount > 0) {
+ switch (constructions[constructionsCount - 1]) {
+ case TokenNamefor :
+ //indentationLevel += popExclusiveUntilBlock();
+ //break;
+ case TokenNameswitch :
+ case TokenNameif :
+ case TokenNameelse :
+ case TokenNametry :
+ case TokenNamecatch :
+ case TokenNamefinally :
+ case TokenNamewhile :
+ case TokenNamedo :
+ clearNonBlockIndents = true;
+ default :
+ break;
+ }
+ }
+
+ }
+ break;
+ case TokenNameLBRACKET :
+ openBracketCount++;
+ pendingSpace = false;
+ break;
+ case TokenNameRBRACKET :
+ openBracketCount -= (openBracketCount > 0) ? 1 : 0;
+ // if there is no left bracket to close, the right bracket is ignored.
+ pendingSpace = false;
+ break;
+ case TokenNameCOMMA :
+ case TokenNameDOT :
+ pendingSpace = false;
+ break;
+ case TokenNameSEMICOLON :
+
+ // Do not generate line terminators in the definition of
+ // the for statement.
+ // if not in this case, jump a line and reduce indentation after the brace
+ // if the block it closes belongs to a conditional statement (if, while, do...).
+
+ if (openParenthesisCount <= 1) {
+ pendingNewLines = 1;
+ if (expectingOpenBrace) {
+ clearNonBlockIndents = true;
+ expectingOpenBrace = false;
+ }
+ }
+ inAssignment = false;
+ pendingSpace = false;
+ break;
+ case TokenNamePLUS_PLUS :
+ case TokenNameMINUS_MINUS :
+
+ // Do not put a space between a post-increment/decrement
+ // and the identifier being modified.
+
+ if (previousToken == TokenNameIdentifier
+ || previousToken == TokenNameRBRACKET) {
+ pendingSpace = false;
+ }
+ break;
+ case TokenNamePLUS : // previously ADDITION
+ case TokenNameMINUS :
+
+ // Handle the unary operators plus and minus via a 3-state flag.
+
+ if (!isLiteralToken(previousToken)
+ && previousToken != TokenNameIdentifier
+ && previousToken != TokenNameRPAREN
+ && previousToken != TokenNameRBRACKET) {
+ unarySignModifier = 2;
+ }
+ break;
+ case TokenNameCOLON :
+
+ // In a switch/case statement, add a newline & indent
+ // when a colon is encountered.
+ if (tokenBeforeColonCount > 0) {
+ if (tokenBeforeColon[tokenBeforeColonCount - 1] == TokenNamecase) {
+ pendingNewLines = 1;
+ }
+ tokenBeforeColonCount--;
+ }
+ break;
+ case TokenNameEQUAL :
+ inAssignment = true;
+ break;
+ case Scanner.TokenNameCOMMENT_LINE :
+ pendingNewLines = 1;
+ if (inAssignment) {
+ currentLineIndentationLevel++;
+ }
+ break; // a line is always inserted after a one-line comment
+ case Scanner.TokenNameCOMMENT_JAVADOC :
+ case Scanner.TokenNameCOMMENT_BLOCK :
+ currentCommentOffset = getCurrentCommentOffset();
+ if (openParenthesis[0] == 0 && openBracketCount < 1) {
+ pendingNewLines = 1;
+ // a new line is inserted only if the comment is not between parenthesis.
+ }
+ break;
+ case Scanner.TokenNameWHITESPACE :
+
+ // Count the number of line terminators in the whitespace so
+ // line spacing can be preserved near comments.
+
+ char[] source = scanner.source;
+ newLinesInWhitespace = 0;
+ for (int i = scanner.startPosition, max = scanner.currentPosition;
+ i < max;
+ i++) {
+ if (source[i] == '\n') {
+ newLinesInWhitespace++;
+ }
+ }
+ increaseLineDelta(scanner.startPosition - scanner.currentPosition);
+ break;
+ default :
+ if ((token == TokenNameIdentifier)
+ || isLiteralToken(token)
+ || token == TokenNamesuper
+ || token == TokenNamethis) {
+
+ // Do not put a space between a unary operator
+ // (eg: ++, --, +, -) and the identifier being modified.
+
+ unarySignModifier -= (unarySignModifier > 0) ? 1 : 0;
+ if (previousToken == TokenNamePLUS_PLUS
+ || previousToken == TokenNameMINUS_MINUS
+ || (unarySignModifier > 0)) {
+ pendingSpace = false;
+ }
+ }
+ break;
+ }
+
+ // Do not output whitespace tokens.
+
+ if (token != Scanner.TokenNameWHITESPACE) {
+
+ /* Add pending space to the formatted source string.
+ Do not output a space under the following circumstances:
+ 1) this is the first pass
+ 2) previous token is an open paren
+ 3) previous token is a period
+ 4) previous token is the logical compliment (eg: !)
+ 5) previous token is the bitwise compliment (eg: ~)
+ 6) previous token is the open bracket (eg: [)
+ 7) in an assignment statement, if the previous token is an
+ open brace or the current token is a close brace
+ 8) previous token is a single line comment
+ */
+
+ boolean openAndCloseBrace =
+ previousCompilableToken == TokenNameLBRACE && token == TokenNameRBRACE;
+
+ // to be replaced by a nicer condition.
+
+ if (pendingSpace
+ && insertSpaceAfter(previousToken)
+ && !(inAssignment
+ && (previousToken == TokenNameLBRACE || token == TokenNameRBRACE))
+ && previousToken != Scanner.TokenNameCOMMENT_LINE) {
+ if ((!(options.compactAssignmentMode && token == TokenNameEQUAL))
+ && !openAndCloseBrace)
+ space();
+ }
+
+ // Add the next token to the formatted source string.
+
+ outputCurrentToken(token);
+ if (token == Scanner.TokenNameCOMMENT_LINE && openParenthesisCount > 1) {
+ pendingNewLines = 0;
+ currentLineBuffer.append(options.lineSeparatorSequence);
+ increaseLineDelta(options.lineSeparatorSequence.length);
+ }
+ pendingSpace = true;
+ }
+
+ // Whitespace tokens do not need to be remembered.
+
+ if (token != Scanner.TokenNameWHITESPACE) {
+ previousToken = token;
+ if (token != Scanner.TokenNameCOMMENT_BLOCK
+ && token != Scanner.TokenNameCOMMENT_LINE
+ && token != Scanner.TokenNameCOMMENT_JAVADOC) {
+ previousCompilableToken = token;
+ }
+ }
+
+ }
+ output(copyRemainingSource());
+ flushBuffer(); // dump the last token of the source in the formatted output.
+ } catch (InvalidInputException e) {
+ output(copyRemainingSource());
+ flushBuffer(); // dump the last token of the source in the formatted output.
+ }
+ }
+
+ /**
+ * Formats a given source string, starting indenting it at depth 0
+ * using default options.
+ */
+ public static String format(String sourceString) {
+ return format(sourceString, 0, null);
+ }
+
+ /**
+ * Formats a given source string, starting indenting it at a particular
+ * depth and using the given options
+ */
+ public static String format(
+ String sourceString,
+ int initialIndentationLevel,
+ ConfigurableOption[] options) {
+ CodeFormatter formatter = new CodeFormatter(options);
+ formatter.setInitialIndentationLevel(initialIndentationLevel);
+ return formatter.formatSourceString(sourceString);
+ }
+
+ /**
+ * Formats the char array <code>sourceString</code>,
+ * and returns a string containing the formatted version.
+ * @return the formatted ouput.
+ */
+ public String formatSourceString(String sourceString) {
+ char[] sourceChars = sourceString.toCharArray();
+ formattedSource = new StringBuffer(sourceChars.length);
+ scanner.setSourceBuffer(sourceChars);
+ format();
+ return formattedSource.toString();
+ }
+
+ /**
+ * Returns the number of characters and tab char between the beginning of the line
+ * and the beginning of the comment.
+ */
+ private int getCurrentCommentOffset() {
+ int linePtr = scanner.linePtr;
+ // if there is no beginning of line, return 0.
+ if (linePtr < 0)
+ return 0;
+ int offset = 0;
+ int beginningOfLine = scanner.lineEnds[linePtr];
+ int currentStartPosition = scanner.startPosition;
+ char[] source = scanner.source;
+
+ // find the position of the beginning of the line containing the comment
+ while (beginningOfLine > currentStartPosition) {
+ if (linePtr > 0) {
+ beginningOfLine = scanner.lineEnds[--linePtr];
+ } else {
+ beginningOfLine = 0;
+ break;
+ }
+ }
+
+ for (int i = beginningOfLine; i < currentStartPosition; i++) {
+ char currentCharacter = source[i];
+ switch (currentCharacter) {
+ case '\t' :
+ offset += options.tabSize;
+ case '\n' :
+ case '\r' :
+ break;
+ default :
+ offset++;
+ }
+ }
+
+ return offset;
+ }
+
+ /**
+ * Returns an array of descriptions for the configurable options.
+ * The descriptions may be changed and passed back to a different
+ * compiler.
+ */
+ public static ConfigurableOption[] getDefaultOptions(Locale locale) {
+ return new FormatterOptions().getConfigurableOptions(locale);
+ }
+
+ /**
+ * Returns the array of mapped positions.
+ * Returns null is no positions have been set.
+ * @return int[]
+ */
+ public int[] getMappedPositions() {
+ return mappedPositions;
+ }
+
+ /**
+ * Returns the priority of the token given as argument<br>
+ * The most prioritary the token is, the smallest the return value is.
+ * @return the priority of <code>token</code>
+ * @param token the token of which the priority is requested
+ */
+ private static int getTokenPriority(int token) {
+ switch (token) {
+ case TokenNameextends :
+ case TokenNameimplements :
+ case TokenNamethrows :
+ return 10;
+ case TokenNameSEMICOLON : // ;
+ return 20;
+ case TokenNameCOMMA : // ,
+ return 25;
+ case TokenNameEQUAL : // =
+ return 30;
+ case TokenNameAND_AND : // &&
+ case TokenNameOR_OR : // ||
+ return 40;
+ case TokenNameQUESTION : // ?
+ case TokenNameCOLON : // :
+ return 50; // it's better cutting on ?: than on ;
+ case TokenNameEQUAL_EQUAL : // ==
+ case TokenNameNOT_EQUAL : // !=
+ return 60;
+ case TokenNameLESS : // <
+ case TokenNameLESS_EQUAL : // <=
+ case TokenNameGREATER : // >
+ case TokenNameGREATER_EQUAL : // >=
+ case TokenNameinstanceof : // instanceof
+ return 70;
+ case TokenNamePLUS : // +
+ case TokenNameMINUS : // -
+ return 80;
+ case TokenNameMULTIPLY : // *
+ case TokenNameDIVIDE : // /
+ case TokenNameREMAINDER : // %
+ return 90;
+ case TokenNameLEFT_SHIFT : // <<
+ case TokenNameRIGHT_SHIFT : // >>
+ case TokenNameUNSIGNED_RIGHT_SHIFT : // >>>
+ return 100;
+ case TokenNameAND : // &
+ case TokenNameOR : // |
+ case TokenNameXOR : // ^
+ return 110;
+ case TokenNameMULTIPLY_EQUAL : // *=
+ case TokenNameDIVIDE_EQUAL : // /=
+ case TokenNameREMAINDER_EQUAL : // %=
+ case TokenNamePLUS_EQUAL : // +=
+ case TokenNameMINUS_EQUAL : // -=
+ case TokenNameLEFT_SHIFT_EQUAL : // <<=
+ case TokenNameRIGHT_SHIFT_EQUAL : // >>=
+ case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : // >>>=
+ case TokenNameAND_EQUAL : // &=
+ case TokenNameXOR_EQUAL : // ^=
+ case TokenNameOR_EQUAL : // |=
+ return 120;
+ case TokenNameDOT : // .
+ return 130;
+ default :
+ return Integer.MAX_VALUE;
+ }
+ }
+
+ /**
+ * Handles the exception raised when an invalid token is encountered.
+ * Returns true if the exception has been handled, false otherwise.
+ */
+ private boolean handleInvalidToken(Exception e) {
+ if (e.getMessage().equals(Scanner.INVALID_CHARACTER_CONSTANT)
+ || e.getMessage().equals(Scanner.INVALID_CHAR_IN_STRING)
+ || e.getMessage().equals(Scanner.INVALID_ESCAPE)) {
+ return true;
+ }
+ return false;
+ }
+
+ private final void increaseGlobalDelta(int offset) {
+ globalDelta += offset;
+ }
+
+ private final void increaseLineDelta(int offset) {
+ lineDelta += offset;
+ }
+
+ private final void increaseSplitDelta(int offset) {
+ splitDelta += offset;
+ }
+
+ /**
+ * Returns true if a space has to be inserted after <code>operator</code>
+ * false otherwise.
+ */
+ private boolean insertSpaceAfter(int token) {
+ switch (token) {
+ case TokenNameLPAREN :
+ case TokenNameNOT :
+ case TokenNameTWIDDLE :
+ case TokenNameDOT :
+ case 0 : // no token
+ case TokenNameLBRACKET :
+ case Scanner.TokenNameCOMMENT_LINE :
+ return false;
+ default :
+ return true;
+ }
+
+ }
+
+ /**
+ * Returns true if a space has to be inserted before <code>operator</code>
+ * false otherwise.<br>
+ * Cannot be static as it uses the code formatter options
+ * (to know if the compact assignment mode is on).
+ */
+ private boolean insertSpaceBefore(int token) {
+ switch (token) {
+ case TokenNameEQUAL :
+ return (!options.compactAssignmentMode);
+ default :
+ return false;
+ }
+ }
+
+ private static boolean isComment(int token) {
+ boolean result =
+ token == Scanner.TokenNameCOMMENT_BLOCK
+ || token == Scanner.TokenNameCOMMENT_LINE
+ || token == Scanner.TokenNameCOMMENT_JAVADOC;
+ return result;
+ }
+
+ private static boolean isLiteralToken(int token) {
+ boolean result =
+ token == TokenNameIntegerLiteral
+ || token == TokenNameLongLiteral
+ || token == TokenNameFloatingPointLiteral
+ || token == TokenNameDoubleLiteral
+ || token == TokenNameCharacterLiteral
+ || token == TokenNameStringLiteral;
+ return result;
+ }
+
+ /**
+ * If the length of <code>oneLineBuffer</code> exceeds <code>maxLineLength</code>,
+ * it is split and the result is dumped in <code>formattedSource</code>
+ * @param newLineCount the number of new lines to append
+ */
+ private void newLine(int newLineCount) {
+
+ // format current line
+ splitDelta = 0;
+ beginningOfLineIndex = formattedSource.length();
+ String currentLine = currentLineBuffer.toString();
+ if (containsOpenCloseBraces) {
+ containsOpenCloseBraces = false;
+ outputLine(
+ currentLine,
+ false,
+ indentationLevelForOpenCloseBraces,
+ 0,
+ -1,
+ null,
+ 0);
+ indentationLevelForOpenCloseBraces = currentLineIndentationLevel;
+ } else {
+ outputLine(currentLine, false, currentLineIndentationLevel, 0, -1, null, 0);
+ }
+ // dump line break(s)
+ for (int i = 0; i < newLineCount; i++) {
+ formattedSource.append(options.lineSeparatorSequence);
+ increaseSplitDelta(options.lineSeparatorSequence.length);
+ }
+ // reset formatter for next line
+ int currentLength = currentLine.length();
+ currentLineBuffer =
+ new StringBuffer(
+ currentLength > maxLineSize ? maxLineSize = currentLength : maxLineSize);
+
+ increaseGlobalDelta(splitDelta);
+ increaseGlobalDelta(lineDelta);
+ lineDelta = 0;
+ currentLineIndentationLevel = initialIndentationLevel;
+ }
+
+ private String operatorString(int operator) {
+ switch (operator) {
+ case TokenNameextends :
+ return "extends";
+
+ case TokenNameimplements :
+ return "implements";
+
+ case TokenNamethrows :
+ return "throws";
+
+ case TokenNameSEMICOLON : // ;
+ return ";";
+
+ case TokenNameCOMMA : // ,
+ return ",";
+
+ case TokenNameEQUAL : // =
+ return "=";
+
+ case TokenNameAND_AND : // && (15.22)
+ return "&&";
+
+ case TokenNameOR_OR : // || (15.23)
+ return "||";
+
+ case TokenNameQUESTION : // ? (15.24)
+ return "?";
+
+ case TokenNameCOLON : // : (15.24)
+ return ":";
+
+ case TokenNameEQUAL_EQUAL : // == (15.20, 15.20.1, 15.20.2, 15.20.3)
+ return "==";
+
+ case TokenNameNOT_EQUAL : // != (15.20, 15.20.1, 15.20.2, 15.20.3)
+ return "!=";
+
+ case TokenNameLESS : // < (15.19.1)
+ return "<";
+
+ case TokenNameLESS_EQUAL : // <= (15.19.1)
+ return "<=";
+
+ case TokenNameGREATER : // > (15.19.1)
+ return ">";
+
+ case TokenNameGREATER_EQUAL : // >= (15.19.1)
+ return ">=";
+
+ case TokenNameinstanceof : // instanceof
+ return "instanceof";
+
+ case TokenNamePLUS : // + (15.17, 15.17.2)
+ return "+";
+
+ case TokenNameMINUS : // - (15.17.2)
+ return "-";
+
+ case TokenNameMULTIPLY : // * (15.16.1)
+ return "*";
+
+ case TokenNameDIVIDE : // / (15.16.2)
+ return "/";
+
+ case TokenNameREMAINDER : // % (15.16.3)
+ return "%";
+
+ case TokenNameLEFT_SHIFT : // << (15.18)
+ return "<<";
+
+ case TokenNameRIGHT_SHIFT : // >> (15.18)
+ return ">>";
+
+ case TokenNameUNSIGNED_RIGHT_SHIFT : // >>> (15.18)
+ return ">>>";
+
+ case TokenNameAND : // & (15.21, 15.21.1, 15.21.2)
+ return "&";
+
+ case TokenNameOR : // | (15.21, 15.21.1, 15.21.2)
+ return "|";
+
+ case TokenNameXOR : // ^ (15.21, 15.21.1, 15.21.2)
+ return "^";
+
+ case TokenNameMULTIPLY_EQUAL : // *= (15.25.2)
+ return "*=";
+
+ case TokenNameDIVIDE_EQUAL : // /= (15.25.2)
+ return "/=";
+
+ case TokenNameREMAINDER_EQUAL : // %= (15.25.2)
+ return "%=";
+
+ case TokenNamePLUS_EQUAL : // += (15.25.2)
+ return "+=";
+
+ case TokenNameMINUS_EQUAL : // -= (15.25.2)
+ return "-=";
+
+ case TokenNameLEFT_SHIFT_EQUAL : // <<= (15.25.2)
+ return "<<=";
+
+ case TokenNameRIGHT_SHIFT_EQUAL : // >>= (15.25.2)
+ return ">>=";
+
+ case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : // >>>= (15.25.2)
+ return ">>>=";
+
+ case TokenNameAND_EQUAL : // &= (15.25.2)
+ return "&=";
+
+ case TokenNameXOR_EQUAL : // ^= (15.25.2)
+ return "^=";
+
+ case TokenNameOR_EQUAL : // |= (15.25.2)
+ return "|=";
+
+ case TokenNameDOT : // .
+ return ".";
+
+ default :
+ return "";
+ }
+ }
+
+ /**
+ * Appends <code>stringToOutput</code> to the formatted output.<br>
+ * If it contains \n, append a LINE_SEPARATOR and indent after it.
+ */
+ private void output(String stringToOutput) {
+ char currentCharacter;
+ for (int i = 0, max = stringToOutput.length(); i < max; i++) {
+ currentCharacter = stringToOutput.charAt(i);
+ if (currentCharacter != '\t') {
+ currentLineBuffer.append(currentCharacter);
+ }
+ }
+ updateMappedPositions(scanner.startPosition);
+ }
+
+ /**
+ * Appends <code>token</code> to the formatted output.<br>
+ * If it contains <code>\n</code>, append a LINE_SEPARATOR and indent after it.
+ */
+ private void outputCurrentToken(int token) {
+ char[] source = scanner.source;
+ int startPosition = scanner.startPosition;
+
+ switch (token) {
+ case Scanner.TokenNameCOMMENT_JAVADOC :
+ case Scanner.TokenNameCOMMENT_BLOCK :
+ case Scanner.TokenNameCOMMENT_LINE :
+ boolean endOfLine = false;
+ int currentCommentOffset = getCurrentCommentOffset();
+ int beginningOfLineSpaces = 0;
+ for (int i = startPosition, max = scanner.currentPosition; i < max; i++) {
+ char currentCharacter = source[i];
+ switch (currentCharacter) {
+ case '\r' :
+ case '\n' :
+ endOfLine = true;
+ currentLineBuffer.append(currentCharacter);
+ beginningOfLineSpaces = 0;
+ break;
+ case '\t' :
+ if (endOfLine) {
+ // we remove a maximum of currentCommentOffset characters (tabs are converted to space numbers).
+ beginningOfLineSpaces += options.tabSize;
+ if (beginningOfLineSpaces > currentCommentOffset)
+ currentLineBuffer.append(currentCharacter);
+ } else {
+ currentLineBuffer.append(currentCharacter);
+ }
+ break;
+ case ' ' :
+ if (endOfLine) {
+ // we remove a maximum of currentCommentOffset characters (tabs are converted to space numbers).
+ beginningOfLineSpaces++;
+ if (beginningOfLineSpaces > currentCommentOffset)
+ currentLineBuffer.append(currentCharacter);
+ } else {
+ currentLineBuffer.append(currentCharacter);
+ }
+ break;
+ default :
+ beginningOfLineSpaces = 0;
+ currentLineBuffer.append(currentCharacter);
+ endOfLine = false;
+ }
+ }
+ break;
+ default :
+ currentLineBuffer.append(
+ source,
+ startPosition,
+ scanner.currentPosition - startPosition);
+ }
+ updateMappedPositions(startPosition);
+ }
+
+ /**
+ * Outputs <code>currentString</code>:<br>
+ * <ul><li>If its length is < maxLineLength, output
+ * <li>Otherwise it is split.</ul>
+ * @param currentString string to output
+ * @param preIndented whether the string to output was pre-indented
+ * @param depth number of indentation to put in front of <code>currentString</code>
+ * @param operator value of the operator belonging to <code>currentString</code>.
+ */
+ private void outputLine(
+ String currentString,
+ boolean preIndented,
+ int depth,
+ int operator,
+ int substringIndex,
+ int[] startSubstringIndexes,
+ int offsetInGlobalLine) {
+
+ boolean emptyFirstSubString = false;
+ String operatorString = operatorString(operator);
+ boolean placeOperatorBehind = !breakLineBeforeOperator(operator);
+ boolean placeOperatorAhead = !placeOperatorBehind;
+
+ // dump prefix operator?
+ if (placeOperatorAhead) {
+ if (!preIndented) {
+ dumpTab(depth);
+ preIndented = true;
+ }
+ if (operator != 0) {
+ if (insertSpaceBefore(operator)) {
+ formattedSource.append(' ');
+ increaseSplitDelta(1);
+ }
+ formattedSource.append(operatorString);
+ increaseSplitDelta(operatorString.length());
+
+ if (insertSpaceAfter(operator)
+ && operator != TokenNameimplements
+ && operator != TokenNameextends
+ && operator != TokenNamethrows) {
+ formattedSource.append(' ');
+ increaseSplitDelta(1);
+ }
+ }
+ }
+ SplitLine splitLine = null;
+ if (options.maxLineLength == 0
+ || currentString.length() < options.maxLineLength
+ || (splitLine = split(currentString, offsetInGlobalLine)) == null) {
+ // depending on the type of operator, outputs new line before of after dumping it
+ // indent before postfix operator
+ // indent also when the line cannot be split
+
+ if (operator == TokenNameextends
+ || operator == TokenNameimplements
+ || operator == TokenNamethrows) {
+ formattedSource.append(' ');
+ increaseSplitDelta(1);
+ }
+
+ if (placeOperatorBehind) {
+ if (!preIndented) {
+ dumpTab(depth);
+ }
+ }
+
+ boolean containsMultiLineComment = currentString.lastIndexOf("/*") != -1;
+ int numberOfSpaces = 0;
+ int max = currentString.length();
+ updateMappedPositionsWhileSplitting(
+ beginningOfLineIndex,
+ beginningOfLineIndex + max);
+ for (int i = 0; i < max; i++) {
+ char currentChar = currentString.charAt(i);
+ switch (currentChar) {
+ case '\r' :
+ break;
+ case '\n' :
+ if (i != max - 1) {
+ // fix for 1FFYL5C: LFCOM:ALL - Incorrect indentation when split with a comment inside a condition
+ // a substring cannot end with a lineSeparatorSequence,
+ // except if it has been added by format() after a one-line comment
+ formattedSource.append(options.lineSeparatorSequence);
+ increaseSplitDelta(options.lineSeparatorSequence.length);
+
+ if (containsMultiLineComment) {
+ // fix for 1FGGQCN: LFCOM:ALL - Space management in comments for the formatter
+ dumpTab(currentLineIndentationLevel);
+ } else {
+ // 1FGDDV6: LFCOM:WIN98 - Weird splitting on message expression
+ dumpTab(depth - 1);
+ }
+ }
+ break;
+ default :
+ formattedSource.append(currentChar);
+ }
+ }
+
+ // update positions inside the mappedPositions table
+ if (substringIndex != -1) {
+ int startPosition =
+ beginningOfLineIndex + startSubstringIndexes[substringIndex];
+ updateMappedPositionsWhileSplitting(startPosition, startPosition + max);
+
+ // compute the splitDelta resulting with the operator and blank removal
+ if (substringIndex + 1 != startSubstringIndexes.length) {
+ increaseSplitDelta(
+ startSubstringIndexes[substringIndex]
+ + max
+ - startSubstringIndexes[substringIndex
+ + 1]);
+ }
+ }
+ // dump postfix operator?
+ if (placeOperatorBehind) {
+ if (insertSpaceBefore(operator)) {
+ formattedSource.append(' ');
+ if (operator != 0) {
+ increaseSplitDelta(1);
+ }
+ }
+ formattedSource.append(operatorString);
+ if (operator != 0) {
+ increaseSplitDelta(operatorString.length());
+ }
+ }
+ return;
+ }
+
+ // fix for 1FG0BA3: LFCOM:WIN98 - Weird splitting on interfaces
+ // extends has to stand alone on a line when currentString has been split.
+ if (options.maxLineLength != 0
+ && splitLine != null
+ && (operator == TokenNameextends
+ || operator == TokenNameimplements
+ || operator == TokenNamethrows)) {
+ formattedSource.append(options.lineSeparatorSequence);
+ increaseSplitDelta(options.lineSeparatorSequence.length);
+
+ dumpTab(depth + 1);
+ } else {
+ if (operator == TokenNameextends
+ || operator == TokenNameimplements
+ || operator == TokenNamethrows) {
+ formattedSource.append(' ');
+ increaseSplitDelta(1);
+ }
+ }
+
+ // perform actual splitting
+ String result[] = splitLine.substrings;
+ int[] splitOperators = splitLine.operators;
+ int[] splitLineStartIndexes = splitLine.startSubstringsIndexes;
+
+ if (result[0].length() == 0) {
+ // when the substring 0 is null, the substring 1 is correctly indented.
+ depth--;
+ emptyFirstSubString = true;
+ }
+ // the operator going in front of the result[0] string is the operator parameter
+
+ for (int i = 0, max = result.length; i < max; i++) {
+ // the new depth is the current one if this is the first substring,
+ // the current one + 1 otherwise.
+
+ // if the substring is a comment, use the current indentation Level instead of the depth
+ // (-1 because the ouputline increases depth).
+ // (fix for 1FFC72R: LFCOM:ALL - Incorrect line split in presence of line comments)
+ String currentResult = result[i];
+
+ if (currentResult.length() != 0 || splitOperators[i] != 0) {
+ int newDepth =
+ (currentResult.startsWith("/*") || currentResult.startsWith("//"))
+ ? indentationLevel - 1
+ : depth;
+ outputLine(
+ currentResult,
+ i == 0 || (i == 1 && emptyFirstSubString) ? preIndented : false,
+ i == 0 ? newDepth : newDepth + 1,
+ splitOperators[i],
+ i,
+ splitLine.startSubstringsIndexes,
+ currentString.indexOf(currentResult));
+ if (i != max - 1) {
+ formattedSource.append(options.lineSeparatorSequence);
+ increaseSplitDelta(options.lineSeparatorSequence.length);
+ }
+ }
+ }
+ if (result.length == splitOperators.length - 1) {
+ int lastOperator = splitOperators[result.length];
+ String lastOperatorString = operatorString(lastOperator);
+ formattedSource.append(options.lineSeparatorSequence);
+ increaseSplitDelta(options.lineSeparatorSequence.length);
+
+ if (breakLineBeforeOperator(lastOperator)) {
+ dumpTab(depth + 1);
+ if (lastOperator != 0) {
+ if (insertSpaceBefore(lastOperator)) {
+ formattedSource.append(' ');
+ increaseSplitDelta(1);
+ }
+ formattedSource.append(lastOperatorString);
+ increaseSplitDelta(lastOperatorString.length());
+
+ if (insertSpaceAfter(lastOperator)
+ && lastOperator != TokenNameimplements
+ && lastOperator != TokenNameextends
+ && lastOperator != TokenNamethrows) {
+ formattedSource.append(' ');
+ increaseSplitDelta(1);
+ }
+ }
+ }
+ }
+ if (placeOperatorBehind) {
+ if (insertSpaceBefore(operator)) {
+ formattedSource.append(' ');
+ increaseSplitDelta(1);
+ }
+ formattedSource.append(operatorString);
+ //increaseSplitDelta(operatorString.length());
+ }
+ }
+
+ /**
+ * Pops the top statement of the stack if it is <code>token</code>
+ */
+ private int pop(int token) {
+ int delta = 0;
+ if ((constructionsCount > 0)
+ && (constructions[constructionsCount - 1] == token)) {
+ delta--;
+ constructionsCount--;
+ }
+ return delta;
+ }
+
+ /**
+ * Pops the top statement of the stack if it is a <code>BLOCK</code> or a <code>NONINDENT_BLOCK</code>.
+ */
+ private int popBlock() {
+ int delta = 0;
+ if ((constructionsCount > 0)
+ && ((constructions[constructionsCount - 1] == BLOCK)
+ || (constructions[constructionsCount - 1] == NONINDENT_BLOCK))) {
+ if (constructions[constructionsCount - 1] == BLOCK)
+ delta--;
+ constructionsCount--;
+ }
+ return delta;
+ }
+
+ /**
+ * Pops elements until the stack is empty or the top element is <code>token</code>.<br>
+ * Does not remove <code>token</code> from the stack.
+ * @param token the token to be left as the top of the stack
+ */
+ private int popExclusiveUntil(int token) {
+ int delta = 0;
+ int startCount = constructionsCount;
+ for (int i = startCount - 1; i >= 0 && constructions[i] != token; i--) {
+ if (constructions[i] != NONINDENT_BLOCK)
+ delta--;
+ constructionsCount--;
+ }
+ return delta;
+ }
+
+ /**
+ * Pops elements until the stack is empty or the top element is
+ * a <code>BLOCK</code> or a <code>NONINDENT_BLOCK</code>.<br>
+ * Does not remove it from the stack.
+ */
+ private int popExclusiveUntilBlock() {
+ int startCount = constructionsCount;
+ int delta = 0;
+ for (int i = startCount - 1;
+ i >= 0 && constructions[i] != BLOCK && constructions[i] != NONINDENT_BLOCK;
+ i--) {
+ constructionsCount--;
+ delta--;
+ }
+ return delta;
+ }
+
+ /**
+ * Pops elements until the stack is empty or the top element is
+ * a <code>BLOCK</code>, a <code>NONINDENT_BLOCK</code> or a <code>CASE</code>.<br>
+ * Does not remove it from the stack.
+ */
+ private int popExclusiveUntilBlockOrCase() {
+ int startCount = constructionsCount;
+ int delta = 0;
+ for (int i = startCount - 1;
+ i >= 0
+ && constructions[i] != BLOCK
+ && constructions[i] != NONINDENT_BLOCK
+ && constructions[i] != TokenNamecase;
+ i--) {
+ constructionsCount--;
+ delta--;
+ }
+ return delta;
+ }
+
+ /**
+ * Pops elements until the stack is empty or the top element is <code>token</code>.<br>
+ * Removes <code>token</code> from the stack too.
+ * @param token the token to remove from the stack
+ */
+ private int popInclusiveUntil(int token) {
+ int startCount = constructionsCount;
+ int delta = 0;
+ for (int i = startCount - 1; i >= 0 && constructions[i] != token; i--) {
+ if (constructions[i] != NONINDENT_BLOCK)
+ delta--;
+ constructionsCount--;
+ }
+ if (constructionsCount > 0) {
+ if (constructions[constructionsCount - 1] != NONINDENT_BLOCK)
+ delta--;
+ constructionsCount--;
+ }
+ return delta;
+ }
+
+ /**
+ * Pops elements until the stack is empty or the top element is
+ * a <code>BLOCK</code> or a <code>NONINDENT_BLOCK</code>.<br>
+ * Does not remove it from the stack.
+ */
+ private int popInclusiveUntilBlock() {
+ int startCount = constructionsCount;
+ int delta = 0;
+ for (int i = startCount - 1;
+ i >= 0 && (constructions[i] != BLOCK && constructions[i] != NONINDENT_BLOCK);
+ i--) {
+ delta--;
+ constructionsCount--;
+ }
+ if (constructionsCount > 0) {
+ if (constructions[constructionsCount - 1] == BLOCK)
+ delta--;
+ constructionsCount--;
+ }
+ return delta;
+ }
+
+ /**
+ * Pushes a block in the stack.<br>
+ * Pushes a <code>BLOCK</code> if the stack is empty or if the top element is a <code>BLOCK</code>,
+ * pushes <code>NONINDENT_BLOCK</code> otherwise.
+ * Creates a new bigger array if the current one is full.
+ */
+ private int pushBlock() {
+ int delta = 0;
+ if (constructionsCount == constructions.length)
+ System.arraycopy(
+ constructions,
+ 0,
+ (constructions = new int[constructionsCount * 2]),
+ 0,
+ constructionsCount);
+
+ if ((constructionsCount == 0)
+ || (constructions[constructionsCount - 1] == BLOCK)
+ || (constructions[constructionsCount - 1] == NONINDENT_BLOCK)
+ || (constructions[constructionsCount - 1] == TokenNamecase)) {
+ delta++;
+ constructions[constructionsCount++] = BLOCK;
+ } else {
+ constructions[constructionsCount++] = NONINDENT_BLOCK;
+ }
+ return delta;
+ }
+
+ /**
+ * Pushes <code>token</code>.<br>
+ * Creates a new bigger array if the current one is full.
+ */
+ private int pushControlStatement(int token) {
+ if (constructionsCount == constructions.length)
+ System.arraycopy(
+ constructions,
+ 0,
+ (constructions = new int[constructionsCount * 2]),
+ 0,
+ constructionsCount);
+ constructions[constructionsCount++] = token;
+ return 1;
+ }
+
+ private static boolean separateFirstArgumentOn(int currentToken) {
+ //return (currentToken == TokenNameCOMMA || currentToken == TokenNameSEMICOLON);
+ return currentToken != TokenNameif
+ && currentToken != TokenNameLPAREN
+ && currentToken != TokenNameNOT
+ && currentToken != TokenNamewhile
+ && currentToken != TokenNamefor
+ && currentToken != TokenNameswitch;
+ }
+
+ /**
+ * Sets the behaviour of the formatter about the braces
+ * using <coe>newBraceIndentationLevel</code><br>
+ * <ul>
+ * <li>if 0, the formatter add new line & indent
+ * when current token is open brace,
+ * remove extra indentation when current token is close brace.
+ * <li>if -1, the formatter does not add a new line before the brace.</ul>
+ *
+ * @deprecated backward compatibility with VAJ APIs,
+ * use addNewLineOnOpeningBrace(boolean) instead
+ * @see addNewLineOnOpeningBrace(boolean)
+ */
+ public void setBraceIndentationLevel(int newBraceIndentationLevel) {
+ options.setNewLineBeforeOpeningBraceMode(newBraceIndentationLevel == 0);
+ }
+
+ /**
+ * Sets the behaviour of the formatter regarding the whitespaces
+ * in the string to format.
+ * @param newClearBlankLines true if the blank lines can be wiped out
+ * false otherwise.
+ *
+ * @deprecated backward compatibility with VAJ
+ */
+ public void setClearBlankLines(boolean newClearBlankLines) {
+ options.setClearAllBlankLinesMode(newClearBlankLines);
+ }
+
+ /**
+ * Sets the number of consecutive spaces used to replace the tab char
+ * if <code>newIndentationLength</code> is greater than one.<br>
+ * @param newIndentationLength 1 if 1 indent = 1 tab char, n>1 if 1 indent = n consecutive spaces.
+ *
+ * @deprecated backward compatibility with VAJ
+ */
+ public void setIndentationLength(int newIndentationLength) {
+ options.setTabSize(newIndentationLength);
+ }
+
+ /**
+ * Sets the initial indentation level
+ * @param indentationLevel new indentation level
+ *
+ * @deprecated
+ */
+ public void setInitialIndentationLevel(int newIndentationLevel) {
+ this.initialIndentationLevel =
+ currentLineIndentationLevel = indentationLevel = newIndentationLevel;
+ }
+
+ /**
+ * Sets the behaviour of the scanner.<br>
+ * if <code>flag</code> is true, newline & indent won't be added
+ * between close brace and else, (do) while, catch, and finally.
+ * @param flag must be true if newline & indent must NOT
+ * be added between close brace and else, (do) while,
+ * catch, and finally, false otherwise.
+ *
+ * @deprecated backward compatibility with VAJ
+ */
+ public void setNewlineInCompoundStatement(boolean flag) {
+ options.setNewlineInControlStatementMode(flag);
+ }
+
+ /**
+ * Set the positions to map. The mapped positions should be retrieved using the
+ * getMappedPositions() method.
+ * @see getMappedPositions()
+ * @param positions int[]
+ */
+ public void setPositionsToMap(int[] positions) {
+ positionsToMap = positions;
+ lineDelta = 0;
+ globalDelta = 0;
+ mappedPositions = new int[positions.length];
+ }
+
+ /**
+ * Appends a space character to the current line buffer.
+ */
+ private void space() {
+ currentLineBuffer.append(' ');
+ increaseLineDelta(1);
+ }
+
+ /**
+ * Splits <code>stringToSplit</code> on the top level token<br>
+ * If there are several identical token at the same level,
+ * the string is cut into many pieces.
+ * @return an object containing the operator and all the substrings
+ * or null if the string cannot be split
+ */
+ public SplitLine split(String stringToSplit) {
+ return split(stringToSplit, 0);
+ }
+
+ /**
+ * Splits <code>stringToSplit</code> on the top level token<br>
+ * If there are several identical token at the same level,
+ * the string is cut into many pieces.
+ * @return an object containing the operator and all the substrings
+ * or null if the string cannot be split
+ */
+ public SplitLine split(String stringToSplit, int offsetInGlobalLine) {
+ // local variables
+ int currentToken = 0;
+ int splitTokenType = 0;
+ int splitTokenDepth = Integer.MAX_VALUE;
+ int splitTokenPriority = Integer.MAX_VALUE;
+
+ int[] substringsStartPositions = new int[10];
+ // contains the start position of substrings
+ int[] substringsEndPositions = new int[10];
+ // contains the start position of substrings
+ int substringsCount = 1; // index in the substringsStartPosition array
+ int[] splitOperators = new int[10];
+ // contains the start position of substrings
+ int splitOperatorsCount = 0; // index in the substringsStartPosition array
+ int[] openParenthesisPosition = new int[10];
+ int openParenthesisPositionCount = 0;
+ int position = 0;
+ int lastOpenParenthesisPosition = -1;
+ // used to remember the position of the 1st open parenthesis
+ // needed for a pattern like: A.B(C); we want formatted like A.B( split C);
+ // setup the scanner with a new source
+ int lastCommentStartPosition = -1;
+ // to remember the start position of the last comment
+ int firstTokenOnLine = -1;
+ // to remember the first token of the line
+ int previousToken = -1;
+ // to remember the previous token.
+ splitScanner.setSourceBuffer(stringToSplit.toCharArray());
+
+ try {
+ // start the loop
+ while (true) {
+ // takes the next token
+ try {
+ if (currentToken != Scanner.TokenNameWHITESPACE)
+ previousToken = currentToken;
+ currentToken = splitScanner.getNextToken();
+ } catch (InvalidInputException e) {
+ if (!handleInvalidToken(e))
+ throw e;
+ currentToken = 0; // this value is not modify when an exception is raised.
+ }
+ if (currentToken == TokenNameEOF)
+ break;
+
+ if (firstTokenOnLine == -1) {
+ firstTokenOnLine = currentToken;
+ }
+
+ switch (currentToken) {
+ case TokenNameRBRACE :
+ case TokenNameRPAREN :
+ if (openParenthesisPositionCount > 0) {
+ if (openParenthesisPositionCount == 1
+ && lastOpenParenthesisPosition < openParenthesisPosition[0]) {
+ lastOpenParenthesisPosition = openParenthesisPosition[0];
+ } else
+ if ((splitTokenDepth == Integer.MAX_VALUE)
+ || (splitTokenDepth > openParenthesisPositionCount
+ && openParenthesisPositionCount == 1)) {
+ splitTokenType = 0;
+ splitTokenDepth = openParenthesisPositionCount;
+ splitTokenPriority = Integer.MAX_VALUE;
+ substringsStartPositions[0] = 0;
+ // better token means the whole line until now is the first substring
+ substringsCount = 1; // resets the count of substrings
+
+ substringsEndPositions[0] = openParenthesisPosition[0];
+ // substring ends on operator start
+ position = openParenthesisPosition[0];
+ // the string mustn't be cut before the closing parenthesis but after the opening one.
+ splitOperatorsCount = 1; // resets the count of split operators
+ splitOperators[0] = 0;
+ }
+ openParenthesisPositionCount--;
+ }
+ break;
+ case TokenNameLBRACE :
+ case TokenNameLPAREN :
+ if (openParenthesisPositionCount == openParenthesisPosition.length) {
+ System.arraycopy(
+ openParenthesisPosition,
+ 0,
+ (openParenthesisPosition = new int[openParenthesisPositionCount * 2]),
+ 0,
+ openParenthesisPositionCount);
+ }
+ openParenthesisPosition[openParenthesisPositionCount++] =
+ splitScanner.currentPosition;
+ if (currentToken == TokenNameLPAREN && previousToken == TokenNameRPAREN) {
+ openParenthesisPosition[openParenthesisPositionCount - 1] =
+ splitScanner.startPosition;
+ }
+ break;
+ case TokenNameSEMICOLON : // ;
+ case TokenNameCOMMA : // ,
+ case TokenNameEQUAL : // =
+ if (openParenthesisPositionCount < splitTokenDepth
+ || (openParenthesisPositionCount == splitTokenDepth
+ && splitTokenPriority > getTokenPriority(currentToken))) {
+ // the current token is better than the one we currently have
+ // (in level or in priority if same level)
+ // reset the substringsCount
+ splitTokenDepth = openParenthesisPositionCount;
+ splitTokenType = currentToken;
+ splitTokenPriority = getTokenPriority(currentToken);
+ substringsStartPositions[0] = 0;
+ // better token means the whole line until now is the first substring
+
+ if (separateFirstArgumentOn(firstTokenOnLine)
+ && openParenthesisPositionCount > 0) {
+ substringsCount = 2; // resets the count of substrings
+
+ substringsEndPositions[0] = openParenthesisPosition[splitTokenDepth - 1];
+ substringsStartPositions[1] = openParenthesisPosition[splitTokenDepth - 1];
+ substringsEndPositions[1] = splitScanner.startPosition;
+ splitOperatorsCount = 2; // resets the count of split operators
+ splitOperators[0] = 0;
+ splitOperators[1] = currentToken;
+ position = splitScanner.currentPosition;
+ // next substring will start from operator end
+ } else {
+ substringsCount = 1; // resets the count of substrings
+
+ substringsEndPositions[0] = splitScanner.startPosition;
+ // substring ends on operator start
+ position = splitScanner.currentPosition;
+ // next substring will start from operator end
+ splitOperatorsCount = 1; // resets the count of split operators
+ splitOperators[0] = currentToken;
+ }
+ } else {
+ if ((openParenthesisPositionCount == splitTokenDepth
+ && splitTokenPriority == getTokenPriority(currentToken))
+ && splitTokenType != TokenNameEQUAL
+ && currentToken != TokenNameEQUAL) {
+ // fix for 1FG0BCN: LFCOM:WIN98 - Missing one indentation after split
+ // take only the 1st = into account.
+ // if another token with the same priority is found,
+ // push the start position of the substring and
+ // push the token into the stack.
+ // create a new array object if the current one is full.
+ if (substringsCount == substringsStartPositions.length) {
+ System.arraycopy(
+ substringsStartPositions,
+ 0,
+ (substringsStartPositions = new int[substringsCount * 2]),
+ 0,
+ substringsCount);
+ System.arraycopy(
+ substringsEndPositions,
+ 0,
+ (substringsEndPositions = new int[substringsCount * 2]),
+ 0,
+ substringsCount);
+ }
+ if (splitOperatorsCount == splitOperators.length) {
+ System.arraycopy(
+ splitOperators,
+ 0,
+ (splitOperators = new int[splitOperatorsCount * 2]),
+ 0,
+ splitOperatorsCount);
+ }
+ substringsStartPositions[substringsCount] = position;
+ substringsEndPositions[substringsCount++] = splitScanner.startPosition;
+ // substring ends on operator start
+ position = splitScanner.currentPosition;
+ // next substring will start from operator end
+ splitOperators[splitOperatorsCount++] = currentToken;
+ }
+ }
+ break;
+
+ case TokenNameCOLON : // : (15.24)
+ // see 1FK7C5R, we only split on a colon, when it is associated with a question-mark.
+ // indeed it might appear also behind a case statement, and we do not to break at this point.
+ if ((splitOperatorsCount == 0)
+ || splitOperators[splitOperatorsCount - 1] != TokenNameQUESTION) {
+ break;
+ }
+ case TokenNameextends :
+ case TokenNameimplements :
+ case TokenNamethrows :
+
+ case TokenNameDOT : // .
+ case TokenNameMULTIPLY : // * (15.16.1)
+ case TokenNameDIVIDE : // / (15.16.2)
+ case TokenNameREMAINDER : // % (15.16.3)
+ case TokenNamePLUS : // + (15.17, 15.17.2)
+ case TokenNameMINUS : // - (15.17.2)
+ case TokenNameLEFT_SHIFT : // << (15.18)
+ case TokenNameRIGHT_SHIFT : // >> (15.18)
+ case TokenNameUNSIGNED_RIGHT_SHIFT : // >>> (15.18)
+ case TokenNameLESS : // < (15.19.1)
+ case TokenNameLESS_EQUAL : // <= (15.19.1)
+ case TokenNameGREATER : // > (15.19.1)
+ case TokenNameGREATER_EQUAL : // >= (15.19.1)
+ case TokenNameinstanceof : // instanceof
+ case TokenNameEQUAL_EQUAL : // == (15.20, 15.20.1, 15.20.2, 15.20.3)
+ case TokenNameNOT_EQUAL : // != (15.20, 15.20.1, 15.20.2, 15.20.3)
+ case TokenNameAND : // & (15.21, 15.21.1, 15.21.2)
+ case TokenNameOR : // | (15.21, 15.21.1, 15.21.2)
+ case TokenNameXOR : // ^ (15.21, 15.21.1, 15.21.2)
+ case TokenNameAND_AND : // && (15.22)
+ case TokenNameOR_OR : // || (15.23)
+ case TokenNameQUESTION : // ? (15.24)
+ case TokenNameMULTIPLY_EQUAL : // *= (15.25.2)
+ case TokenNameDIVIDE_EQUAL : // /= (15.25.2)
+ case TokenNameREMAINDER_EQUAL : // %= (15.25.2)
+ case TokenNamePLUS_EQUAL : // += (15.25.2)
+ case TokenNameMINUS_EQUAL : // -= (15.25.2)
+ case TokenNameLEFT_SHIFT_EQUAL : // <<= (15.25.2)
+ case TokenNameRIGHT_SHIFT_EQUAL : // >>= (15.25.2)
+ case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : // >>>= (15.25.2)
+ case TokenNameAND_EQUAL : // &= (15.25.2)
+ case TokenNameXOR_EQUAL : // ^= (15.25.2)
+ case TokenNameOR_EQUAL : // |= (15.25.2)
+
+ if ((openParenthesisPositionCount < splitTokenDepth
+ || (openParenthesisPositionCount == splitTokenDepth
+ && splitTokenPriority > getTokenPriority(currentToken)))
+ && !((currentToken == TokenNamePLUS || currentToken == TokenNameMINUS)
+ && (previousToken == TokenNameLBRACE
+ || previousToken == TokenNameLBRACKET
+ || splitScanner.startPosition == 0))) {
+ // the current token is better than the one we currently have
+ // (in level or in priority if same level)
+ // reset the substringsCount
+ splitTokenDepth = openParenthesisPositionCount;
+ splitTokenType = currentToken;
+ splitTokenPriority = getTokenPriority(currentToken);
+ substringsStartPositions[0] = 0;
+ // better token means the whole line until now is the first substring
+
+ if (separateFirstArgumentOn(firstTokenOnLine)
+ && openParenthesisPositionCount > 0) {
+ substringsCount = 2; // resets the count of substrings
+
+ substringsEndPositions[0] = openParenthesisPosition[splitTokenDepth - 1];
+ substringsStartPositions[1] = openParenthesisPosition[splitTokenDepth - 1];
+ substringsEndPositions[1] = splitScanner.startPosition;
+ splitOperatorsCount = 3; // resets the count of split operators
+ splitOperators[0] = 0;
+ splitOperators[1] = 0;
+ splitOperators[2] = currentToken;
+ position = splitScanner.currentPosition;
+ // next substring will start from operator end
+ } else {
+ substringsCount = 1; // resets the count of substrings
+
+ substringsEndPositions[0] = splitScanner.startPosition;
+ // substring ends on operator start
+ position = splitScanner.currentPosition;
+ // next substring will start from operator end
+ splitOperatorsCount = 2; // resets the count of split operators
+ splitOperators[0] = 0;
+ // nothing for first operand since operator will be inserted in front of the second operand
+ splitOperators[1] = currentToken;
+
+ }
+ } else {
+ if (openParenthesisPositionCount == splitTokenDepth
+ && splitTokenPriority == getTokenPriority(currentToken)) {
+ // if another token with the same priority is found,
+ // push the start position of the substring and
+ // push the token into the stack.
+ // create a new array object if the current one is full.
+ if (substringsCount == substringsStartPositions.length) {
+ System.arraycopy(
+ substringsStartPositions,
+ 0,
+ (substringsStartPositions = new int[substringsCount * 2]),
+ 0,
+ substringsCount);
+ System.arraycopy(
+ substringsEndPositions,
+ 0,
+ (substringsEndPositions = new int[substringsCount * 2]),
+ 0,
+ substringsCount);
+ }
+ if (splitOperatorsCount == splitOperators.length) {
+ System.arraycopy(
+ splitOperators,
+ 0,
+ (splitOperators = new int[splitOperatorsCount * 2]),
+ 0,
+ splitOperatorsCount);
+ }
+ substringsStartPositions[substringsCount] = position;
+ substringsEndPositions[substringsCount++] = splitScanner.startPosition;
+ // substring ends on operator start
+ position = splitScanner.currentPosition;
+ // next substring will start from operator end
+ splitOperators[splitOperatorsCount++] = currentToken;
+ }
+ }
+ default :
+ break;
+ }
+ if (isComment(currentToken)) {
+ lastCommentStartPosition = splitScanner.startPosition;
+ } else {
+ lastCommentStartPosition = -1;
+ }
+ }
+ } catch (InvalidInputException e) {
+ return null;
+ }
+ // if the string cannot be split, return null.
+ if (splitOperatorsCount == 0)
+ return null;
+
+ // ## SPECIAL CASES BEGIN
+ if (((splitOperatorsCount == 2
+ && splitOperators[1] == TokenNameDOT
+ && splitTokenDepth == 0
+ && lastOpenParenthesisPosition > -1)
+ || (splitOperatorsCount > 2
+ && splitOperators[1] == TokenNameDOT
+ && splitTokenDepth == 0
+ && lastOpenParenthesisPosition > -1
+ && lastOpenParenthesisPosition <= options.maxLineLength)
+ || (separateFirstArgumentOn(firstTokenOnLine)
+ && splitTokenDepth > 0
+ && lastOpenParenthesisPosition > -1))
+ && (lastOpenParenthesisPosition < splitScanner.source.length
+ && splitScanner.source[lastOpenParenthesisPosition] != ')')) {
+ // fix for 1FH4J2H: LFCOM:WINNT - Formatter - Empty parenthesis should not be broken on two lines
+ // only one split on a top level .
+ // or more than one split on . and substring before open parenthesis fits one line.
+ // or split inside parenthesis and first token is not a for/while/if
+ SplitLine sl =
+ split(
+ stringToSplit.substring(lastOpenParenthesisPosition),
+ lastOpenParenthesisPosition);
+ if (sl == null || sl.operators[0] != TokenNameCOMMA) {
+ // trim() is used to remove the extra blanks at the end of the substring. See PR 1FGYPI1
+ return new SplitLine(
+ new int[] { 0, 0 },
+ new String[] {
+ stringToSplit.substring(0, lastOpenParenthesisPosition).trim(),
+ stringToSplit.substring(lastOpenParenthesisPosition)},
+ new int[] {
+ offsetInGlobalLine,
+ lastOpenParenthesisPosition + offsetInGlobalLine });
+ } else {
+
+ // right substring can be split and is split on comma
+ // copy substrings and operators
+ // except if the 1st string is empty.
+
+ int startIndex = (sl.substrings[0].length() == 0) ? 1 : 0;
+
+ int subStringsLength = sl.substrings.length + 1 - startIndex;
+ String[] result = new String[subStringsLength];
+ int[] startIndexes = new int[subStringsLength];
+ int operatorsLength = sl.operators.length + 1 - startIndex;
+ int[] operators = new int[operatorsLength];
+
+ result[0] = stringToSplit.substring(0, lastOpenParenthesisPosition);
+ operators[0] = 0;
+
+ System.arraycopy(
+ sl.startSubstringsIndexes,
+ startIndex,
+ startIndexes,
+ 1,
+ subStringsLength - 1);
+ for (int i = subStringsLength - 1; i >= 0; i--) {
+ startIndexes[i] += offsetInGlobalLine;
+ }
+ System.arraycopy(sl.substrings, startIndex, result, 1, subStringsLength - 1);
+ System.arraycopy(sl.operators, startIndex, operators, 1, operatorsLength - 1);
+
+ return new SplitLine(operators, result, startIndexes);
+ }
+ }
+
+ // if the last token is a comment and the substring before the comment fits on a line,
+ // split before the comment and return the result.
+ if (lastCommentStartPosition > -1
+ && lastCommentStartPosition < options.maxLineLength
+ && splitTokenPriority > 50) {
+ int end = lastCommentStartPosition;
+ int start = lastCommentStartPosition;
+ if (stringToSplit.charAt(end - 1) == ' ') {
+ end--;
+ }
+ if (start != end && stringToSplit.charAt(start) == ' ') {
+ start++;
+ }
+ return new SplitLine(
+ new int[] { 0, 0 },
+ new String[] { stringToSplit.substring(0, end), stringToSplit.substring(start)},
+ new int[] { 0, start });
+ }
+
+ if (position != stringToSplit.length()) {
+
+ if (substringsCount == substringsStartPositions.length) {
+ System.arraycopy(
+ substringsStartPositions,
+ 0,
+ (substringsStartPositions = new int[substringsCount * 2]),
+ 0,
+ substringsCount);
+ System.arraycopy(
+ substringsEndPositions,
+ 0,
+ (substringsEndPositions = new int[substringsCount * 2]),
+ 0,
+ substringsCount);
+ }
+ // avoid empty extra substring, e.g. line terminated with a semi-colon
+ substringsStartPositions[substringsCount] = position;
+ substringsEndPositions[substringsCount++] = stringToSplit.length();
+ }
+
+ if (splitOperatorsCount == splitOperators.length) {
+ System.arraycopy(
+ splitOperators,
+ 0,
+ (splitOperators = new int[splitOperatorsCount * 2]),
+ 0,
+ splitOperatorsCount);
+ }
+
+ splitOperators[splitOperatorsCount] = 0;
+
+ // the last element of the stack is the position of the end of StringToSPlit
+ // +1 because the substring method excludes the last character
+ String[] result = new String[substringsCount];
+ for (int i = 0; i < substringsCount; i++) {
+ int start = substringsStartPositions[i];
+ int end = substringsEndPositions[i];
+ if (stringToSplit.charAt(start) == ' ') {
+ start++;
+ substringsStartPositions[i]++;
+ }
+ if (end != start && stringToSplit.charAt(end - 1) == ' ') {
+ end--;
+ }
+
+ result[i] = stringToSplit.substring(start, end);
+ substringsStartPositions[i] += offsetInGlobalLine;
+ }
+ if (splitOperatorsCount > substringsCount) {
+ System.arraycopy(
+ substringsStartPositions,
+ 0,
+ (substringsStartPositions = new int[splitOperatorsCount]),
+ 0,
+ substringsCount);
+ System.arraycopy(
+ substringsEndPositions,
+ 0,
+ (substringsEndPositions = new int[splitOperatorsCount]),
+ 0,
+ substringsCount);
+ for (int i = substringsCount; i < splitOperatorsCount; i++) {
+ substringsStartPositions[i] = position;
+ substringsEndPositions[i] = position;
+ }
+ System.arraycopy(
+ splitOperators,
+ 0,
+ (splitOperators = new int[splitOperatorsCount]),
+ 0,
+ splitOperatorsCount);
+ } else {
+ System.arraycopy(
+ substringsStartPositions,
+ 0,
+ (substringsStartPositions = new int[substringsCount]),
+ 0,
+ substringsCount);
+ System.arraycopy(
+ substringsEndPositions,
+ 0,
+ (substringsEndPositions = new int[substringsCount]),
+ 0,
+ substringsCount);
+ System.arraycopy(
+ splitOperators,
+ 0,
+ (splitOperators = new int[substringsCount]),
+ 0,
+ substringsCount);
+ }
+
+ SplitLine splitLine =
+ new SplitLine(splitOperators, result, substringsStartPositions);
+ return splitLine;
+
+ }
+
+ private void updateMappedPositions(int startPosition) {
+ if (positionsToMap == null)
+ return;
+ char[] source = scanner.source;
+ int sourceLength = source.length;
+ while (indexToMap < positionsToMap.length
+ && positionsToMap[indexToMap] <= startPosition) {
+ int posToMap = positionsToMap[indexToMap];
+ if (posToMap < 0
+ || posToMap >= sourceLength) { // protection against out of bounds position
+ indexToMap = positionsToMap.length; // no more mapping
+ return;
+ }
+ if (Character.isWhitespace(source[posToMap])) {
+ mappedPositions[indexToMap] = startPosition + globalDelta + lineDelta;
+ } else {
+ mappedPositions[indexToMap] = posToMap + globalDelta + lineDelta;
+ }
+ indexToMap++;
+ }
+ }
+
+ private void updateMappedPositionsWhileSplitting(
+ int startPosition,
+ int endPosition) {
+ if (mappedPositions == null || mappedPositions.length == indexInMap)
+ return;
+
+ while (indexInMap < mappedPositions.length
+ && startPosition <= mappedPositions[indexInMap]
+ && mappedPositions[indexInMap] < endPosition
+ && indexInMap < indexToMap) {
+ mappedPositions[indexInMap] += splitDelta;
+ indexInMap++;
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/impl/FormatterOptions.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/impl/FormatterOptions.java
new file mode 100644
index 0000000000..54fa0388e3
--- /dev/null
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/impl/FormatterOptions.java
@@ -0,0 +1,255 @@
+package org.eclipse.jdt.internal.formatter.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.formatter.*;
+import java.util.*;
+
+public class FormatterOptions {
+
+ // by default, do not insert blank line before opening brace
+ public boolean newLineBeforeOpeningBraceMode = false;
+
+ // by default, do not insert blank line behind keywords (ELSE, CATCH, FINALLY,...) in control statements
+ public boolean newlineInControlStatementMode = false;
+
+ // by default, preserve one blank line per sequence of blank lines
+ public boolean clearAllBlankLinesMode = false;
+
+ // line splitting will occur when line exceeds this length
+ public int maxLineLength = 80;
+
+ public boolean compactAssignmentMode = false;
+ // if isTrue, assignments look like x= 12 (not like x = 12);
+
+ //number of consecutive spaces used to replace the tab char
+ public int tabSize = 4; // n spaces for one tab
+ public boolean indentWithTab = true;
+
+ public boolean compactElseIfMode = false;
+ // if true, else and if are kept on the same line.
+ public boolean newLineInEmptyBlockMode = true;
+ // if false, no new line in {} if it's empty.
+
+ public char[] lineSeparatorSequence =
+ System.getProperty("line.separator").toCharArray();
+ /**
+ * Initializing the formatter options with default settings
+ */
+ public FormatterOptions() {
+ }
+
+ /**
+ * Initializing the formatter options with external settings
+ */
+ public FormatterOptions(ConfigurableOption[] settings) {
+ if (settings == null)
+ return;
+ // filter options which are related to the compiler component
+ String componentName = CodeFormatter.class.getName();
+ for (int i = 0, max = settings.length; i < max; i++) {
+ if (settings[i].getComponentName().equals(componentName)) {
+ this.setOption(settings[i]);
+ }
+ }
+ }
+
+ /**
+ * Returns all the options of the Code Formatter to be shown by the UI
+ *
+ * @param locale java.util.Locale
+ * @return com.ibm.compiler.java.ConfigurableOption[]
+ */
+ public ConfigurableOption[] getConfigurableOptions(Locale locale) {
+ String componentName = CodeFormatter.class.getName();
+ return new ConfigurableOption[] {
+ new ConfigurableOption(
+ componentName,
+ "newline.openingBrace",
+ locale,
+ newLineBeforeOpeningBraceMode ? 0 : 1),
+ new ConfigurableOption(
+ componentName,
+ "newline.controlStatement",
+ locale,
+ newlineInControlStatementMode ? 0 : 1),
+ new ConfigurableOption(
+ componentName,
+ "newline.clearAll",
+ locale,
+ clearAllBlankLinesMode ? 0 : 1),
+ new ConfigurableOption(
+ componentName,
+ "newline.elseIf",
+ locale,
+ compactElseIfMode ? 0 : 1),
+ new ConfigurableOption(
+ componentName,
+ "newline.emptyBlock",
+ locale,
+ newLineInEmptyBlockMode ? 0 : 1),
+ new ConfigurableOption(componentName, "line.split", locale, maxLineLength),
+ new ConfigurableOption(
+ componentName,
+ "style.compactAssignment",
+ locale,
+ compactAssignmentMode ? 0 : 1),
+ new ConfigurableOption(
+ componentName,
+ "tabulation.char",
+ locale,
+ indentWithTab ? 0 : 1),
+ new ConfigurableOption(componentName, "tabulation.size", locale, tabSize)};
+ }
+
+ /**
+ *
+ * @return int
+ */
+ public int getMaxLineLength() {
+ return maxLineLength;
+ }
+
+ public int getTabSize() {
+ return tabSize;
+ }
+
+ public boolean isAddingNewLineBeforeOpeningBrace() {
+ return newLineBeforeOpeningBraceMode;
+ }
+
+ public boolean isAddingNewLineInControlStatement() {
+ return newlineInControlStatementMode;
+ }
+
+ public boolean isAddingNewLineInEmptyBlock() {
+ return newLineInEmptyBlockMode;
+ }
+
+ public boolean isClearingAllBlankLines() {
+ return clearAllBlankLinesMode;
+ }
+
+ public boolean isCompactingAssignment() {
+ return compactAssignmentMode;
+ }
+
+ public boolean isCompactingElseIf() {
+ return compactElseIfMode;
+ }
+
+ public boolean isUsingTabForIndenting() {
+ return indentWithTab;
+ }
+
+ public void setClearAllBlankLinesMode(boolean flag) {
+ clearAllBlankLinesMode = flag;
+ }
+
+ /** Set the behaviour of the formatter about the braces.<br>
+ * @param boolean newBraceIndentationLevel<ul>
+ * <li>if true, the formatter add new line & indent before the opening brace.
+ * <li>if false, the formatter leaves the brace on the same line.</ul>
+ */
+ public void setCompactAssignmentMode(boolean flag) {
+ compactAssignmentMode = flag;
+ }
+
+ /** Set the behaviour of the formatter about else if.<br>
+ * @param boolean flag<ul>
+ * <li>if true, a <code>else if</code> sequence is kept on the same line.
+ * <li>if false, <code>else if</code> is formatted like:
+ <pre>
+ else
+ if
+ </pre>
+ </ul>
+ */
+ public void setCompactElseIfMode(boolean flag) {
+ compactElseIfMode = flag;
+ }
+
+ /** Defines whether to use tab characters or sequence of spaces when indenting
+ * @param boolean useTab <ul>
+ * <li>if true, the formatter add new line & indent before the opening brace.
+ * <li>if false, the formatter leaves the brace on the same line.</ul>
+ */
+ public void setIndentationUsesTab(boolean flag) {
+ indentWithTab = flag;
+ }
+
+ public void setLineSeparator(String lineSeparator) {
+ lineSeparatorSequence = lineSeparator.toCharArray();
+ }
+
+ public void setMaxLineLength(int maxLineLength) {
+ this.maxLineLength = maxLineLength;
+ }
+
+ /** Set the behaviour of the formatter about the braces.<br>
+ * @param boolean newBraceIndentationLevel<ul>
+ * <li>if true, the formatter add new line & indent before the opening brace.
+ * <li>if false, the formatter leaves the brace on the same line.</ul>
+ */
+ public void setNewLineBeforeOpeningBraceMode(boolean flag) {
+ newLineBeforeOpeningBraceMode = flag;
+ }
+
+ public void setNewlineInControlStatementMode(boolean flag) {
+ newlineInControlStatementMode = flag;
+ }
+
+ public void setNewLineInEmptyBlockMode(boolean flag) {
+ newLineInEmptyBlockMode = flag;
+ }
+
+ /**
+ * Change the value of the option corresponding to the option number
+ *
+ * @param optionNumber <CODE>int</CODE>
+ * @param newValue <CODE>int</CODE>
+ */
+ public void setOption(ConfigurableOption setting) {
+
+ switch (setting.getID()) {
+ case 1 : // insert blank line before opening brace
+ setNewLineBeforeOpeningBraceMode(setting.getCurrentValueIndex() == 0);
+ break;
+ case 2 : // insert blank line behind keywords (ELSE, CATCH, FINALLY,...) in control statements
+ setNewlineInControlStatementMode(setting.getCurrentValueIndex() == 0);
+ break;
+ case 3 : // flush all blank lines
+ setClearAllBlankLinesMode(setting.getCurrentValueIndex() == 0);
+ break;
+ case 4 : // puts else if on the same line
+ setCompactElseIfMode(setting.getCurrentValueIndex() == 0);
+ break;
+ case 5 : // add a new line inside an empty block.
+ setNewLineInEmptyBlockMode(setting.getCurrentValueIndex() == 0);
+ break;
+ case 6 : // line splitting will occur when line exceeds this length (0 -> no splitting)
+ setMaxLineLength(setting.getCurrentValueIndex());
+ break;
+ case 7 : // if isTrue, assignments look like x= 12 (not like x = 12);
+ setCompactAssignmentMode(setting.getCurrentValueIndex() == 0);
+ break;
+ case 9 : // should use tab or spaces to indent
+ setIndentationUsesTab(setting.getCurrentValueIndex() == 0);
+ break;
+ case 10 : // amount of spaces for a tabulation
+ setTabSize(setting.getCurrentValueIndex());
+ break;
+ }
+ }
+
+ public void setReuseExistingLayoutMode(boolean flag) {
+ }
+
+ public void setTabSize(int size) {
+ this.tabSize = size;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/impl/SplitLine.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/impl/SplitLine.java
new file mode 100644
index 0000000000..ae1d73608e
--- /dev/null
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/impl/SplitLine.java
@@ -0,0 +1,210 @@
+package org.eclipse.jdt.internal.formatter.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.parser.*;
+
+/** Represents a split line: contains an operator and all substrings
+*/
+public class SplitLine implements TerminalSymbols {
+ public int[] operators; // the operator on which the string was split.
+ public String[] substrings;
+ public int[] startSubstringsIndexes;
+ /**
+ * SplitLine constructor comment.
+ */
+ public SplitLine(int[] operators, String[] substrings) {
+ this(operators, substrings, null);
+ }
+
+ /**
+ * SplitLine constructor comment.
+ */
+ public SplitLine(int[] operators, String[] substrings, int[] startIndexes) {
+ super();
+ this.operators = operators;
+ this.substrings = substrings;
+ this.startSubstringsIndexes = startIndexes;
+ }
+
+ /**
+ * Prints a nice representation of the receiver
+ * @return java.lang.String
+ */
+ public String toString() {
+ StringBuffer result = new StringBuffer();
+ String operatorString = new String();
+
+ for (int i = 0, max = substrings.length; i < max; i++) {
+ int currentOperator = operators[i];
+ String currentString = substrings[i];
+ boolean placeOperatorAhead =
+ currentOperator != TerminalSymbols.TokenNameCOMMA
+ && currentOperator != TerminalSymbols.TokenNameSEMICOLON;
+ boolean placeOperatorBehind =
+ currentOperator == TerminalSymbols.TokenNameCOMMA
+ || currentOperator == TerminalSymbols.TokenNameSEMICOLON;
+
+ switch (currentOperator) {
+ case TokenNameextends :
+ operatorString = "extends";
+ break;
+ case TokenNameimplements :
+ operatorString = "implements";
+ break;
+ case TokenNamethrows :
+ operatorString = "throws";
+ break;
+ case TokenNameSEMICOLON : // ;
+ operatorString = ";";
+ break;
+ case TokenNameCOMMA : // ,
+ operatorString = ",";
+ break;
+ case TokenNameEQUAL : // =
+ operatorString = "=";
+ break;
+ case TokenNameAND_AND : // && (15.22)
+ operatorString = "&&";
+ break;
+ case TokenNameOR_OR : // || (15.23)
+ operatorString = "||";
+ break;
+ case TokenNameQUESTION : // ? (15.24)
+ operatorString = "?";
+ break;
+
+ case TokenNameCOLON : // : (15.24)
+ operatorString = ":";
+ break;
+ case TokenNameEQUAL_EQUAL : // == (15.20, 15.20.1, 15.20.2, 15.20.3)
+ operatorString = "==";
+ break;
+
+ case TokenNameNOT_EQUAL : // != (15.20, 15.20.1, 15.20.2, 15.20.3)
+ operatorString = "!=";
+ break;
+
+ case TokenNameLESS : // < (15.19.1)
+ operatorString = "<";
+ break;
+
+ case TokenNameLESS_EQUAL : // <= (15.19.1)
+ operatorString = "<=";
+ break;
+
+ case TokenNameGREATER : // > (15.19.1)
+ operatorString = ">";
+ break;
+
+ case TokenNameGREATER_EQUAL : // >= (15.19.1)
+ operatorString = ">=";
+ break;
+
+ case TokenNameinstanceof : // instanceof
+ operatorString = "instanceof";
+ break;
+ case TokenNamePLUS : // + (15.17, 15.17.2)
+ operatorString = "+";
+ break;
+
+ case TokenNameMINUS : // - (15.17.2)
+ operatorString = "-";
+ break;
+ case TokenNameMULTIPLY : // * (15.16.1)
+ operatorString = "*";
+ break;
+
+ case TokenNameDIVIDE : // / (15.16.2)
+ operatorString = "/";
+ break;
+
+ case TokenNameREMAINDER : // % (15.16.3)
+ operatorString = "%";
+ break;
+ case TokenNameLEFT_SHIFT : // << (15.18)
+ operatorString = "<<";
+ break;
+
+ case TokenNameRIGHT_SHIFT : // >> (15.18)
+ operatorString = ">>";
+ break;
+
+ case TokenNameUNSIGNED_RIGHT_SHIFT : // >>> (15.18)
+ operatorString = ">>>";
+ break;
+ case TokenNameAND : // & (15.21, 15.21.1, 15.21.2)
+ operatorString = "&";
+ break;
+
+ case TokenNameOR : // | (15.21, 15.21.1, 15.21.2)
+ operatorString = "|";
+ break;
+
+ case TokenNameXOR : // ^ (15.21, 15.21.1, 15.21.2)
+ operatorString = "^";
+ break;
+ case TokenNameMULTIPLY_EQUAL : // *= (15.25.2)
+ operatorString = "*=";
+ break;
+
+ case TokenNameDIVIDE_EQUAL : // /= (15.25.2)
+ operatorString = "/=";
+ break;
+ case TokenNameREMAINDER_EQUAL : // %= (15.25.2)
+ operatorString = "%=";
+ break;
+
+ case TokenNamePLUS_EQUAL : // += (15.25.2)
+ operatorString = "+=";
+ break;
+
+ case TokenNameMINUS_EQUAL : // -= (15.25.2)
+ operatorString = "-=";
+ break;
+
+ case TokenNameLEFT_SHIFT_EQUAL : // <<= (15.25.2)
+ operatorString = "<<=";
+ break;
+
+ case TokenNameRIGHT_SHIFT_EQUAL : // >>= (15.25.2)
+ operatorString = ">>=";
+ break;
+
+ case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : // >>>= (15.25.2)
+ operatorString = ">>>=";
+ break;
+
+ case TokenNameAND_EQUAL : // &= (15.25.2)
+ operatorString = "&=";
+ break;
+
+ case TokenNameXOR_EQUAL : // ^= (15.25.2)
+ operatorString = "^=";
+ break;
+
+ case TokenNameOR_EQUAL : // |= (15.25.2)
+ operatorString = "|=";
+ break;
+ case TokenNameDOT : // .
+ operatorString = ".";
+ break;
+
+ default :
+ operatorString = "";
+ }
+ if (placeOperatorAhead) {
+ result.append(operatorString);
+ }
+ result.append(currentString);
+ if (placeOperatorBehind) {
+ result.append(operatorString);
+ }
+ result.append('\n');
+ }
+ return "";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/Readme.txt b/org.eclipse.jdt.core/model/Readme.txt
new file mode 100644
index 0000000000..54a73c8d02
--- /dev/null
+++ b/org.eclipse.jdt.core/model/Readme.txt
@@ -0,0 +1 @@
+This folder contains the project resources for the IBM Tooling Platform Java Model project.
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/BufferChangedEvent.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/BufferChangedEvent.java
new file mode 100644
index 0000000000..54ba0fedfd
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/BufferChangedEvent.java
@@ -0,0 +1,112 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.EventObject;
+
+/**
+ * A buffer changed event describes how a buffer has changed. These events are
+ * used in <code>IBufferChangedListener</code> notifications.
+ * <p>
+ * For text insertions, <code>getOffset</code> is the offset
+ * of the first inserted character, <code>getText</code> is the
+ * inserted text, and <code>getLength</code> is 0.
+ * </p>
+ * <p>
+ * For text removals, <code>getOffset</code> is the offset
+ * of the first removed character, <code>getText</code> is <code>null</code>,
+ * and <code>getLength</code> is the length of the text that was removed.
+ * </p>
+ * <p>
+ * For replacements (including <code>IBuffer.setContents</code>),
+ * <code>getOffset</code> is the offset
+ * of the first replaced character, <code>getText</code> is the replacement
+ * text, and <code>getLength</code> is the length of the original text
+ * that was replaced.
+ * </p>
+ * <p>
+ * When a buffer is closed, <code>getOffset</code> is 0, <code>getLength</code>
+ * is 0, and <code>getText</code> is <code>null</code>.
+ * </p>
+ * <p>
+ * This class is not intended to be instantiated or subclassed by clients.
+ * Instances of this class are automatically created by the Java model.
+ * </p>
+ *
+ * @see IBuffer
+ */
+public class BufferChangedEvent extends EventObject {
+
+ /**
+ * The length of text that has been modified in the buffer.
+ */
+ private int length;
+
+ /**
+ * The offset into the buffer where the modification took place.
+ */
+ private int offset;
+
+ /**
+ * The text that was modified.
+ */
+ private String text;
+
+ /**
+ * Creates a new buffer changed event indicating that the given buffer has changed.
+ */
+ public BufferChangedEvent(
+ IBuffer buffer,
+ int offset,
+ int length,
+ String text) {
+ super(buffer);
+ this.offset = offset;
+ this.length = length;
+ this.text = text;
+ }
+
+ /**
+ * Returns the buffer which has changed.
+ *
+ * @return the buffer affected by the change
+ */
+ public IBuffer getBuffer() {
+ return (IBuffer) source;
+ }
+
+ /**
+ * Returns the length of text removed or replaced in the buffer, or
+ * 0 if text has been inserted into the buffer.
+ *
+ * @return the length of the original text fragment modified by the
+ * buffer change (<code> 0 </code> in case of insertion).
+ */
+ public int getLength() {
+ return this.length;
+ }
+
+ /**
+ * Returns the index of the first character inserted, removed, or replaced
+ * in the buffer.
+ *
+ * @return the source offset of the textual manipulation in the buffer
+ */
+ public int getOffset() {
+ return this.offset;
+ }
+
+ /**
+ * Returns the text that was inserted, the replacement text,
+ * or <code>null</code> if text has been removed.
+ *
+ * @return the text corresponding to the buffer change (<code> null </code>
+ * in case of deletion).
+ */
+ public String getText() {
+ return this.text;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ElementChangedEvent.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ElementChangedEvent.java
new file mode 100644
index 0000000000..b408713c73
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ElementChangedEvent.java
@@ -0,0 +1,40 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.EventObject;
+
+/**
+ * An element changed event describes a change to the structure or contents
+ * of a tree of Java elements. The changes to the elements are described by
+ * the associated delta object carried by this event.
+ * <p>
+ * This class is not intended to be instantiated or subclassed by clients.
+ * Instances of this class are automatically created by the Java model.
+ * </p>
+ *
+ * @see IElementChangedListener
+ * @see IJavaElementDelta
+ */
+public class ElementChangedEvent extends EventObject {
+ /**
+ * Creates an new element changed event (based on a <code>IJavaElementDelta</code>).
+ *
+ * @param delta the Java element delta.
+ */
+ public ElementChangedEvent(IJavaElementDelta delta) {
+ super(delta);
+ }
+
+ /**
+ * Returns the delta describing the change.
+ *
+ * @return the delta describing the change
+ */
+ public IJavaElementDelta getDelta() {
+ return (IJavaElementDelta) source;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Flags.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Flags.java
new file mode 100644
index 0000000000..c4ea380943
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Flags.java
@@ -0,0 +1,217 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.jdt.internal.compiler.env.IConstants;
+
+/**
+ * Utility class for decoding modifier flags in Java elements.
+ * <p>
+ * This class provides static methods only; it is not intended to be
+ * instantiated or subclassed by clients.
+ * </p>
+ *
+ * @see IMember#getFlags
+ */
+public final class Flags {
+ /**
+ * Not instantiable.
+ */
+ private Flags() {
+ }
+
+ /**
+ * Returns whether the given integer includes the <code>abstract</code> modifier.
+ *
+ * @param flags the flags
+ * @return <code>true</code> if the <code>abstract</code> modifier is included
+ */
+ public static boolean isAbstract(int flags) {
+ return (flags & IConstants.AccAbstract) != 0;
+ }
+
+ /**
+ * Returns whether the given integer includes the indication that the
+ * element is deprecated (<code>@deprecated</code> tag in Javadoc comment).
+ *
+ * @param flags the flags
+ * @return <code>true</code> if the element is marked as deprecated
+ */
+ public static boolean isDeprecated(int flags) {
+ return (flags & IConstants.AccDeprecated) != 0;
+ }
+
+ /**
+ * Returns whether the given integer includes the <code>final</code> modifier.
+ *
+ * @param flags the flags
+ * @return <code>true</code> if the <code>final</code> modifier is included
+ */
+ public static boolean isFinal(int flags) {
+ return (flags & IConstants.AccFinal) != 0;
+ }
+
+ /**
+ * Returns whether the given integer includes the <code>native</code> modifier.
+ *
+ * @param flags the flags
+ * @return <code>true</code> if the <code>native</code> modifier is included
+ */
+ public static boolean isNative(int flags) {
+ return (flags & IConstants.AccNative) != 0;
+ }
+
+ /**
+ * Returns whether the given integer includes the <code>private</code> modifier.
+ *
+ * @param flags the flags
+ * @return <code>true</code> if the <code>private</code> modifier is included
+ */
+ public static boolean isPrivate(int flags) {
+ return (flags & IConstants.AccPrivate) != 0;
+ }
+
+ /**
+ * Returns whether the given integer includes the <code>protected</code> modifier.
+ *
+ * @param flags the flags
+ * @return <code>true</code> if the <code>protected</code> modifier is included
+ */
+ public static boolean isProtected(int flags) {
+ return (flags & IConstants.AccProtected) != 0;
+ }
+
+ /**
+ * Returns whether the given integer includes the <code>public</code> modifier.
+ *
+ * @param flags the flags
+ * @return <code>true</code> if the <code>public</code> modifier is included
+ */
+ public static boolean isPublic(int flags) {
+ return (flags & IConstants.AccPublic) != 0;
+ }
+
+ /**
+ * Returns whether the given integer includes the <code>static</code> modifier.
+ *
+ * @param flags the flags
+ * @return <code>true</code> if the <code>static</code> modifier is included
+ */
+ public static boolean isStatic(int flags) {
+ return (flags & IConstants.AccStatic) != 0;
+ }
+
+ /**
+ * Returns whether the given integer includes the <code>strictfp</code> modifier.
+ *
+ * @param flags the flags
+ * @return <code>true</code> if the <code>strictfp</code> modifier is included
+ */
+ public static boolean isStrictfp(int flags) {
+ return (flags & IConstants.AccStrictfp) != 0;
+ }
+
+ /**
+ * Returns whether the given integer includes the <code>synchronized</code> modifier.
+ *
+ * @param flags the flags
+ * @return <code>true</code> if the <code>synchronized</code> modifier is included
+ */
+ public static boolean isSynchronized(int flags) {
+ return (flags & IConstants.AccSynchronized) != 0;
+ }
+
+ /**
+ * Returns whether the given integer includes the indication that the
+ * element is synthetic.
+ *
+ * @param flags the flags
+ * @return <code>true</code> if the element is marked synthetic
+ */
+ public static boolean isSynthetic(int flags) {
+ return (flags & IConstants.AccSynthetic) != 0;
+ }
+
+ /**
+ * Returns whether the given integer includes the <code>transient</code> modifier.
+ *
+ * @param flags the flags
+ * @return <code>true</code> if the <code>transient</code> modifier is included
+ */
+ public static boolean isTransient(int flags) {
+ return (flags & IConstants.AccTransient) != 0;
+ }
+
+ /**
+ * Returns whether the given integer includes the <code>volatile</code> modifier.
+ *
+ * @param flags the flags
+ * @return <code>true</code> if the <code>volatile</code> modifier is included
+ */
+ public static boolean isVolatile(int flags) {
+ return (flags & IConstants.AccVolatile) != 0;
+ }
+
+ /**
+ * Returns a standard string describing the given modifier flags.
+ * Only modifier flags are included in the output; the deprecated and
+ * synthetic flags are ignored if set.
+ * <p>
+ * The flags are output in the following order:
+ * <pre>
+ * <code>public</code> <code>protected</code> <code>private</code>
+ * <code>static</code>
+ * <code>abstract</code> <code>final</code> <code>native</code> <code>synchronized</code> <code>transient</code> <code>volatile</code> <code>strictfp</code>
+ * </pre>
+ * This is a compromise between the orders specified in sections 8.1.1,
+ * 8.3.1, 8.4.3, 8.8.3, 9.1.1, and 9.3 of the <em>The Java Language
+ * Specification, Second Edition</em> (JLS2).
+ * </p>
+ * <p>
+ * Examples results:
+ * <pre>
+ * <code>"public static final"</code>
+ * <code>"private native"</code>
+ * </pre>
+ * </p>
+ *
+ * @param flags the flags
+ * @return the standard string representation of the given flags
+ */
+ public static String toString(int flags) {
+ StringBuffer sb = new StringBuffer();
+
+ if (isPublic(flags))
+ sb.append("public ");
+ if (isProtected(flags))
+ sb.append("protected ");
+ if (isPrivate(flags))
+ sb.append("private ");
+ if (isStatic(flags))
+ sb.append("static ");
+ if (isAbstract(flags))
+ sb.append("abstract ");
+ if (isFinal(flags))
+ sb.append("final ");
+ if (isNative(flags))
+ sb.append("native ");
+ if (isSynchronized(flags))
+ sb.append("synchronized ");
+ if (isTransient(flags))
+ sb.append("transient ");
+ if (isVolatile(flags))
+ sb.append("volatile ");
+ if (isStrictfp(flags))
+ sb.append("strictfp ");
+
+ int len = sb.length();
+ if (len == 0)
+ return "";
+ sb.setLength(len - 1);
+ return sb.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IBuffer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IBuffer.java
new file mode 100644
index 0000000000..5bb08875ab
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IBuffer.java
@@ -0,0 +1,220 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * A buffer contains the text contents of a resource. It is not language-specific.
+ * The contents may be in the process of being edited, differing from the actual contents of the
+ * underlying resource. A buffer has an owner, which is an <code>IOpenable</code>.
+ * If a buffer does not have an underlying resource, saving the buffer has no effect.
+ * Buffers can be read-only.
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ */
+public interface IBuffer {
+
+ /**
+ * Adds the given listener for changes to this buffer.
+ * Has no effect if an identical listener is already registered.
+ *
+ * @param listener the listener of buffer changes
+ */
+ public void addBufferChangedListener(IBufferChangedListener listener);
+ /**
+ * Appends the given character array to the contents of the buffer.
+ * This buffer will now have unsaved changes.
+ * Any client can append to the contents of the buffer, not just the owner of the buffer.
+ * Reports a buffer changed event.
+ *
+ * <p>Has no effect if this buffer is read-only.
+ *
+ * @param text the given character array to append to contents of the buffer
+ */
+ public void append(char[] text);
+ /**
+ * Appends the given string to the contents of the buffer.
+ * This buffer will now have unsaved changes.
+ * Any client can append to the contents of the buffer, not just the owner of the buffer.
+ * Reports a buffer changed event.
+ *
+ * <p>Has no effect if this buffer is read-only.
+ *
+ * @param text the <code>String</code> to append to the contents of the buffer
+ */
+ public void append(String text);
+ /**
+ * Closes the buffer. Any unsaved changes are lost. Reports a buffer changed event.
+ * Further operations on the buffer are not allowed, except for close. If an
+ * attempt is made to close an already closed buffer, the second attempt has no effect.
+ */
+ public void close();
+ /**
+ * Returns the character at the given position in this buffer.
+ *
+ * @param position a zero-based source offset in this buffer
+ * @return the character at the given position in this buffer
+ */
+ public char getChar(int position);
+ /**
+ * Returns the contents of this buffer as a character array.
+ * <p>
+ * Callers should make no assumption about whether the returned character array
+ * is or is not the genuine article or a copy. In other words, if the client
+ * wishes to change this array, they should make a copy. Likewise, if the
+ * client wishes to hang on to the array in its current state, they should
+ * make a copy.
+ * </p>
+ *
+ * @return the characters contained in this buffer
+ */
+ public char[] getCharacters();
+ /**
+ * Returns the contents of this buffer as a <code>String</code>. Like all strings,
+ * the result is an immutable value object.
+ *
+ * @return the contents of this buffer as a <code>String</code>
+ */
+ public String getContents();
+ /**
+ * Returns number of characters stored in this buffer.
+ *
+ * @return the number of characters in this buffer
+ */
+ public int getLength();
+ /**
+ * Returns the Java openable element owning of this buffer.
+ *
+ * @return the openable element owning this buffer
+ */
+ public IOpenable getOwner();
+ /**
+ * Returns the given range of text in this buffer.
+ *
+ * @param offset the zero-based starting offset
+ * @param length the number of characters to retrieve
+ * @return the given range of text in this buffer
+ */
+ public String getText(int offset, int length);
+ /**
+ * Returns the underlying resource for which this buffer was opened,
+ * or <code>null</code> if this buffer was not opened on a resource.
+ *
+ * @return the underlying resource for this buffer, or <code>null</code>
+ * if none.
+ */
+ public IResource getUnderlyingResource();
+ /**
+ * Returns whether this buffer has been modified since it
+ * was opened or since it was last saved.
+ * If a buffer does not have an underlying resource, this method always
+ * returns <code>true</code>.
+ *
+ * @return a <code>boolean</code> indicating presence of unsaved changes (in
+ * the absence of any underlying resource, it will always return <code>true</code>).
+ */
+ public boolean hasUnsavedChanges();
+ /**
+ * Returns whether this buffer has been closed.
+ *
+ * @return a <code>boolean</code> indicating whether this buffer is closed.
+ */
+ public boolean isClosed();
+ /**
+ * Returns whether this buffer is read-only.
+ *
+ * @return a <code>boolean</code> indicating whether this buffer is read-only
+ */
+ public boolean isReadOnly();
+ /**
+ * Removes the given listener from this buffer.
+ * Has no affect if an identical listener is not registered.
+ *
+ * @param listener the listener
+ */
+ public void removeBufferChangedListener(IBufferChangedListener listener);
+ /**
+ * Replaces the given range of characters in this buffer with the given text.
+ * <code>position</code> and <code>position + length</code> must be in the range [0, getLength()].
+ * <code>length</code> must not be negative.
+ *
+ * @param position the zero-based starting position of the affected text range in this buffer
+ * @param length the length of the affected text range in this buffer
+ * @param text the replacing text as a character array
+ */
+ public void replace(int position, int length, char[] text);
+ /**
+ * Replaces the given range of characters in this buffer with the given text.
+ * <code>position</code> and <code>position + length</code> must be in the range [0, getLength()].
+ * <code>length</code> must not be negative.
+ *
+ * @param position the zero-based starting position of the affected text range in this buffer
+ * @param length the length of the affected text range in this buffer
+ * @param text the replacing text as a <code>String</code>
+ */
+ public void replace(int position, int length, String text);
+ /**
+ * Saves the contents of this buffer to its underlying resource. If
+ * successful, this buffer will have no unsaved changes.
+ * The buffer is left open. Saving a buffer with no unsaved
+ * changes has no effect - the underlying resource is not changed.
+ * If the buffer does not have an underlying resource or is read-only, this
+ * has no effect.
+ * <p>
+ * The <code>force</code> parameter controls how this method deals with
+ * cases where the workbench is not completely in sync with the local file system.
+ * If <code>false</code> is specified, this method will only attempt
+ * to overwrite a corresponding file in the local file system provided
+ * it is in sync with the workbench. This option ensures there is no
+ * unintended data loss; it is the recommended setting.
+ * However, if <code>true</code> is specified, an attempt will be made
+ * to write a corresponding file in the local file system,
+ * overwriting any existing one if need be.
+ * In either case, if this method succeeds, the resource will be marked
+ * as being local (even if it wasn't before).
+ *
+ * @param monitor the progress monitor to notify
+ * @param force a <code> boolean </code> flag indicating how to deal with resource
+ * inconsistencies.
+ *
+ * @exception JavaModelException if an error occurs writing the buffer
+ * to the underlying resource
+ *
+ * @see org.eclipse.core.resources.IFile#setContents(InputStream, boolean, boolean, IProgressMonitor)
+ */
+ public void save(IProgressMonitor progress, boolean force)
+ throws JavaModelException;
+ /**
+ * Sets the contents of this buffer to the given character array.
+ * This buffer will now have unsaved changes.
+ * Any client can set the contents of the buffer, not just the owner of the buffer.
+ * Reports a buffer changed event.
+ * <p>
+ * Equivalent to <code>replace(0,getLength(),contents)</code>.
+ * </p>
+ *
+ * <p>Has no effect if this buffer is read-only.
+ *
+ * @param contents the new contents of this buffer as a character array
+ */
+ public void setContents(char[] contents);
+ /**
+ * Sets the contents of this buffer to the given <code>String</code>.
+ * This buffer will now have unsaved changes.
+ * Any client can set the contents of the buffer, not just the owner of the buffer.
+ * Reports a buffer changed event.
+ * <p>
+ * Equivalent to <code>replace(0,getLength(),contents)</code>.
+ * </p>
+ *
+ * <p>Has no effect if this buffer is read-only.
+ *
+ * @param contents the new contents of this buffer as a <code>String</code>
+ */
+ public void setContents(String contents);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IBufferChangedListener.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IBufferChangedListener.java
new file mode 100644
index 0000000000..b716d1b2a9
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IBufferChangedListener.java
@@ -0,0 +1,11 @@
+package org.eclipse.jdt.core;
+
+public interface IBufferChangedListener {
+
+ /**
+ * Notifies that the given event has occurred.
+ *
+ * @param event the change event
+ */
+ public void bufferChanged(BufferChangedEvent event);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClassFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClassFile.java
new file mode 100644
index 0000000000..e649ffcea0
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClassFile.java
@@ -0,0 +1,49 @@
+package org.eclipse.jdt.core;
+
+public interface IClassFile
+ extends IJavaElement, IParent, IOpenable, ISourceReference, ICodeAssist {
+ /**
+ * Returns the smallest element within this class file that
+ * includes the given source position (a method, field, etc.), or
+ * <code>null</code> if there is no element other than the class file
+ * itself at the given position, or if the given position is not
+ * within the source range of this class file.
+ *
+ * @param position a source position inside the class file
+ * @return the innermost Java element enclosing a given source position or <code>null</code>
+ * if none (excluding the class file).
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ IJavaElement getElementAt(int position) throws JavaModelException;
+ /**
+ * Returns the type contained in this class file.
+ *
+ * @return the type contained in this class file
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ IType getType() throws JavaModelException;
+ /**
+ * Returns whether this type represents a class. This is not guaranteed to be
+ * instantaneous, as it may require parsing the underlying file.
+ *
+ * @return <code>true</code> if the class file represents a class.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ boolean isClass() throws JavaModelException;
+ /**
+ * Returns whether this type represents an interface. This is not guaranteed to
+ * be instantaneous, as it may require parsing the underlying file.
+ *
+ * @return <code>true</code> if the class file represents an interface.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ boolean isInterface() throws JavaModelException;
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathEntry.java
new file mode 100644
index 0000000000..51847a64c3
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathEntry.java
@@ -0,0 +1,183 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * An entry on a Java project classpath identifying one or more package fragment
+ * roots. A classpath entry has a content kind (either source,
+ * <code>K_SOURCE</code>, or binary, <code>K_BINARY</code>) which is inherited
+ * by each package fragment root and package fragment associated with the entry.
+ * <p>
+ * A classpath entry can refer to any of the following:<ul>
+ * <li>Source code in the current project. In this case, the entry identifies a
+ * root folder in the current project containing package fragments and
+ * <code>.java</code> source files. The root folder itself represents a default
+ * package, subfolders represent package fragments, and <code>.java</code> files
+ * represent compilation units. All compilation units will be compiled when
+ * the project is built. The classpath entry must specify the
+ * absolute path to the root folder. Entries of this kind are
+ * associated with the <code>CPE_SOURCE</code> constant.</li>
+ * <li>A binary library in the current project, in another project, or in the external
+ * file system. In this case the entry identifies a JAR (or root folder) containing
+ * package fragments and <code>.class</code> files. The classpath entry
+ * must specify the absolute path to the JAR (or root folder), and in case it refers
+ * to an external JAR, then there is no associated resource in the workbench. Entries
+ * of this kind are associated with the <code>CPE_LIBRARY</code> constant.</li>
+ * <li>A required project. In this case the entry identifies another project in
+ * the workspace. The required project is used as a binary library when compiling
+ * (that is, the builder looks in the output location of the required project
+ * for required <code>.class</code> files when building). When performing other
+ * "development" operations - such as code assist, code resolve, type hierarchy
+ * creation, etc. - the source code of the project is referred to. Thus, development
+ * is performed against a required project's source code, and compilation is
+ * performed against a required project's last built state. The
+ * classpath entry must specify the absolute path to the
+ * project. Entries of this kind are associated with the <code>CPE_PROJECT</code>
+ * constant. Note: referencing a required project with a classpath entry
+ * only refers to the source code and associated <code>.class</code>
+ * files. It does not include any other libraries or projects that the required
+ * project's classpath refers to. Classpaths are not chained - each project must
+ * specify its own classpath in its entirety.</li>
+ * <li> A path beginning in a classpath variable defined globally to the workspace.
+ * Entries of this kind are associated with the <code>CPE_VARIABLE</code> constant.
+ * These entries are created using <code>JavaCore.setClasspathVariable</code>,
+ * and gets resolved, to either a project or library entry, using
+ * <code>JavaCore.getResolvedClasspathVariable</code>.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * Classpath entries can be created via methods on <code>JavaCore</code>.
+ * </p>
+ *
+ * @see IJavaProject#newLibraryEntry
+ * @see IJavaProject#newProjectEntry
+ * @see IJavaProject#newSourceEntry
+ */
+public interface IClasspathEntry {
+
+ /**
+ * Entry kind constant describing a classpath entry identifying a
+ * library. A library is a folder or JAR containing package
+ * fragments consisting of pre-compiled binaries.
+ */
+ public static final int CPE_LIBRARY = 1;
+
+ /**
+ * Entry kind constant describing a classpath entry identifying a
+ * required project.
+ */
+ public static final int CPE_PROJECT = 2;
+
+ /**
+ * Entry kind constant describing a classpath entry identifying a
+ * folder containing package fragments with source code
+ * to be compiled.
+ */
+ public static final int CPE_SOURCE = 3;
+
+ /**
+ * Entry kind constant describing a classpath entry defined using
+ * a path that begins with a classpath variable reference.
+ */
+ public static final int CPE_VARIABLE = 4;
+
+ /**
+ * Returns the kind of files found in the package fragments identified by this
+ * classpath entry.
+ *
+ * @return <code>IPackageFragmentRoot.K_SOURCE</code> for files containing
+ * source code, and <code>IPackageFragmentRoot.K_BINARY</code> for binary
+ * class files.
+ * There is no specified value for an entry denoting a variable (<code>CPE_VARIABLE</code>)
+ */
+ int getContentKind();
+ /**
+ * Returns the kind of this classpath entry.
+ *
+ * @return one of:
+ * <ul>
+ * <li><code>CPE_SOURCE</code> - this entry describes a source root in
+ its project
+ * <li><code>CPE_LIBRARY</code> - this entry describes a folder or JAR
+ containing binaries
+ * <li><code>CPE_PROJECT</code> - this entry describes another project
+ *
+ * <li><code>CPE_VARIABLE</code> - this entry describes a project or library
+ * indirectly via a classpath variable in the first segment of the path
+ * </ul>
+ */
+ int getEntryKind();
+ /**
+ * Returns the path of this classpath entry.
+ *
+ * The meaning of the path of a classpath entry depends on its entry kind:<ul>
+ * <li>Source code in the current project (<code>CPE_SOURCE</code>) -
+ * The path associated with this entry is the absolute path to the root folder. </li>
+ * <li>A binary library in the current project (<code>CPE_LIBRARY</code>) - the path
+ * associated with this entry is the absolute path to the JAR (or root folder), and
+ * in case it refers to an external JAR, then there is no associated resource in
+ * the workbench.
+ * <li>A required project (<code>CPE_PROJECT</code>) - the path of the entry denotes the
+ * path to the corresponding project resource.</li>
+ * <li>A variable entry (<code>CPE_VARIABLE</code>) - the first segment of the path
+ * is the name of a classpath variable. If this classpath variable
+ * is bound to the path <it>P</it>, the path of the corresponding classpath entry
+ * is computed by appending to <it>P</it> the segments of the returned
+ * path without the variable.</li>
+ * </ul>
+ *
+ * @return the path of this classpath entry
+ */
+ IPath getPath();
+ /**
+ * This is a helper method which returns the resolved classpath entry denoted
+ * by an entry (if it is a variable entry). It is obtained by resolving the variable
+ * reference in the first segment. Returns <node>null</code> if unable to resolve using
+ * the following algorithm:
+ * <ul>
+ * <li> if variable segment cannot be resolved, returns <code>null</code></li>
+ * <li> finds a project, JAR or binary folder in the workspace at the resolved path location</li>
+ * <li> if none finds an external JAR file or folder outside the workspace at the resolved path location </li>
+ * <li> if none returns <code>null</code></li>
+ * </ul>
+ * <p>
+ * Variable source attachment is also resolved and recorded in the resulting classpath entry.
+ * <p>
+ * @return the resolved library or project classpath entry, or <code>null</code>
+ * if the given path could not be resolved to a classpath entry
+ *
+ * @deprecated - use JavaCore.getResolvedClasspathEntry(...)
+ */
+ IClasspathEntry getResolvedEntry();
+ /**
+ * Returns the path to the source archive associated with this
+ * classpath entry, or <code>null</code> if this classpath entry has no
+ * source attachment.
+ * <p>
+ * Only library and variable classpath entries may have source attachments.
+ * For library classpath entries, the result path (if present) locates a source
+ * archive. For variable classpath entries, the result path (if present) has
+ * an analogous form and meaning as the variable path, namely the first segment
+ * is the name of a classpath variable.
+ * </p>
+ *
+ * @return the path to the source archive, or <code>null</code> if none
+ */
+ IPath getSourceAttachmentPath();
+ /**
+ * Returns the path within the source archive where package fragments
+ * are located. An empty path indicates that packages are located at
+ * the root of the source archive. Returns a non-<code>null</code> value
+ * if and only if <code>getSourceAttachmentPath</code> returns
+ * a non-<code>null</code> value.
+ *
+ * @return the path within the source archive, or <code>null</code> if
+ * not applicable
+ */
+ IPath getSourceAttachmentRootPath();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeAssist.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeAssist.java
new file mode 100644
index 0000000000..4b2615b749
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeAssist.java
@@ -0,0 +1,35 @@
+package org.eclipse.jdt.core;
+
+public interface ICodeAssist {
+ /**
+ * Performs code completion at the given offset position in this compilation unit,
+ * reporting results to the given completion requestor. The <code>offset</code>
+ * is the 0-based index of the character, after which code assist is desired.
+ * An <code>offset</code> of -1 indicates to code assist at the beginning of this
+ * compilation unit.
+ *
+ * @exception JavaModelException if code assist could not be performed. Reasons include:<ul>
+ * <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> The position specified is < -1 or is greater than this compilation unit's
+ * source length (INDEX_OUT_OF_BOUNDS)
+ * </ul>
+ *
+ * @exception IllegalArgumentException if <code>requestor</code> is <code>null</code>
+ */
+ void codeComplete(int offset, ICodeCompletionRequestor requestor)
+ throws JavaModelException;
+ /**
+ * Performs code selection on the given selected text in this compilation unit,
+ * reporting results to the given selection requestor. The <code>offset</code>
+ * is the 0-based index of the first selected character. The <code>length</code>
+ * is the number of selected characters.
+ *
+ * @exception JavaModelException if code resolve could not be performed. Reasons include:
+ * <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> The range specified is not within this element's
+ * source range (INDEX_OUT_OF_BOUNDS)
+ * </ul>
+ *
+ */
+ IJavaElement[] codeSelect(int offset, int length) throws JavaModelException;
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeCompletionRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeCompletionRequestor.java
new file mode 100644
index 0000000000..cbb150baf2
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeCompletionRequestor.java
@@ -0,0 +1,263 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.IMarker;
+
+/**
+ * A completion requestor accepts results as they are computed and is aware
+ * of source positions to complete the various different results.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ * @see ICodeAssist
+ */
+public interface ICodeCompletionRequestor {
+ /**
+ * Code assist notification of a class completion.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param packageName char[] - Declaring package name of the class.
+ * @param className char[] - Name of the class.
+ * @param completionName char[] - The completion for the class.
+ * Can include ';' for imported classes.
+ * @param modifiers int - The modifiers of the class.
+ * @param completionStart int - The start position of insertion of the name of the class.
+ * @param completionEnd int - The end position of insertion of the name of the class.
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Nested type names are in the qualified form "A.M".
+ * The default package is represented by an empty array.
+ */
+ void acceptClass(
+ char[] packageName,
+ char[] className,
+ char[] completionName,
+ int modifiers,
+ int completionStart,
+ int completionEnd);
+ /**
+ * Code assist notification of a compilation error detected during completion.
+ *
+ * @return void - Nothing is answered back.
+ *
+ * @param error org.eclipse.core.resources.IMarker
+ * Only problems which are categorized as errors are notified to the requestor,
+ * warnings are silently ignored.
+ * In case an error got signaled, no other completions might be available,
+ * therefore the problem message should be presented to the user.
+ * The source positions of the problem are related to the source where it was
+ * detected (might be in another compilation unit, if it was indirectly requested
+ * during the code assist process).
+ * Note: the problem knows its originating file name.
+ */
+ void acceptError(IMarker marker);
+ /**
+ * Code assist notification of a field completion.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param declaringTypePackageName char[] - Name of the package in which the type that contains this field is declared.
+ * @param declaringTypeName char[] - Name of the type declaring this new field.
+ * @param name char[] - Name of the field.
+ * @param typePackageName char[] - Name of the package in which the type of this field is declared.
+ * @param typeName char[] - Name of the type of this field.
+ * @param completionName char[] - The completion for the field.
+ * @param modifiers int - The modifiers of this field.
+ * @param completionStart int - The start position of insertion of the name of this field.
+ * @param completionEnd int - The end position of insertion of the name of this field.
+ * @see com.ibm.compiler.java.ast.Modifiers
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Base types are in the form "int" or "boolean".
+ * Array types are in the qualified form "M[]" or "int[]".
+ * Nested type names are in the qualified form "A.M".
+ * The default package is represented by an empty array.
+ */
+ void acceptField(
+ char[] declaringTypePackageName,
+ char[] declaringTypeName,
+ char[] name,
+ char[] typePackageName,
+ char[] typeName,
+ char[] completionName,
+ int modifiers,
+ int completionStart,
+ int completionEnd);
+ /**
+ * Code assist notification of an interface completion.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param packageName char[] - Declaring package name of the interface.
+ * @param className char[] - Name of the interface.
+ * @param completionName char[] - The completion for the interface.
+ * Can include ';' for imported interfaces.
+ * @param modifiers int - The modifiers of the interface.
+ * @param completionStart int - The start position of insertion of the name of the interface.
+ * @param completionEnd int - The end position of insertion of the name of the interface.
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Nested type names are in the qualified form "A.M".
+ * The default package is represented by an empty array.
+ */
+ void acceptInterface(
+ char[] packageName,
+ char[] interfaceName,
+ char[] completionName,
+ int modifiers,
+ int completionStart,
+ int completionEnd);
+ /**
+ * Code assist notification of a keyword completion.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param keywordName char[] - The keyword source.
+ * @param completionStart int - The start position of insertion of the name of this keyword.
+ * @param completionEnd int - The end position of insertion of the name of this keyword.
+ */
+ void acceptKeyword(char[] keywordName, int completionStart, int completionEnd);
+ /**
+ * Code assist notification of a label completion.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param labelName char[] - The label source.
+ * @param completionStart int - The start position of insertion of the name of this label.
+ * @param completionEnd int - The end position of insertion of the name of this label.
+ */
+ void acceptLabel(char[] labelName, int completionStart, int completionEnd);
+ /**
+ * Code assist notification of a local variable completion.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param name char[] - Name of the new local variable.
+ * @param typePackageName char[] - Name of the package in which the type of this new local variable is declared.
+ * @param typeName char[] - Name of the type of this new local variable.
+ * @param modifiers int - The modifiers of this new local variable.
+ * @param completionStart int - The start position of insertion of the name of this new local variable.
+ * @param completionEnd int - The end position of insertion of the name of this new local variable.
+ * @see com.ibm.compiler.java.ast.Modifiers
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Base types are in the form "int" or "boolean".
+ * Array types are in the qualified form "M[]" or "int[]".
+ * Nested type names are in the qualified form "A.M".
+ * The default package is represented by an empty array.
+ */
+ void acceptLocalVariable(
+ char[] name,
+ char[] typePackageName,
+ char[] typeName,
+ int modifiers,
+ int completionStart,
+ int completionEnd);
+ /**
+ * Code assist notification of a method completion.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param declaringTypePackageName char[] - Name of the package in which the type that contains this new method is declared.
+ * @param declaringTypeName char[] - Name of the type declaring this new method.
+ * @param selector char[] - Name of the new method.
+ * @param parameterPackageNames char[][] - Names of the packages in which the parameter types are declared.
+ * Should contain as many elements as parameterTypeNames.
+ * @param parameterTypeNames char[][] - Names of the parameters types.
+ * Should contain as many elements as parameterPackageNames.
+ * @param returnTypePackageName char[] - Name of the package in which the return type is declared.
+ * @param returnTypeName char[] - Name of the return type of this new method, should be <code>null</code> for a constructor.
+ * @param completionName char[] - The completion for the method.
+ * Can include zero, one or two brackets. If the closing bracket is included, then the cursor should be placed before it.
+ * @param modifiers int - The modifiers of this new method.
+ * @param completionStart int - The start position of insertion of the name of this new method.
+ * @param completionEnd int - The end position of insertion of the name of this new method.
+ * @see com.ibm.compiler.java.ast.Modifiers
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Base types are in the form "int" or "boolean".
+ * Array types are in the qualified form "M[]" or "int[]".
+ * Nested type names are in the qualified form "A.M".
+ * The default package is represented by an empty array.
+ *
+ * NOTE: parameter names can be retrieved from the source model after the user selects a specific method.
+ */
+ void acceptMethod(
+ char[] declaringTypePackageName,
+ char[] declaringTypeName,
+ char[] selector,
+ char[][] parameterPackageNames,
+ char[][] parameterTypeNames,
+ char[] returnTypePackageName,
+ char[] returnTypeName,
+ char[] completionName,
+ int modifiers,
+ int completionStart,
+ int completionEnd);
+ /**
+ * Code assist notification of a modifier completion.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param modifierName char[] - The new modifier.
+ * @param completionStart int - The start position of insertion of the name of this new modifier.
+ * @param completionEnd int - The end position of insertion of the name of this new modifier.
+ */
+ void acceptModifier(
+ char[] modifierName,
+ int completionStart,
+ int completionEnd);
+ /**
+ * Code assist notification of a package completion.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param packageName char[] - The package name.
+ * @param completionName char[] - The completion for the package.
+ * Can include '.*;' for imports.
+ * @param completionStart int - The start position of insertion of the name of this new package.
+ * @param completionEnd int - The end position of insertion of the name of this new package.
+ *
+ * NOTE - All package names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * The default package is represented by an empty array.
+ */
+ void acceptPackage(
+ char[] packageName,
+ char[] completionName,
+ int completionStart,
+ int completionEnd);
+ /**
+ * Code assist notification of a type completion.
+ *
+ * @return void - Nothing is answered back to code assist engine
+ *
+ * @param packageName char[] - Declaring package name of the type.
+ * @param typeName char[] - Name of the type.
+ * @param completionName char[] - The completion for the type.
+ * Can include ';' for imported types.
+ * @param completionStart int - The start position of insertion of the name of the type.
+ * @param completionEnd int - The end position of insertion of the name of the type.
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ * Package names are in the form "a.b.c".
+ * Nested type names are in the qualified form "A.M".
+ * The default package is represented by an empty array.
+ */
+ void acceptType(
+ char[] packageName,
+ char[] typeName,
+ char[] completionName,
+ int completionStart,
+ int completionEnd);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICompilationUnit.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICompilationUnit.java
new file mode 100644
index 0000000000..59d0537e24
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICompilationUnit.java
@@ -0,0 +1,220 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * Represents an entire Java compilation unit (<code>.java</code> source file).
+ * Compilation unit elements need to be opened before they can be navigated or manipulated.
+ * The children are of type <code>IPackageDeclaration</code>,
+ * <code>IImportContainer</code>, and <code>IType</code>,
+ * and appear in the order in which they are declared in the source.
+ * If a <code>.java</code> file cannot be parsed, its structure remains unknown.
+ * Use <code>IJavaElement.isStructureKnown</code> to determine whether this is
+ * the case.
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ */
+public interface ICompilationUnit
+ extends
+ IJavaElement,
+ ISourceReference,
+ IParent,
+ IOpenable,
+ IWorkingCopy,
+ ISourceManipulation,
+ ICodeAssist {
+ /**
+ * Creates and returns an import declaration in this compilation unit
+ * with the given name.
+ * <p>
+ * Optionally, the new element can be positioned before the specified
+ * sibling. If no sibling is specified, the element will be inserted
+ * as the last import declaration in this compilation unit.
+ * <p>
+ * If the compilation unit already includes the specified import declaration,
+ * the import is not generated (it does not generate duplicates).
+ * Note that it is valid to specify both a single-type import and an on-demand import
+ * for the same package, for example <code>"java.io.File"</code> and
+ * <code>"java.io.*"</code>, in which case both are preserved since the semantics
+ * of this are not the same as just importing <code>"java.io.*"</code>.
+ * Importing <code>"java.lang.*"</code>, or the package in which the compilation unit
+ * is defined, are not treated as special cases. If they are specified, they are
+ * included in the result.
+ *
+ * @param name the name of the import declaration to add as defined by JLS2 7.5. (For example: <code>"java.io.File"</code> or
+ * <code>"java.awt.*"</code>)
+ * @param sibling the existing element which the import declaration will be inserted immediately before (if
+ * <code> null </code>, then this import will be inserted as the last import declaration.
+ * @param monitor the progress monitor to notify
+ * @return the newly inserted import declaration (or the previously existing one in case attempting to create a duplicate)
+ *
+ * @exception JavaModelException if the element could not be created. Reasons include:
+ * <ul>
+ * <li> This Java element does not exist or the specified sibling does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource
+ * <li> The specified sibling is not a child of this compilation unit (INVALID_SIBLING)
+ * <li> The name is not a valid import name (INVALID_NAME)
+ * </ul>
+ */
+ IImportDeclaration createImport(
+ String name,
+ IJavaElement sibling,
+ IProgressMonitor monitor)
+ throws JavaModelException;
+ /**
+ * Creates and returns a package declaration in this compilation unit
+ * with the given package name.
+ *
+ * <p>If the compilation unit already includes the specified package declaration,
+ * it is not generated (it does not generate duplicates).
+ *
+ * @param name the name of the package declaration to add as defined by JLS2 7.4. (For example, <code>"java.lang"</code>)
+ * @param monitor the progress monitor to notify
+ * @return the newly inserted package declaration (or the previously existing one in case attempting to create a duplicate)
+ *
+ * @exception JavaModelException if the element could not be created. Reasons include:
+ * <ul>
+ * <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource
+ * <li> The name is not a valid package name (INVALID_NAME)
+ * </ul>
+ */
+ IPackageDeclaration createPackageDeclaration(
+ String name,
+ IProgressMonitor monitor)
+ throws JavaModelException;
+ /**
+ * Creates and returns a type in this compilation unit with the
+ * given contents. If this compilation unit does not exist, one
+ * will be created with an appropriate package declaration.
+ * <p>
+ * Optionally, the new type can be positioned before the specified
+ * sibling. If <code>sibling</code> is <code>null</code>, the type will be appended
+ * to the end of this compilation unit.
+ *
+ * <p>It is possible that a type with the same name already exists in this compilation unit.
+ * The value of the <code>force</code> parameter effects the resolution of
+ * such a conflict:<ul>
+ * <li> <code>true</code> - in this case the type is created with the new contents</li>
+ * <li> <code>false</code> - in this case a <code>JavaModelException</code> is thrown</li>
+ * </ul>
+ *
+ * @param contents the source contents of the type declaration to add.
+ * @param sibling the existing element which the type will be inserted immediately before (if
+ * <code> null </code>, then this type will be inserted as the last type declaration.
+ * @param force a <code> boolean </code> flag indicating how to deal with duplicates
+ * @param monitor the progress monitor to notify
+ * @return the newly inserted type
+ *
+ * @exception JavaModelException if the element could not be created. Reasons include:
+ * <ul>
+ * <li>The specified sibling element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource
+ * <li> The specified sibling is not a child of this compilation unit (INVALID_SIBLING)
+ * <li> The contents could not be recognized as a type declaration (INVALID_CONTENTS)
+ * <li> There was a naming collision with an existing type (NAME_COLLISION)
+ * </ul>
+ */
+ IType createType(
+ String contents,
+ IJavaElement sibling,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException;
+ /**
+ * Returns all types declared in this compilation unit in the order
+ * in which they appear in the source.
+ * This includes all top-level types and nested member types.
+ * It does NOT include local types (types defined in methods).
+ *
+ * @return the array of toplevel and member types defined in a compilation unit, in declaration order.
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ IType[] getAllTypes() throws JavaModelException;
+ /**
+ * Returns the smallest element within this compilation unit that
+ * includes the given source position (that is, a method, field, etc.), or
+ * <code>null</code> if there is no element other than the compilation
+ * unit itself at the given position, or if the given position is not
+ * within the source range of this compilation unit.
+ *
+ * @param position a source position inside the compilation unit
+ * @return the innermost Java element enclosing a given source position or <code>null</code>
+ * if none (excluding the compilation unit).
+ * @exception JavaModelException if the compilation unit does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ IJavaElement getElementAt(int position) throws JavaModelException;
+ /**
+ * Returns the first import declaration in this compilation unit with the given name.
+ * This is a handle-only method. The import declaration may or may not exist. This
+ * is a convenience method - imports can also be accessed from a compilation unit's
+ * import container.
+ *
+ * @param the name of the import to find as defined by JLS2 7.5. (For example: <code>"java.io.File"</code>
+ * or <code>"java.awt.*"</code>)
+ * @return a handle onto the corresponding import declaration. The import declaration may or may not exist.
+ */
+ IImportDeclaration getImport(String name);
+ /**
+ * Returns the import container for this compilation unit.
+ * This is a handle-only method. The import container may or
+ * may not exist. The import container can used to access the
+ * imports.
+ *
+ * @return a handle onto the corresponding import container. The
+ * import contain may or may not exist.
+ */
+ IImportContainer getImportContainer();
+ /**
+ * Returns the import declarations in this compilation unit
+ * in the order in which they appear in the source. This is
+ * a convenience method - import declarations can also be
+ * accessed from a compilation unit's import container.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ IImportDeclaration[] getImports() throws JavaModelException;
+ /**
+ * Returns the first package declaration in this compilation unit with the given package name
+ * (there normally is at most one package declaration).
+ * This is a handle-only method. The package declaration may or may not exist.
+ *
+ * @param name the name of the package declaration as defined by JLS2 7.4. (For example, <code>"java.lang"</code>)
+ */
+ IPackageDeclaration getPackageDeclaration(String name);
+ /**
+ * Returns the package declarations in this compilation unit
+ * in the order in which they appear in the source.
+ * There normally is at most one package declaration.
+ *
+ * @return an array of package declaration (normally of size one)
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ IPackageDeclaration[] getPackageDeclarations() throws JavaModelException;
+ /**
+ * Returns the top-level type declared in this compilation unit with the given simple type name.
+ * This is a handle-only method. The type may or may not exist.
+ *
+ * @param name the simple name of the requested type in the compilation unit
+ * @return a handle onto the corresponding type. The type may or may not exist.
+ */
+ IType getType(String name);
+ /**
+ * Returns the top-level types declared in this compilation unit
+ * in the order in which they appear in the source.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ IType[] getTypes() throws JavaModelException;
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IElementChangedListener.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IElementChangedListener.java
new file mode 100644
index 0000000000..26c6d3f811
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IElementChangedListener.java
@@ -0,0 +1,12 @@
+package org.eclipse.jdt.core;
+
+public interface IElementChangedListener {
+
+ /**
+ * Notifies that one or more attributes of one or more Java elements have changed.
+ * The specific details of the change are described by the given event.
+ *
+ * @param event the change event
+ */
+ public void elementChanged(ElementChangedEvent event);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IField.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IField.java
new file mode 100644
index 0000000000..bad3043857
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IField.java
@@ -0,0 +1,28 @@
+package org.eclipse.jdt.core;
+
+public interface IField extends IMember {
+ /**
+ * Returns the constant value associated with this field
+ * or <code>null</code> if this field has none.
+ * Returns either a subclass of <code>Number</code>, or a <code>String</code>,
+ * depending on the type of the field.
+ * For example, if the field is of type <code>short</code>, this returns
+ * a <code>Short</code>.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ public Object getConstant() throws JavaModelException;
+ /**
+ * Returns the simple name of this field.
+ */
+ String getElementName();
+ /**
+ * Returns the type signature of this field.
+ *
+ * @see Signature
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ String getTypeSignature() throws JavaModelException;
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IImportContainer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IImportContainer.java
new file mode 100644
index 0000000000..4da2605c74
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IImportContainer.java
@@ -0,0 +1,10 @@
+package org.eclipse.jdt.core;
+
+public interface IImportContainer
+ extends IJavaElement, IParent, ISourceReference {
+ /**
+ * Returns the first import declaration in this import container with the given name.
+ * This is a handle-only method. The import declaration may or may not exist.
+ */
+ IImportDeclaration getImport(String name);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IImportDeclaration.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IImportDeclaration.java
new file mode 100644
index 0000000000..b881952da6
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IImportDeclaration.java
@@ -0,0 +1,19 @@
+package org.eclipse.jdt.core;
+
+public interface IImportDeclaration
+ extends IJavaElement, ISourceReference, ISourceManipulation {
+ /**
+ * Returns the name that has been imported.
+ * For an on-demand import, this includes the trailing <code>".*"</code>.
+ * For example, for the statement <code>"import java.util.*"</code>,
+ * this returns <code>"java.util.*"</code>.
+ * For the statement <code>"import java.util.Hashtable"</code>,
+ * this returns <code>"java.util.Hashtable"</code>.
+ */
+ String getElementName();
+ /**
+ * Returns whether the import is on-demand. An import is on-demand if it ends
+ * with <code>".*"</code>.
+ */
+ boolean isOnDemand();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IInitializer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IInitializer.java
new file mode 100644
index 0000000000..10a8435f70
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IInitializer.java
@@ -0,0 +1,15 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+/**
+ * Represents a stand-alone instance or class (static) initializer in a type.
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ */
+public interface IInitializer extends IMember {
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaElement.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaElement.java
new file mode 100644
index 0000000000..1133cc090d
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaElement.java
@@ -0,0 +1,215 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IAdaptable;
+
+/**
+ * Common protocol for all elements provided by the Java model.
+ * Java model elements are exposed to clients as handles to the actual underlying element.
+ * The Java model may hand out any number of handles for each element. Handles
+ * that refer to the same element are guaranteed to be equal, but not necessarily identical.
+ * <p>
+ * Methods annotated as "handle-only" do not require underlying elements to exist.
+ * Methods that require underlying elements to exist throw
+ * a <code>JavaModelException</code> when an underlying element is missing.
+ * <code>JavaModelException.isDoesNotExist</code> can be used to recognize
+ * this common special case.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ */
+public interface IJavaElement extends IAdaptable {
+
+ /**
+ * Constant representing a Java model (workspace level object).
+ * A Java element with this type can be safely cast to <code>IJavaModel</code>.
+ */
+ public static final int JAVA_MODEL = 1;
+
+ /**
+ * Constant representing a Java project.
+ * A Java element with this type can be safely cast to <code>IJavaProject</code>.
+ */
+ public static final int JAVA_PROJECT = 2;
+
+ /**
+ * Constant representing a package fragment root.
+ * A Java element with this type can be safely cast to <code>IPackageFragmentRoot</code>.
+ */
+ public static final int PACKAGE_FRAGMENT_ROOT = 3;
+
+ /**
+ * Constant representing a package fragment.
+ * A Java element with this type can be safely cast to <code>IPackageFragment</code>.
+ */
+ public static final int PACKAGE_FRAGMENT = 4;
+
+ /**
+ * Constant representing a Java compilation unit.
+ * A Java element with this type can be safely cast to <code>ICompilationUnit</code>.
+ */
+ public static final int COMPILATION_UNIT = 5;
+
+ /**
+ * Constant representing a class file.
+ * A Java element with this type can be safely cast to <code>IClassFile</code>.
+ */
+ public static final int CLASS_FILE = 6;
+
+ /**
+ * Constant representing a type (a class or interface).
+ * A Java element with this type can be safely cast to <code>IType</code>.
+ */
+ public static final int TYPE = 7;
+
+ /**
+ * Constant representing a field.
+ * A Java element with this type can be safely cast to <code>IField</code>.
+ */
+ public static final int FIELD = 8;
+
+ /**
+ * Constant representing a method or constructor.
+ * A Java element with this type can be safely cast to <code>IMethod</code>.
+ */
+ public static final int METHOD = 9;
+
+ /**
+ * Constant representing a stand-alone instance or class initializer.
+ * A Java element with this type can be safely cast to <code>IInitializer</code>.
+ */
+ public static final int INITIALIZER = 10;
+
+ /**
+ * Constant representing a package declaration within a compilation unit.
+ * A Java element with this type can be safely cast to <code>IPackageDeclaration</code>.
+ */
+ public static final int PACKAGE_DECLARATION = 11;
+
+ /**
+ * Constant representing all import declarations within a compilation unit.
+ * A Java element with this type can be safely cast to <code>IImportContainer</code>.
+ */
+ public static final int IMPORT_CONTAINER = 12;
+
+ /**
+ * Constant representing an import declaration within a compilation unit.
+ * A Java element with this type can be safely cast to <code>IImportDeclaration</code>.
+ */
+ public static final int IMPORT_DECLARATION = 13;
+
+ /**
+ * Returns whether this Java element exists in the model.
+ *
+ * @return <code>true</code> if this element exists in the Java model
+ */
+ boolean exists();
+ /**
+ * Returns the resource that corresponds directly to this element,
+ * or <code>null</code> if there is no resource that corresponds to
+ * this element.
+ * <p>
+ * For example, the corresponding resource for an <code>ICompilationUnit</code>
+ * is its underlying <code>IFile</code>. The corresponding resource for
+ * an <code>IPackageFragment</code> that is not contained in an archive
+ * is its underlying <code>IFolder</code>. An <code>IPackageFragment</code>
+ * contained in an archive has no corresponding resource. Similarly, there
+ * are no corresponding resources for <code>IMethods</code>,
+ * <code>IFields</code>, etc.
+ * <p>
+ *
+ * @return the corresponding resource, or <code>null</code> if none
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ IResource getCorrespondingResource() throws JavaModelException;
+ /**
+ * Returns the name of this element. This is a handle-only method.
+ *
+ * @return the element name
+ */
+ String getElementName();
+ /**
+ * Returns this element's kind encoded as an integer.
+ * This is a handle-only method.
+ *
+ * @return the kind of element; one of the constants declared in
+ * <code>IJavaElement</code>
+ * @see IJavaElement
+ */
+ public int getElementType();
+ /**
+ * Returns a string representation of this element handle. The format of
+ * the string is not specified; however, the identifier is stable across
+ * workspace sessions, and can be used to recreate this handle via the
+ * <code>JavaCore.create(String)</code> method.
+ *
+ * @return the string handle identifier
+ * @see JavaCore#create(java.lang.String)
+ */
+ String getHandleIdentifier();
+ /**
+ * Returns the Java model.
+ * This is a handle-only method.
+ *
+ * @return the Java model
+ */
+ IJavaModel getJavaModel();
+ /**
+ * Returns the Java project this element is contained in,
+ * or <code>null</code> if this element is not contained in any Java project
+ * (for instance, the <code>IJavaModel</code> is not contained in any Java
+ * project).
+ * This is a handle-only method.
+ *
+ * @return the containing Java project, or <code>null</code> if this element is
+ * not contained in a Java project
+ */
+ IJavaProject getJavaProject();
+ /**
+ * Returns the element directly containing this element,
+ * or <code>null</code> if this element has no parent.
+ * This is a handle-only method.
+ *
+ * @return the parent element, or <code>null</code> if this element has no parent
+ */
+ IJavaElement getParent();
+ /**
+ * Returns the smallest underlying resource that contains
+ * this element, or <code>null</code> if this element is not contained
+ * in a resource.
+ *
+ * @return the underlying resource, or <code>null</code> if none
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its underlying resource
+ */
+ IResource getUnderlyingResource() throws JavaModelException;
+ /**
+ * Returns whether this Java element is read-only.
+ * This is a handle-only method.
+ *
+ * @return <code>true</code> if this element is read-only
+ */
+ boolean isReadOnly();
+ /**
+ * Returns whether the structure of this element is known. For example, for a
+ * compilation unit that could not be parsed, <code>false</code> is returned.
+ * If the structure of an element is unknown, navigations will return reasonable
+ * defaults. For example, <code>getChildren</code> will return an empty collection.
+ * <p>
+ * Note: This does not imply anything about consistency with the
+ * underlying resource/buffer contents.
+ * </p>
+ *
+ * @return <code>true</code> if the structure of this element is known
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ boolean isStructureKnown() throws JavaModelException;
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaElementDelta.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaElementDelta.java
new file mode 100644
index 0000000000..7f1986235a
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaElementDelta.java
@@ -0,0 +1,231 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.IResourceDelta;
+
+/**
+ * A Java element delta describes changes in Java element between two discrete
+ * points in time. Given a delta, clients can access the element that has
+ * changed, and any children that have changed.
+ * <p>
+ * Deltas have a different status depending on the kind of change they represent.
+ * The list below summarizes each status (as returned by <code>getKind</code>)
+ * and its meaning:
+ * <ul>
+ * <li><code>ADDED</code> - The element described by the delta
+ * has been added. Additional information is specified by
+ * <code>getFlags</code> which returns <code>F_ADDED_TO_CLASSPATH</code>
+ * if the element added is a package fragment root on the classpath.</li>
+ * <li><code>REMOVED</code> - The element described by the delta
+ * has been removed. Additional information is specified by
+ * <code>getFlags</code> which returns <code>F_REMOVED_FROM_CLASSPATH</code>
+ * if the element removed was a package fragment root on the classpath.</li>
+ * <li><code>CHANGED</code> - The element described by the delta
+ * has been changed in some way. Specification of the type of change is provided
+ * by <code>getFlags</code> which returns the following values:
+ * <ul>
+ * <li><code>F_CONTENT</code> - The contents of the element have been altered. This flag
+ * is only valid for elements which correspond to files.</li>
+ * <li><code>F_CHILDREN</code> - A child of the element has changed in some way. This flag
+ * is only valid if the element is an <code>IParent</code>.</li>
+ * <li><code>F_MODIFIERS</code> - the modifiers on the element have changed in some way.
+ * This flag is only valid if the element is an <code>IMember</code>.</li>
+ * <li><code>F_OPENED</code> - the underlying <code>IProject</code>
+ * has been opened. This flag is only valid if the element is an <code>IJavaModel</code>
+ * or an <code>IJavaProject</code>.</li>
+ * <li><code>F_CLOSED</code> - the underlying <code>IProject</code>
+ * has been closed. This flag is only valid if the element is an <code>IJavaModel</code>
+ * or an <code>IJavaProject</code>.</li>
+ * </ul>
+ * </li>
+ * </ul>
+ * </p>
+ * <p>
+ * Move operations are indicated by other change flags, layered on top
+ * of the change flags described above. If element A is moved to become B,
+ * the delta for the change in A will have status <code>REMOVED</code>,
+ * with change flag <code>F_MOVED_TO</code>. In this case,
+ * <code>getMovedToElement</code> on delta A will return the handle for B.
+ * The delta for B will have status <code>ADDED</code>, with change flag
+ * <code>F_MOVED_FROM</code>, and <code>getMovedFromElement</code> on delta
+ * B will return the handle for A. (Note, the handle to A in this case represents
+ * an element that no longer exists).
+ * </p>
+ * <p>
+ * Note that the move change flags only describe the changes to a single element, they
+ * do not imply anything about the parent or children of the element.
+ * </p>
+ * <p>
+ * The following flags describe changes in an <code>IJavaProject</code>'s classpath:
+ * <ul>
+ * <li><code>F_ADDED_TO_CLASSPATH</code> - the element described by the delta has been added to the
+ * classpath.</li>
+ * <li><code>F_REMOVED_FROM_CLASSPATH</code> - the element described by the delta has been removed
+ * from the classpath.</li>
+ * <li><code>F_CLASSPATH_REORDER</code> - the element described by the delta has changed its
+ * position in the classpath.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * <code>IJavaElementDelta</code> object are not valid outside the dynamic scope
+ * of the notification.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ */
+public interface IJavaElementDelta {
+
+ /**
+ * Status constant indicating that the element has been added.
+ */
+ public int ADDED = 1;
+
+ /**
+ * Status constant indicating that the element has been removed.
+ */
+ public int REMOVED = 2;
+
+ /**
+ * Status constant indicating that the element has been changed,
+ * as described by the change flags.
+ */
+ public int CHANGED = 4;
+
+ /**
+ * Change flag indicating that the content of the element has changed.
+ */
+ public int F_CONTENT = 0x0001;
+
+ /**
+ * Change flag indicating that the modifiers of the element have changed.
+ */
+ public int F_MODIFIERS = 0x0002;
+
+ /**
+ * Change flag indicating that there are changes to the children of the element.
+ */
+ public int F_CHILDREN = 0x0008;
+
+ /**
+ * Change flag indicating that the element was moved from another location.
+ * The location of the old element can be retrieved using <code>getMovedFromElement</code>.
+ */
+ public int F_MOVED_FROM = 0x0010;
+
+ /**
+ * Change flag indicating that the element was moved to another location.
+ * The location of the new element can be retrieved using <code>getMovedToElement</code>.
+ */
+ public int F_MOVED_TO = 0x0020;
+
+ /**
+ * Change flag indicating that the element was added to the classpath. In this
+ * case the element is an <code>IPackageFragmentRoot</code>.
+ */
+ public int F_ADDED_TO_CLASSPATH = 0x0040;
+
+ /**
+ * Change flag indicating that the element was removed from the classpath. In this
+ * case the element is an <code>IPackageFragmentRoot</code>.
+ */
+ public int F_REMOVED_FROM_CLASSPATH = 0x0080;
+
+ /**
+ * Change flag indicating that the element's position in the classpath has changed.
+ * In this case the element is an <code>IPackageFragmentRoot</code>.
+ */
+ public int F_CLASSPATH_REORDER = 0x0100;
+
+ /**
+ * Change flag indicating that the underlying <code>IProject</code> has been
+ * opened.
+ */
+ public int F_OPENED = 0x0200;
+
+ /**
+ * Change flag indicating that the underlying <code>IProject</code> has been
+ * closed.
+ */
+ public int F_CLOSED = 0x0400;
+
+ /**
+ * Change flag indicating that one of the supertypes of an <code>IType</code>
+ * has changed.
+ */
+ public int F_SUPER_TYPES = 0x0800;
+
+ /**
+ * Change flag indicating that a source jar has been attached to a binary jar.
+ */
+ public int F_SOURCEATTACHED = 0x1000;
+
+ /**
+ * Change flag indicating that a source jar has been detached to a binary jar.
+ */
+ public int F_SOURCEDETACHED = 0x2000;
+ /**
+ * Returns deltas for the children that have been added.
+ */
+ public IJavaElementDelta[] getAddedChildren();
+ /**
+ * Returns deltas for the affected (added, removed, or changed) children.
+ */
+ public IJavaElementDelta[] getAffectedChildren();
+ /**
+ * Returns deltas for the children which have changed.
+ */
+ public IJavaElementDelta[] getChangedChildren();
+ /**
+ * Returns the element that this delta describes a change to.
+ */
+ public IJavaElement getElement();
+ /**
+ * Returns flags that describe how an element has changed.
+ *
+ * @see IJavaElementDelta#F_CHILDREN
+ * @see IJavaElementDelta#F_CONTENT
+ * @see IJavaElementDelta#F_MODIFIERS
+ * @see IJavaElementDelta#F_MOVED_FROM
+ * @see IJavaElementDelta#F_MOVED_TO
+ * @see IJavaElementDelta#F_ADDED_TO_CLASSPATH
+ * @see IJavaElementDelta#F_REMOVED_FROM_CLASSPATH
+ * @see IJavaElementDelta#F_CLASSPATH_REORDER
+ */
+ public int getFlags();
+ /**
+ * Returns the kind of this delta - one of <code>ADDED</code>, <code>REMOVED</code>,
+ * or <code>CHANGED</code>.
+ */
+ public int getKind();
+ /**
+ * Returns an element describing this element before it was moved
+ * to its current location, or <code>null</code> if the
+ * <code>F_MOVED_FROM</code> change flag is not set.
+ */
+ public IJavaElement getMovedFromElement();
+ /**
+ * Returns an element describing this element in its new location,
+ * or <code>null</code> if the <code>F_MOVED_TO</code> change
+ * flag is not set.
+ */
+ public IJavaElement getMovedToElement();
+ /**
+ * Returns deltas for the children which have been removed.
+ */
+ public IJavaElementDelta[] getRemovedChildren();
+ /**
+ * Returns the collection of resource deltas.
+ * <p>
+ * Note that resource deltas, like Java element deltas, are generally only valid
+ * for the dynamic scope of an event notification. Clients must not hang on to
+ * these objects.
+ * </p>
+ *
+ * @return the underlying resource deltas, or <code>null</code> if none
+ */
+ public IResourceDelta[] getResourceDeltas();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModel.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModel.java
new file mode 100644
index 0000000000..0725beb7f6
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModel.java
@@ -0,0 +1,200 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * Represent the root Java element corresponding to the workspace.
+ * Since there is only one such root element, it is commonly referred to as
+ * <em>the</em> Java model element.
+ * The Java model element needs to be opened before it can be navigated or manipulated.
+ * The Java model element has no parent (it is the root of the Java element
+ * hierarchy). Its children are <code>IJavaProject</code>s.
+ * <p>
+ * This interface provides methods for performing copy, move, rename, and
+ * delete operations on multiple Java elements.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients. An instance
+ * of one of these handles can be created via
+ * <code>JavaCore.create(workspace.getRoot())</code>.
+ * </p>
+ *
+ * @see JavaCore#create(org.eclipse.core.resources.IWorkspaceRoot)
+ */
+public interface IJavaModel extends IJavaElement, IOpenable, IParent {
+ /**
+ * Copies the given elements to the specified container(s).
+ * If one container is specified, all elements are copied to that
+ * container. If more than one container is specified, the number of
+ * elements and containers must match, and each element is copied to
+ * its associated container.
+ * <p>
+ * Optionally, each copy can positioned before a sibling
+ * element. If <code>null</code> is specified for a given sibling, the copy
+ * is inserted as the last child of its associated container.
+ * </p>
+ * <p>
+ * Optionally, each copy can be renamed. If
+ * <code>null</code> is specified for the new name, the copy
+ * is not renamed.
+ * </p>
+ * <p>
+ * Optionally, any existing child in the destination container with
+ * the same name can be replaced by specifying <code>true</code> for
+ * force. Otherwise an exception is thrown in the event that a name
+ * collision occurs.
+ * </p>
+ *
+ * @param elements the elements to copy
+ * @param containers the container, or list of containers
+ * @param siblings the list of siblings element any of which may be
+ * <code>null</code>; or <code>null</code>
+ * @param renamings the list of new names any of which may be
+ * <code>null</code>; or <code>null</code>
+ * @param replace <code>true</code> if any existing child in a target container
+ * with the target name should be replaced, and <code>false</code> to throw an
+ * exception in the event of a name collision
+ * @param monitor a progress monitor
+ * @exception JavaModelException if an element could not be copied. Reasons include:
+ * <ul>
+ * <li> A specified element, container, or sibling does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource
+ * <li> A container is of an incompatible type (<code>INVALID_DESTINATION</code>)
+ * <li> A sibling is not a child of it associated container (<code>INVALID_SIBLING</code>)
+ * <li> A new name is invalid (<code>INVALID_NAME</code>)
+ * <li> A child in its associated container already exists with the same
+ * name and <code>replace</code> has been specified as <code>false</code> (<code>NAME_COLLISION</code>)
+ * <li> A container or element is read-only (<code>READ_ONLY</code>)
+ * </ul>
+ */
+ void copy(
+ IJavaElement[] elements,
+ IJavaElement[] containers,
+ IJavaElement[] siblings,
+ String[] renamings,
+ boolean replace,
+ IProgressMonitor monitor)
+ throws JavaModelException;
+ /**
+ * Deletes the given elements, forcing the operation if necessary and specified.
+ *
+ * @param elements the elements to delete
+ * @param force a flag controlling whether underlying resources that are not
+ * in sync with the local file system will be tolerated
+ * @param monitor a progress monitor
+ * @exception JavaModelException if an element could not be deleted. Reasons include:
+ * <ul>
+ * <li> A specified element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource
+ * <li> An element is read-only (<code>READ_ONLY</code>)
+ * </ul>
+ */
+ void delete(IJavaElement[] elements, boolean force, IProgressMonitor monitor)
+ throws JavaModelException;
+ /**
+ * Returns the Java project with the given name. This is a handle-only method.
+ * The project may or may not exist.
+ */
+ IJavaProject getJavaProject(String name);
+ /**
+ * Returns the Java projects in this Java model, or an empty array if there
+ * are none.
+ *
+ * @exception JavaModelException if this request fails.
+ */
+ IJavaProject[] getJavaProjects() throws JavaModelException;
+ /**
+ * Returns the workspace associated with this Java model.
+ */
+ IWorkspace getWorkspace();
+ /**
+ * Moves the given elements to the specified container(s).
+ * If one container is specified, all elements are moved to that
+ * container. If more than one container is specified, the number of
+ * elements and containers must match, and each element is moved to
+ * its associated container.
+ * <p>
+ * Optionally, each element can positioned before a sibling
+ * element. If <code>null</code> is specified for sibling, the element
+ * is inserted as the last child of its associated container.
+ * </p>
+ * <p>
+ * Optionally, each element can be renamed. If
+ * <code>null</code> is specified for the new name, the element
+ * is not renamed.
+ * </p>
+ * <p>
+ * Optionally, any existing child in the destination container with
+ * the same name can be replaced by specifying <code>true</code> for
+ * force. Otherwise an exception is thrown in the event that a name
+ * collision occurs.
+ * </p>
+ *
+ * @param elements the elements to move
+ * @param containers the container, or list of containers
+ * @param siblings the list of siblings element any of which may be
+ * <code>null</code>; or <code>null</code>
+ * @param renamings the list of new names any of which may be
+ * <code>null</code>; or <code>null</code>
+ * @param replace <code>true</code> if any existing child in a target container
+ * with the target name should be replaced, and <code>false</code> to throw an
+ * exception in the event of a name collision
+ * @param monitor a progress monitor
+ * @exception JavaModelException if an element could not be moved. Reasons include:
+ * <ul>
+ * <li> A specified element, container, or sibling does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource
+ * <li> A container is of an incompatible type (<code>INVALID_DESTINATION</code>)
+ * <li> A sibling is not a child of it associated container (<code>INVALID_SIBLING</code>)
+ * <li> A new name is invalid (<code>INVALID_NAME</code>)
+ * <li> A child in its associated container already exists with the same
+ * name and <code>replace</code> has been specified as <code>false</code> (<code>NAME_COLLISION</code>)
+ * <li> A container or element is read-only (<code>READ_ONLY</code>)
+ * </ul>
+ *
+ * @exception IllegalArgumentException any element or container is <code>null</code>
+ */
+ void move(
+ IJavaElement[] elements,
+ IJavaElement[] containers,
+ IJavaElement[] siblings,
+ String[] renamings,
+ boolean replace,
+ IProgressMonitor monitor)
+ throws JavaModelException;
+ /**
+ * Renames the given elements as specified.
+ * If one container is specified, all elements are renamed within that
+ * container. If more than one container is specified, the number of
+ * elements and containers must match, and each element is renamed within
+ * its associated container.
+ *
+ * @param elements the elements to rename
+ * @param destinations the container, or list of containers
+ * @param names the list of new names
+ * @param replace <code>true</code> if an existing child in a target container
+ * with the target name should be replaced, and <code>false</code> to throw an
+ * exception in the event of a name collision
+ * @param monitor a progress monitor
+ * @exception JavaModelException if an element could not be renamed. Reasons include:
+ * <ul>
+ * <li> A specified element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource
+ * <li> A new name is invalid (<code>INVALID_NAME</code>)
+ * <li> A child already exists with the same name and <code>replace</code> has been specified as <code>false</code> (<code>NAME_COLLISION</code>)
+ * <li> An element is read-only (<code>READ_ONLY</code>)
+ * </ul>
+ */
+ void rename(
+ IJavaElement[] elements,
+ IJavaElement[] destinations,
+ String[] names,
+ boolean replace,
+ IProgressMonitor monitor)
+ throws JavaModelException;
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelMarker.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelMarker.java
new file mode 100644
index 0000000000..927dc7becb
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelMarker.java
@@ -0,0 +1,41 @@
+package org.eclipse.jdt.core;
+
+public interface IJavaModelMarker {
+
+ /**
+ * Java model problem marker type (value <code>"org.eclipse.jdt.core.problem"</code>).
+ * This can be used to recognize those markers in the workspace that flag problems
+ * detected by the Java tooling during compilation.
+ */
+ public static final String JAVA_MODEL_PROBLEM_MARKER =
+ JavaCore.PLUGIN_ID + ".problem";
+
+ /**
+ * Java model transient problem marker type (value <code>"org.eclipse.jdt.core.transient_problem"</code>).
+ * This can be used to recognize those markers in the workspace that flag transcient
+ * problems detected by the Java tooling (such as a cycle in the build path, a problem
+ * detected by the outliner, or a problem detected during a code completion)
+ */
+ public static final String TRANSIENT_PROBLEM =
+ JavaCore.PLUGIN_ID + ".transient_problem";
+
+ /**
+ * Id marker attribute (value <code>"id"</code>).
+ * Reserved for future use.
+ */
+ public static final String ID = "id";
+
+ /**
+ * Flags marker attribute (value <code>"flags"</code>).
+ * Reserved for future use.
+ */
+ public static final String FLAGS = "flags";
+
+ /**
+ * Cycle detected marker attribute (value <code>"cycleDetected"</code>).
+ * Used only on transient problem markers.
+ * The value of this attribute is the name of the project that caused a
+ * cycle in the projects classpaths.
+ */
+ public static final String CYCLE_DETECTED = "cycleDetected";
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatus.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatus.java
new file mode 100644
index 0000000000..898ef0e6c2
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatus.java
@@ -0,0 +1,76 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+
+/**
+ * Represents the outcome of an Java model operation. Status objects are
+ * used inside <code>JavaModelException</code> objects to indicate what went
+ * wrong.
+ * <p>
+ * Java model status object are distinguished by their plug-in id:
+ * <code>getPlugin</code> returns <code>"org.eclipse.jdt.core"</code>.
+ * <code>getCode</code> returns one of the status codes declared in
+ * <code>IJavaModelStatusConstants</code>.
+ * </p>
+ * <p>
+ * A Java model status may also carry additional information (that is, in
+ * addition to the information defined in <code>IStatus</code>):
+ * <ul>
+ * <li>elements - optional handles to Java elements associated with the failure</li>
+ * <li>string - optional string associated with the failure</li>
+ * </ul>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @see org.eclipse.core.runtime.IStatus
+ * @see IJavaModelStatusConstants
+ */
+public interface IJavaModelStatus extends IStatus {
+ /**
+ * Returns any Java elements associated with the failure (see specification
+ * of the status code), or an empty array if no elements are related to this
+ * particular status code.
+ *
+ * @return the list of Java element culprits
+ * @see IJavaModelStatusConstants
+ */
+ IJavaElement[] getElements();
+ /**
+ * Returns the path associated with the failure (see specification
+ * of the status code), or <code>null</code> if the failure is not
+ * one of <code>DEVICE_PATH</code>, <code>INVALID_PATH</code>,
+ * <code>PATH_OUTSIDE_PROJECT</code>, or <code>RELATIVE_PATH</code>.
+ *
+ * @return the path that caused the failure, or <code>null</code> if none
+ * @see IJavaModelStatusConstants#DEVICE_PATH
+ * @see IJavaModelStatusConstants#INVALID_PATH
+ * @see IJavaModelStatusConstants#PATH_OUTSIDE_PROJECT
+ * @see IJavaModelStatusConstants#RELATIVE_PATH
+ */
+ IPath getPath();
+ /**
+ * Returns the string associated with the failure (see specification
+ * of the status code), or <code>null</code> if no string is related to this
+ * particular status code.
+ *
+ * @return the string culprit, or <code>null</code> if none
+ * @see IJavaModelStatusConstants
+ */
+ String getString();
+ /**
+ * Returns whether this status indicates that a Java model element does not exist.
+ * This convenience method is equivalent to
+ * <code>getCode() == IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST</code>.
+ *
+ * @return <code>true</code> if the status code indicates that a Java model
+ * element does not exist
+ * @see IJavaModelStatusConstants#ELEMENT_DOES_NOT_EXIST
+ */
+ boolean isDoesNotExist();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java
new file mode 100644
index 0000000000..2ca618de78
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java
@@ -0,0 +1,211 @@
+package org.eclipse.jdt.core;
+
+public interface IJavaModelStatusConstants {
+
+ /**
+ * Status constant indicating that a variable path was not resolvable
+ * indicating either the referred variable is undefined, unbound or the resolved
+ * variable path does not correspond to an existing file or folder.
+ */
+ public static final int CP_VARIABLE_PATH_UNBOUND = 965;
+
+ /**
+ * Status constant indicating a core exception occurred.
+ * Use <code>getException</code> to retrieve a <code>CoreException</code>.
+ */
+ public static final int CORE_EXCEPTION = 966;
+
+ /**
+ * Status constant indicating one or more of the elements
+ * supplied are not of a valid type for the operation to
+ * process.
+ * The element(s) can be retrieved using <code>getElements</code> on the status object.
+ */
+ public static final int INVALID_ELEMENT_TYPES = 967;
+
+ /**
+ * Status constant indicating that no elements were
+ * provided to the operation for processing.
+ */
+ public static final int NO_ELEMENTS_TO_PROCESS = 968;
+
+ /**
+ * Status constant indicating that one or more elements
+ * supplied do not exist.
+ * The element(s) can be retrieved using <code>getElements</code> on the status object.
+ *
+ * @see IJavaModelStatus#isDoesNotExist
+ */
+ public static final int ELEMENT_DOES_NOT_EXIST = 969;
+
+ /**
+ * Status constant indicating that a <code>null</code> path was
+ * supplied to the operation.
+ */
+ public static final int NULL_PATH = 970;
+
+ /**
+ * Status constant indicating that a path outside of the
+ * project was supplied to the operation. The path can be retrieved using
+ * <code>getPath</code> on the status object.
+ */
+ public static final int PATH_OUTSIDE_PROJECT = 971;
+
+ /**
+ * Status constant indicating that a relative path
+ * was supplied to the operation when an absolute path is
+ * required. The path can be retrieved using <code>getPath</code> on the
+ * status object.
+ */
+ public static final int RELATIVE_PATH = 972;
+
+ /**
+ * Status constant indicating that a path specifying a device
+ * was supplied to the operation when a path with no device is
+ * required. The path can be retrieved using <code>getPath</code> on the
+ * status object.
+ */
+ public static final int DEVICE_PATH = 973;
+
+ /**
+ * Status constant indicating that a string
+ * was supplied to the operation that was <code>null</code>.
+ */
+ public static final int NULL_STRING = 974;
+
+ /**
+ * Status constant indicating that the operation encountered
+ * a read-only element.
+ * The element(s) can be retrieved using <code>getElements</code> on the status object.
+ */
+ public static final int READ_ONLY = 976;
+
+ /**
+ * Status constant indicating that a naming collision would occur
+ * if the operation proceeded.
+ */
+ public static final int NAME_COLLISION = 977;
+
+ /**
+ * Status constant indicating that a destination provided for a copy/move/rename operation
+ * is invalid.
+ * The destination element can be retrieved using <code>getElements</code> on the status object.
+ */
+ public static final int INVALID_DESTINATION = 978;
+
+ /**
+ * Status constant indicating that a path provided to an operation
+ * is invalid. The path can be retrieved using <code>getPath</code> on the
+ * status object.
+ */
+ public static final int INVALID_PATH = 979;
+
+ /**
+ * Status constant indicating the given source position is out of bounds.
+ */
+ public static final int INDEX_OUT_OF_BOUNDS = 980;
+
+ /**
+ * Status constant indicating there is an update conflict
+ * for a working copy. The compilation unit on which the
+ * working copy is based has changed since the working copy
+ * was created.
+ */
+ public static final int UPDATE_CONFLICT = 981;
+
+ /**
+ * Status constant indicating that <code>null</code> was specified
+ * as a name argument.
+ */
+ public static final int NULL_NAME = 982;
+
+ /**
+ * Status constant indicating that a name provided is not syntactically correct.
+ * The name can be retrieved from <code>getString</code>.
+ */
+ public static final int INVALID_NAME = 983;
+
+ /**
+ * Status constant indicating that the specified contents
+ * are not valid.
+ */
+ public static final int INVALID_CONTENTS = 984;
+
+ /**
+ * Status constant indicating that an <code>java.io.IOException</code>
+ * occurred.
+ */
+ public static final int IO_EXCEPTION = 985;
+
+ /**
+ * Status constant indicating that a <code>DOMException</code>
+ * occurred.
+ */
+ public static final int DOM_EXCEPTION = 986;
+
+ /**
+ * Status constant indicating that a <code>TargetException</code>
+ * occurred.
+ */
+ public static final int TARGET_EXCEPTION = 987;
+
+ /**
+ * Status constant indicating that the Java builder
+ * could not be initialized.
+ */
+ public static final int BUILDER_INITIALIZATION_ERROR = 990;
+
+ /**
+ * Status constant indicating that the Java builder's last built state
+ * could not be serialized or deserialized.
+ */
+ public static final int BUILDER_SERIALIZATION_ERROR = 991;
+
+ /**
+ * Status constant indicating that an error was encountered while
+ * trying to evaluate a code snippet, or other item.
+ */
+ public static final int EVALUATION_ERROR = 992;
+
+ /**
+ * Status constant indicating that a sibling specified is not valid.
+ */
+ public static final int INVALID_SIBLING = 993;
+
+ /**
+ * Status indicating that a Java element could not be created because
+ * the underlying resource is invalid.
+ * @see JavaCore
+ */
+ public static final int INVALID_RESOURCE = 995;
+
+ /**
+ * Status indicating that a Java element could not be created because
+ * the underlying resource is not of an appropriate type.
+ * @see JavaCore
+ */
+ public static final int INVALID_RESOURCE_TYPE = 996;
+
+ /**
+ * Status indicating that a Java element could not be created because
+ * the project owning underlying resource does not have the Java nature.
+ * @see JavaCore
+ */
+ public static final int INVALID_PROJECT = 997;
+
+ /**
+ * Status indicating that the package declaration in a <code>ICompilationUnit</code>
+ * does not correspond to the <code>IPackageFragment</code> it belongs to.
+ * The <code>getString</code> method of the associated status object
+ * gives the name of the package in which the <code>ICompilationUnit</code> is
+ * declared.
+ */
+ public static final int INVALID_PACKAGE = 998;
+
+ /**
+ * Status indicating that the corresponding resource has no local contents yet.
+ * This might happen when attempting to use a resource before its contents
+ * has been made locally available.
+ */
+ public static final int NO_LOCAL_CONTENTS = 999;
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaProject.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaProject.java
new file mode 100644
index 0000000000..d69b0a3fe0
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaProject.java
@@ -0,0 +1,371 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IPath;
+
+import org.eclipse.jdt.core.eval.IEvaluationContext;
+
+/**
+ * A Java project represents a view of a project resource in terms of Java
+ * elements such as package fragments, types, methods and fields.
+ * A project may contain several package roots, which contain package fragments.
+ * A package root corresponds to an underlying folder or JAR.
+ * <p>
+ * Each Java project has a classpath, defining which folders contain source code and
+ * where required libraries are located. Each Java project also has an output location,
+ * defining where the builder writes <code>.class</code> files. A project that
+ * references packages in another project can access the packages by including
+ * the required project in a classpath entry. The Java model will present the
+ * source elements in the required project, and when building, the compiler will
+ * use the binaries from that project (that is, the output location of the
+ * required project is used as a library). The classpath format is a sequence
+ * of classpath entries describing the location and contents of package fragment
+ * roots.
+ * </p>
+ * Java project elements need to be opened before they can be navigated or manipulated.
+ * The children of a Java project are the package fragment roots that are
+ * defined by the classpath and contained in this project (in other words, it
+ * does not include package fragment roots for other projects).
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients. An instance
+ * of one of these handles can be created via
+ * <code>JavaCore.create(project)</code>.
+ * </p>
+ *
+ * @see JavaCore#create(org.eclipse.core.resources.IProject)
+ * @see IClasspathEntry
+ */
+public interface IJavaProject extends IParent, IJavaElement, IOpenable {
+
+ /**
+ * Returns the <code>IJavaElement</code> corresponding to the given
+ * classpath-relative path, or <code>null</code> if no such
+ * <code>IJavaElement</code> is found. The result is one of an
+ * <code>ICompilationUnit</code>, <code>IClassFile</code>, or
+ * <code>IPackageFragment</code>.
+ *
+ * <p>For example, the path "java/lang/Object.java", would result in the
+ * <code>ICompilationUnit</code> or <code>IClassFile</code> corresponding to
+ * "java.lang.Object". The path "java/lang" would result in the
+ * <code>IPackageFragment</code> for "java.lang".
+ *
+ * @exception JavaModelException if the given path is <code>null</code>
+ * or absolute
+ */
+ IJavaElement findElement(IPath path) throws JavaModelException;
+ /**
+ * Returns the first existing package fragment on this project's classpath
+ * whose path matches the given (absolute) path, or <code>null</code> if none
+ * exist.
+ * The path can be:
+ * - internal to the workbench: "/Project/src"
+ * - external to the workbench: "c:/jdk/classes.zip/java/lang"
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ IPackageFragment findPackageFragment(IPath path) throws JavaModelException;
+ /**
+ * Returns the existing package fragment root on this project's classpath
+ * whose path matches the given (absolute) path, or <code>null</code> if
+ * one does not exist.
+ * The path can be:
+ * - internal to the workbench: "/Compiler/src"
+ * - external to the workbench: "c:/jdk/classes.zip"
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ IPackageFragmentRoot findPackageFragmentRoot(IPath path)
+ throws JavaModelException;
+ /**
+ * Returns all of the existing package fragment roots that exist
+ * on the classpath, in the order they are defined by the classpath.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ IPackageFragmentRoot[] getAllPackageFragmentRoots() throws JavaModelException;
+ /**
+ * Returns the classpath for the project, as a list of classpath
+ * entries.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ *
+ * @deprecated - since classpath variable support was added either use #getRawClasspath or #getResolvedClasspath
+ */
+ IClasspathEntry[] getClasspath() throws JavaModelException;
+ /**
+ * Returns an array of non-Java resources directly contained in this project.
+ * It does not transitively answer non-Java resources contained in folders;
+ * these would have to be explicitly iterated over.
+ */
+ Object[] getNonJavaResources() throws JavaModelException;
+ /**
+ * Returns the full path to the location where the builder writes
+ * <code>.class</code> files.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ IPath getOutputLocation() throws JavaModelException;
+ /**
+ * Returns a package fragment root for the JAR at the specified file system path.
+ * This is a handle-only method. The underlying <code>java.io.File</code>
+ * may or may not exist. No resource is associated with this local JAR
+ * package fragment root.
+ */
+ IPackageFragmentRoot getPackageFragmentRoot(String jarPath);
+ /**
+ * Returns a package fragment root for the given resource, which
+ * must either be a folder representing the top of a package hierarchy,
+ * or a <code>.jar</code> or <code>.zip</code> file.
+ * This is a handle-only method. The underlying resource may or may not exist.
+ */
+ IPackageFragmentRoot getPackageFragmentRoot(IResource resource);
+ /**
+ * Returns all of the package fragment roots contained in this
+ * project, identified on this project's resolved classpath. The result
+ * does not include package fragment roots in other projects referenced
+ * on this project's classpath.
+ *
+ * <p>NOTE: This is equivalent to <code>getChildren()</code>.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ IPackageFragmentRoot[] getPackageFragmentRoots() throws JavaModelException;
+ /**
+ * Returns the existing package fragment roots identified by the given entry.
+ * Note that a classpath entry that refers to another project may
+ * have more than one root (if that project has more than on root
+ * containing source), and classpath entries within the current
+ * project identify a single root.
+ *
+ * If the classpath entry denotes a variable, it will be resolved and returning
+ * the roots of the target entry (empty if not resolvable).
+ */
+ IPackageFragmentRoot[] getPackageFragmentRoots(IClasspathEntry entry);
+ /**
+ * Returns all package fragments in all package fragment roots contained
+ * in this project. This is a convenience method.
+ *
+ * Note that the package fragment roots corresponds to the resolved
+ * classpath of the project.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ IPackageFragment[] getPackageFragments() throws JavaModelException;
+ /**
+ * Returns the <code>IProject</code> on which this <code>IJavaProject</code>
+ * was created. This is handle-only method.
+ */
+ IProject getProject();
+ /**
+ * Returns the raw classpath for the project, as a list of classpath entries. This corresponds to the exact set
+ * of entries which were assigned using <code>setRawClasspath</code>, in particular such a classpath may contain
+ * classpath variable entries. Classpath variable entries can be resolved individually (see <code>JavaCore#getClasspathVariable</code>),
+ * or the full classpath can be resolved at once using the helper method <code>getResolvedClasspath</code>.
+ * <p>
+ * A classpath variable provides an indirection level for better sharing a classpath. As an example, it allows
+ * a classpath to no longer refer directly to external JARs located in some user specific location. The classpath
+ * can simply refer to some variables defining the proper locations of these external JARs.
+ * <p>
+ * @exception JavaModelException in one of the corresponding situation:
+ * <ul>
+ * <li> this element does not exist </li>
+ * <li> an exception occurs while accessing its corresponding resource </li>
+ * </ul>
+ * @see IClasspathEntry
+ */
+ IClasspathEntry[] getRawClasspath() throws JavaModelException;
+ /**
+ * Returns the names of the projects that are directly required by this
+ * project. A project is required if it is in its classpath.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ String[] getRequiredProjectNames() throws JavaModelException;
+ /**
+ * This is a helper method returning the resolved classpath for the project, as a list of classpath entries,
+ * where all classpath variable entries have been resolved and substituted with their final target entries.
+ * <p>
+ * A resolved classpath corresponds to a particular instance of the raw classpath bound in the context of
+ * the current values of the referred variables, and thus should not be persisted.
+ * <p>
+ * A classpath variable provides an indirection level for better sharing a classpath. As an example, it allows
+ * a classpath to no longer refer directly to external JARs located in some user specific location. The classpath
+ * can simply refer to some variables defining the proper locations of these external JARs.
+ * <p>
+ * The boolean argument <code>ignoreUnresolvedVariable</code> allows to specify how to handle unresolvable variables,
+ * when set to <code>true</code>, missing variables are simply ignored, the resulting path is then only formed of the
+ * resolvable entries, without any indication about which variable(s) was ignored. When set to <code>false</code>, a
+ * JavaModelException will be thrown for the first unresolved variable (from left to right).
+ *
+ * @exception JavaModelException in one of the corresponding situation:
+ * <ul>
+ * <li> this element does not exist </li>
+ * <li> an exception occurs while accessing its corresponding resource </li>
+ * <li> a classpath variable was not resolvable and <code>ignoreUnresolvedVariable</code> was set to <code>false</code>. </li>
+ * </ul>
+ * @see IClasspathEntry
+ */
+ IClasspathEntry[] getResolvedClasspath(boolean ignoreUnresolvedVariable)
+ throws JavaModelException;
+ /**
+ * Returns whether this project has been built at least once and thus whether it has a build state.
+ */
+ public boolean hasBuildState();
+ /**
+ * Returns whether setting this projec's classpath to the given classpath entries
+ * would result in a cycle.
+ *
+ * If the set of entries contains some variables, these are resolved in order to determine
+ * cycles.
+ */
+ public boolean hasClasspathCycle(IClasspathEntry[] entries);
+ /**
+ * Creates a new evaluation context.
+ */
+ IEvaluationContext newEvaluationContext();
+ /**
+ * Creates and returns a new classpath entry of kind <code>K_BINARY</code> for the JAR
+ * or folder identified by the given absolute path. This specifies that
+ * all package fragments within the root will have children of type
+ * <code>IClassFile</code>.
+ * The path can be:
+ * - internal to the workbench: "/Project/binary"
+ * - external to the workbench: "c:/jdk/classes.zip"
+ *
+ * @deprecated - use JavaCore#newLibraryEntry
+ */
+ public IClasspathEntry newLibraryEntry(IPath path);
+ /**
+ * Creates and returns a new classpath entry of kind <code>K_SOURCE</code>
+ * for the project identified by the given absolute path. This
+ * identifies all the source code of the given project to be
+ * used in the Java model, and the output location of the project
+ * to be used when building.
+ * The path can be:
+ * - internal to the workbench: "/Project/binary"
+ * - external to the workbench: "c:/jdk/classes.zip"
+ *
+ * @deprecated - use JavaCore#newProjectEntry
+ */
+ public IClasspathEntry newProjectEntry(IPath path);
+ /**
+ * Creates and returns a new classpath entry of kind <code>K_SOURCE</code>
+ * for folder identified by the given absolute path. This specifies that
+ * all package fragments within the root will have children of type
+ * <code>ICompilationUnit</code>.
+ * The path can be:
+ * - internal to the workbench: "/Project/binary"
+ * - external to the workbench: "c:/jdk/classes.zip"
+ *
+ * @deprecated - use JavaCore#newSourceEntry
+ */
+ public IClasspathEntry newSourceEntry(IPath path);
+ /**
+ * Creates and returns a type hierarchy for all types in the given
+ * region, considering subtypes within that region.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ *
+ * @exception IllegalArgumentException if region is <code>null</code>
+ */
+ ITypeHierarchy newTypeHierarchy(IRegion region, IProgressMonitor monitor)
+ throws JavaModelException;
+ /**
+ * Creates and returns a type hierarchy for the given type considering
+ * subtypes in the specified region.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ *
+ * @exception IllegalArgumentException if type or region is <code>null</code>
+ */
+ ITypeHierarchy newTypeHierarchy(
+ IType type,
+ IRegion region,
+ IProgressMonitor monitor)
+ throws JavaModelException;
+ /**
+ * Sets the classpath of this project.
+ * <p>
+ * Setting the classpath to <code>null</code> specifies a default classpath
+ * (the project root). Setting the classpath to an empty array specifies an
+ * empty classpath.
+ * <p>
+ * If a cycle is detected while setting this classpath, an error marker will be added
+ * to the project closing the cycle.
+ * To avoid this problem, use <code>hasClasspathCycle(IClasspathEntry[] entries)</code>
+ * before setting the classpath.
+ *
+ * @exception JavaModelException if the classpath could not be set. Reasons include:
+ * <ul>
+ * <li> This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> Two or more entries specify source roots with the same or overlapping paths (NAME_COLLISION)
+ * <li> A entry of kind <code>CPE_PROJECT</code> refers to this project (INVALID_PATH)
+ * <li> The classpath is being modified during resource change event notification (CORE_EXCEPTION)
+ * </ul>
+ * @deprecated - was renamed to #setRawClasspath
+ */
+ void setClasspath(IClasspathEntry[] entries, IProgressMonitor monitor)
+ throws JavaModelException;
+ /**
+ * Sets the output location of this project to the location
+ * described by the given absolute path.
+ * <p>
+ *
+ * @exception JavaModelException if the classpath could not be set. Reasons include:
+ * <ul>
+ * <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li>The path refers to a location not contained in this project (<code>PATH_OUTSIDE_PROJECT</code>)
+ * <li>The path is not an absolute path (<code>RELATIVE_PATH</code>)
+ * <li>The path is nested inside a package fragment root of this project (<code>INVALID_PATH</code>)
+ * </ul>
+ */
+ void setOutputLocation(IPath path, IProgressMonitor monitor)
+ throws JavaModelException;
+ /**
+ * Sets the classpath of this project using a list of classpath entries. In particular such a classpath may contain
+ * classpath variable entries. Classpath variable entries can be resolved individually (see <code>JavaCore#getClasspathVariable</code>),
+ * or the full classpath can be resolved at once using the helper method <code>getResolvedClasspath</code>.
+ * <p>
+ * A classpath variable provides an indirection level for better sharing a classpath. As an example, it allows
+ * a classpath to no longer refer directly to external JARs located in some user specific location. The classpath
+ * can simply refer to some variables defining the proper locations of these external JARs.
+ * <p>
+ * Setting the classpath to <code>null</code> specifies a default classpath
+ * (the project root). Setting the classpath to an empty array specifies an
+ * empty classpath.
+ * <p>
+ * If a cycle is detected while setting this classpath, an error marker will be added
+ * to the project closing the cycle.
+ * To avoid this problem, use <code>hasClasspathCycle(IClasspathEntry[] entries)</code>
+ * before setting the classpath.
+ *
+ * @exception JavaModelException if the classpath could not be set. Reasons include:
+ * <ul>
+ * <li> This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> Two or more entries specify source roots with the same or overlapping paths (NAME_COLLISION)
+ * <li> A entry of kind <code>CPE_PROJECT</code> refers to this project (INVALID_PATH)
+ * <li> The classpath is being modified during resource change event notification (CORE_EXCEPTION)
+ * </ul>
+ * @see IClasspathEntry
+ */
+ void setRawClasspath(IClasspathEntry[] entries, IProgressMonitor monitor)
+ throws JavaModelException;
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IMember.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IMember.java
new file mode 100644
index 0000000000..f3e3d0eea3
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IMember.java
@@ -0,0 +1,51 @@
+package org.eclipse.jdt.core;
+
+public interface IMember
+ extends IJavaElement, ISourceReference, ISourceManipulation {
+ /**
+ * Returns the class file in which this member is declared, or <code>null</code>
+ * if this member is not declared in a class file (for example, a source type).
+ * This is a handle-only method.
+ */
+ IClassFile getClassFile();
+ /**
+ * Returns the compilation unit in which this member is declared, or <code>null</code>
+ * if this member is not declared in a compilation unit (for example, a binary type).
+ * This is a handle-only method.
+ */
+ ICompilationUnit getCompilationUnit();
+ /**
+ * Returns the type in which this member is declared, or <code>null</code>
+ * if this member is not declared in a type (for example, a top-level type).
+ * This is a handle-only method.
+ */
+ IType getDeclaringType();
+ /**
+ * Returns the modifier flags for this member. The flags can be examined using class
+ * <code>Flags</code>.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ *
+ * @see Flags
+ */
+ int getFlags() throws JavaModelException;
+ /**
+ * Returns the source range of this member's simple name,
+ * or <code>null</code> if this member does not have a name
+ * (for example, an initializer), or if this member does not have
+ * associated source code (for example, a binary type).
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ */
+ ISourceRange getNameRange() throws JavaModelException;
+ /**
+ * Returns whether this member is from a class file.
+ * This is a handle-only method.
+ *
+ * @return <code>true</code> if from a class file, and <code>false</code> if
+ * from a compilation unit
+ */
+ boolean isBinary();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IMethod.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IMethod.java
new file mode 100644
index 0000000000..bd176f9e80
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IMethod.java
@@ -0,0 +1,90 @@
+package org.eclipse.jdt.core;
+
+public interface IMethod extends IMember {
+ /**
+ * Returns the simple name of this method.
+ * For a constructor, this returns the simple name of the declaring type.
+ * Note: This holds whether the constructor appears in a source or binary type
+ * (even though class files internally define constructor names to be <code>"&lt;init&gt;"</code>).
+ * For the class initialization methods in binary types, this returns
+ * the special name <code>"&lt;clinit&gt;"</code>.
+ * This is a handle-only method.
+ */
+ String getElementName();
+ /**
+ * Returns the type signatures of the exceptions this method throws,
+ * in the order declared in the source. Returns an empty array
+ * if this method throws no exceptions.
+ *
+ * <p>For example, a source method declaring <code>"throws IOException"</code>,
+ * would return the array <code>{"QIOException;"}</code>.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ *
+ * @see Signature
+ */
+ String[] getExceptionTypes() throws JavaModelException;
+ /**
+ * Returns the number of parameters of this method.
+ * This is a handle-only method.
+ */
+ int getNumberOfParameters();
+ /**
+ * Returns the names of parameters in this method.
+ * For binary types, these names are invented as "arg"+i, where i starts at 1
+ * (even if source is associated with the binary).
+ * Returns an empty array if this method has no parameters.
+ *
+ * <p>For example, a method declared as <code>public void foo(String text, int length)</code>
+ * would return the array <code>{"text","length"}</code>.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ */
+ String[] getParameterNames() throws JavaModelException;
+ /**
+ * Returns the type signatures for the parameters of this method.
+ * Returns an empty array if this method has no parameters.
+ * This is a handle-only method.
+ *
+ * <p>For example, a source method declared as <code>public void foo(String text, int length)</code>
+ * would return the array <code>{"QString;","I"}</code>.
+ *
+ * @see Signature
+ */
+ String[] getParameterTypes();
+ /**
+ * Returns the type signature of the return value of this method.
+ * For constructors, this returns the signature for void.
+ *
+ * <p>For example, a source method declared as <code>public String getName()</code>
+ * would return <code>"QString;"</code>.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ *
+ * @see Signature
+ */
+ String getReturnType() throws JavaModelException;
+ /**
+ * Returns the signature of the method. This includes the signatures for the parameter
+ * types and return type, but does not include the method name or exception types.
+ *
+ * <p>For example, a source method declared as <code>public void foo(String text, int length)</code>
+ * would return <code>"(QString;I)V"</code>.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ *
+ * @see Signature
+ */
+ String getSignature() throws JavaModelException;
+ /**
+ * Returns whether this method is a constructor.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ */
+ boolean isConstructor() throws JavaModelException;
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IOpenable.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IOpenable.java
new file mode 100644
index 0000000000..cd58a42b79
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IOpenable.java
@@ -0,0 +1,149 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * Common protocol for Java elements that must be opened before they can be
+ * navigated or modified. Opening a textual element (such as a compilation unit)
+ * involves opening a buffer on its contents. While open, any changes to the buffer
+ * can be reflected in the element's structure;
+ * see <code>isConsistent</code> and <code>makeConsistent(IProgressMonitor)</code>.
+ * <p>
+ * To reduce complexity in clients, elements are automatically opened
+ * by the Java model as element properties are accessed. The Java model maintains
+ * an LRU cache of open elements, and automatically closes elements as they
+ * are swapped out of the cache to make room for other elements. Elements with
+ * unsaved changes are never removed from the cache, and thus, if the client
+ * maintains many open elements with unsaved
+ * changes, the LRU cache can grow in size (in this case the cache is not
+ * bounded). However, as elements are saved, the cache will shrink back to its
+ * original bounded size.
+ * </p>
+ * <p>
+ * To open an element, all openable parent elements must be open.
+ * The Java model automatically opens parent elements, as it automatically opens elements.
+ * Opening an element may provide access to direct children and other descendants,
+ * but does not automatically open any descendents which are themselves <code>IOpenable</code>.
+ * For example, opening a compilation unit provides access to all its constituent elements,
+ * but opening a package fragment does not open all compilation units in the package fragment.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ */
+public interface IOpenable {
+
+ /**
+ * Closes this element and its buffer (if any).
+ * Closing an element which is not open has no effect.
+ *
+ * <p>Note: although <code>close</code> is exposed in the API, clients are
+ * not expected to open and close elements - the Java model does this automatically
+ * as elements are accessed.
+ *
+ * @exception JavaModelException if an error occurs closing this element
+ */
+ public void close() throws JavaModelException;
+ /**
+ * Returns the buffer opened for this element, or <code>null</code>
+ * if this element does not have a buffer.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ */
+ public IBuffer getBuffer() throws JavaModelException;
+ /**
+ * Returns <code>true</code> if this element is open and:
+ * <ul>
+ * <li>its buffer has unsaved changes, or
+ * <li>one of its descendants has unsaved changes, or
+ * <li>a working copy has been created on one of this
+ * element's children and has not yet destroyed
+ * </ul>
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ */
+ boolean hasUnsavedChanges() throws JavaModelException;
+ /**
+ * Returns whether the element is consistent with its underlying resource or buffer.
+ * The element is consistent when opened, and is consistent if the underlying resource
+ * or buffer has not been modified since it was last consistent.
+ *
+ * <p>NOTE: Child consistency is not considered. For example, a package fragment
+ * responds <code>true</code> when it knows about all of its
+ * compilation units present in its underlying folder. However, one or more of
+ * the compilation units could be inconsistent.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ *
+ * @see IOpenable#makeConsistent
+ */
+ boolean isConsistent() throws JavaModelException;
+ /**
+ * Returns whether this openable is open. This is a handle-only method.
+ */
+ boolean isOpen();
+ /**
+ * Makes this element consistent with its underlying resource or buffer
+ * by updating the element's structure and properties as necessary.
+ *
+ * @exception JavaModelException if the element is unable to access the contents
+ * of its underlying resource. Reasons include:
+ * <ul>
+ * <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * </ul>
+ * @see IOpenable#isConsistent
+ */
+ void makeConsistent(IProgressMonitor progress) throws JavaModelException;
+ /**
+ * Opens this element and all parent elements that are not already open.
+ * For compilation units, a buffer is opened on the contents of the underlying resource.
+ *
+ * <p>Note: although <code>open</code> is exposed in the API, clients are
+ * not expected to open and close elements - the Java model does this automatically
+ * as elements are accessed.
+ *
+ * @exception JavaModelException if an error occurs accessing the contents
+ * of its underlying resource. Reasons include:
+ * <ul>
+ * <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * </ul>
+ */
+ public void open(IProgressMonitor progress) throws JavaModelException;
+ /**
+ * Saves any changes in this element's buffer to its underlying resource
+ * via a workspace resource operation. This has no effect if the element has no underlying
+ * buffer, or if there are no unsaved changed in the buffer.
+ * <p>
+ * The <code>force</code> parameter controls how this method deals with
+ * cases where the workbench is not completely in sync with the local file system.
+ * If <code>false</code> is specified, this method will only attempt
+ * to overwrite a corresponding file in the local file system provided
+ * it is in sync with the workbench. This option ensures there is no
+ * unintended data loss; it is the recommended setting.
+ * However, if <code>true</code> is specified, an attempt will be made
+ * to write a corresponding file in the local file system,
+ * overwriting any existing one if need be.
+ * In either case, if this method succeeds, the resource will be marked
+ * as being local (even if it wasn't before).
+ * <p>
+ * As a result of this operation, the element is consistent with its underlying
+ * resource or buffer.
+ *
+ * @exception JavaModelException if an error occurs accessing the contents
+ * of its underlying resource. Reasons include:
+ * <ul>
+ * <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li>This Java element is read-only (READ_ONLY)</li>
+ * </ul>
+ */
+ public void save(IProgressMonitor progress, boolean force)
+ throws JavaModelException;
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageDeclaration.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageDeclaration.java
new file mode 100644
index 0000000000..771053e061
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageDeclaration.java
@@ -0,0 +1,9 @@
+package org.eclipse.jdt.core;
+
+public interface IPackageDeclaration extends IJavaElement, ISourceReference {
+ /**
+ * Returns the name of the package the statement refers to.
+ * This is a handle-only method.
+ */
+ String getElementName();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragment.java
new file mode 100644
index 0000000000..6c46fdc30f
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragment.java
@@ -0,0 +1,140 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.resources.IResource;
+
+/**
+ * A package fragment is a portion of the workspace corresponding to an entire package,
+ * or to a portion thereof. The distinction between a package fragment and a package
+ * is that a package with some name is the union of all package fragments in the class path
+ * which have the same name.
+ * <p>
+ * Package fragments elements need to be opened before they can be navigated or manipulated.
+ * The children are of type <code>ICompilationUnit</code> (representing a source file) or
+ * <code>IClassFile</code> (representing a binary class file).
+ * The children are listed in no particular order.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ */
+public interface IPackageFragment
+ extends IParent, IJavaElement, IOpenable, ISourceManipulation {
+
+ /**
+ * <p>
+ * The name of package fragment for the default package (value: the empty
+ * string, <code>""</code>).
+ * </p>
+ */
+ public static final String DEFAULT_PACKAGE_NAME = "";
+ /**
+ * Returns whether this fragment contains at least one Java resource.
+ */
+ boolean containsJavaResources() throws JavaModelException;
+ /**
+ * Creates and returns a compilation unit in this package fragment
+ * with the specified name and contents. No verification is performed
+ * on the contents.
+ *
+ * <p>It is possible that a compilation unit with the same name already exists in this
+ * package fragment.
+ * The value of the <code>force</code> parameter effects the resolution of
+ * such a conflict:<ul>
+ * <li> <code>true</code> - in this case the compilation is created with the new contents</li>
+ * <li> <code>false</code> - in this case a <code>JavaModelException</code> is thrown</li>
+ * </ul>
+ *
+ * @exception JavaModelException if the element could not be created. Reasons include:
+ * <ul>
+ * <li> This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while creating an underlying resource
+ * <li> The name is not a valid compilation unit name (INVALID_NAME)
+ * <li> The contents are <code>null</code> (INVALID_CONTENTS)
+ * </ul>
+ */
+ ICompilationUnit createCompilationUnit(
+ String name,
+ String contents,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException;
+ /**
+ * Returns the class file with the specified name
+ * in this package (for example, <code>"Object.class"</code>).
+ * The ".class" suffix is required.
+ * This is a handle-only method. The class file may or may not be present.
+ */
+ IClassFile getClassFile(String name);
+ /**
+ * Returns all of the class files in this package fragment.
+ *
+ * <p>Note: it is possible that a package fragment contains only
+ * compilation units (i.e. its kind is <code>K_SOURCE</code>), in
+ * which case this method returns an empty collection.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ */
+ IClassFile[] getClassFiles() throws JavaModelException;
+ /**
+ * Returns the compilation unit with the specified name
+ * in this package (for example, <code>"Object.java"</code>).
+ * The ".java" suffix is required.
+ * This is a handle-only method. The compilation unit may or may not be present.
+ */
+ ICompilationUnit getCompilationUnit(String name);
+ /**
+ * Returns all of the compilation units in this package fragment.
+ *
+ * <p>Note: it is possible that a package fragment contains only
+ * class files (i.e. its kind is <code>K_BINARY</code>), in which
+ * case this method returns an empty collection.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ */
+ ICompilationUnit[] getCompilationUnits() throws JavaModelException;
+ /**
+ * Returns the dot-separated package name of this fragment, for example
+ * <code>"java.lang"</code>, or <code>""</code> (the empty string),
+ * for the default package.
+ */
+ String getElementName();
+ /**
+ * Returns this package fragment's root kind encoded as an integer.
+ * A package fragment can contain <code>.java</code> source files,
+ * or <code>.class</code> files. This is a convenience method.
+ *
+ * @see IPackageFragmentRoot#K_SOURCE
+ * @see IPackageFragmentRoot#K_BINARY
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ *
+ */
+ int getKind() throws JavaModelException;
+ /**
+ * Returns an array of non-Java resources contained in this package fragment.
+ */
+ Object[] getNonJavaResources() throws JavaModelException;
+ /**
+ * Returns whether this package fragment's name is
+ * a prefix of other package fragments in this package fragment's
+ * root.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ */
+ boolean hasSubpackages() throws JavaModelException;
+ /**
+ * Returns whether this package fragment is a default package.
+ * This is a handle-only method.
+ */
+ boolean isDefaultPackage();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java
new file mode 100644
index 0000000000..473eb5f6e3
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java
@@ -0,0 +1,160 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * A package fragment root contains a set of package fragments.
+ * It corresponds to an underlying resource which is either a folder,
+ * JAR, or zip. In the case of a folder, all descendant folders represent
+ * package fragments. For a given child folder representing a package fragment,
+ * the corresponding package name is composed of the folder names between the folder
+ * for this root and the child folder representing the package, separated by '.'.
+ * In the case of a JAR or zip, the contents of the archive dictates
+ * the set of package fragments in an analogous manner.
+ * Package fragment roots need to be opened before they can be navigated or manipulated.
+ * The children are of type <code>IPackageFragment</code>, and are in no particular order.
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ */
+public interface IPackageFragmentRoot
+ extends IParent, IJavaElement, IOpenable {
+
+ /**
+ * Kind constant for a source path root. Indicates this root
+ * only contains source files.
+ */
+ int K_SOURCE = 1;
+
+ /**
+ * Kind constant for a binary path root. Indicates this
+ * root only contains binary files.
+ */
+ int K_BINARY = 2;
+ /**
+ * Empty root path
+ */
+ String DEFAULT_PACKAGEROOT_PATH = "";
+
+ /**
+ * Attaches the source archive identified by the given absolute path to this
+ * JAR package fragment root. <code>rootPath</code> specifies the location
+ * of the root within the archive (<code>null</code> or empty specifies the default root).
+ * Once a source archive is attached to the JAR,
+ * the <code>getSource</code> and <code>getSourceRange</code>
+ * methods become operational for binary types/members.
+ * To detach a source archive from a JAR, specify <code>null</code> as the
+ * archivePath.
+ *
+ * @exception JavaModelException if this operation fails. Reasons include:
+ * <ul>
+ * <li> This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating a server property
+ * <li> This package fragment root is not a JAR (INVALID_ELEMENT_TYPES)
+ * <li> The path provided is not absolute (RELATIVE_PATH)
+ * </ul>
+ * @deprecated - source attachment is to be specified using classpath entries.
+ */
+ void attachSource(IPath archivePath, IPath rootPath, IProgressMonitor monitor)
+ throws JavaModelException;
+ /**
+ * Creates and returns a package fragment in this root with the
+ * given dot-separated package name. An empty string specifies the default package.
+ * This has the side effect of creating all package
+ * fragments that are a prefix of the new package fragment which
+ * do not exist yet. If the package fragment already exists, this
+ * has no effect.
+ *
+ * For a descrption of the <code>force</code> flag, see <code>IFolder.create</code>.
+ *
+ * @exception JavaModelException if the element could not be created. Reasons include:
+ * <ul>
+ * <li> This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while creating an underlying resource
+ * <li> This package fragment root is read only (READ_ONLY)
+ * <li> The name is not a valid package name (INVALID_NAME)
+ * </ul>
+ * @see org.eclipse.core.resources.IFolder#create
+ */
+ IPackageFragment createPackageFragment(
+ String name,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException;
+ /**
+ * Returns this package fragment root's kind encoded as an integer.
+ * A package fragment root can contain <code>.java</code> source files,
+ * or <code>.class</code> files, but not both.
+ * If the underlying folder or archive contains other kinds of files, they are ignored.
+ * In particular, <code>.class</code> files are ignored under a source package fragment root,
+ * and <code>.java</code> files are ignored under a binary package fragment root.
+ *
+ * @see IPackageFragmentRoot#K_SOURCE
+ * @see IPackageFragmentRoot#K_BINARY
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ */
+ int getKind() throws JavaModelException;
+ /**
+ * Returns an array of non-Java resources contained in this package fragment root.
+ */
+ Object[] getNonJavaResources() throws JavaModelException;
+ /**
+ * Returns the package fragment with the given package name.
+ * An empty string indicates the default package.
+ * This is a handle-only operation. The package fragment
+ * may or may not exist.
+ */
+ IPackageFragment getPackageFragment(String packageName);
+ /**
+ * Returns the path of this package fragment root. If this
+ * package fragment root is not external, the path returned is the
+ * full, absolute path to this package fragment root, relative to the
+ * workbench. If this package fragment root is external, the path
+ * returned is the absolute path to this package fragment root's
+ * archive in the file system.
+ */
+ IPath getPath();
+ /**
+ * Returns the absolute path to the source archive attached to
+ * this package fragment root's binary archive.
+ *
+ * @return the absolute path to the corresponding source archive,
+ * or <code>null</code> if this package fragment root's binary archive
+ * has no corresponding source archive, or if this package fragment root
+ * is not a binary archive
+ * @exception JavaModelException if this operation fails
+ */
+ IPath getSourceAttachmentPath() throws JavaModelException;
+ /**
+ * Returns the path within this package fragment root's source archive.
+ * An empty path indicates that packages are located at the root of the
+ * source archive.
+ *
+ * @return the path within the corresponding source archive,
+ * or <code>null</code> if this package fragment root's binary archive
+ * has no corresponding source archive, or if this package fragment root
+ * is not a binary archive
+ * @exception JavaModelException if this operation fails
+ */
+ IPath getSourceAttachmentRootPath() throws JavaModelException;
+ /**
+ * Returns whether this package fragment root's underlying
+ * resource is a binary archive (a JAR or zip file).
+ */
+ public boolean isArchive();
+ /**
+ * Returns whether this package fragment root is external
+ * to the workbench (that is, a local file), and has no
+ * underlying resource.
+ */
+ boolean isExternal();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IParent.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IParent.java
new file mode 100644
index 0000000000..161850017e
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IParent.java
@@ -0,0 +1,22 @@
+package org.eclipse.jdt.core;
+
+public interface IParent {
+ /**
+ * Returns the immediate children of this element.
+ * Unless otherwise specified by the implementing element,
+ * the children are in no particular order.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ IJavaElement[] getChildren() throws JavaModelException;
+ /**
+ * Returns whether this element has one or more immediate children.
+ * This is a convenience method, and may be more efficient than
+ * testing whether <code>getChildren</code> is an empty array.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ boolean hasChildren() throws JavaModelException;
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IRegion.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IRegion.java
new file mode 100644
index 0000000000..460d89db85
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IRegion.java
@@ -0,0 +1,29 @@
+package org.eclipse.jdt.core;
+
+public interface IRegion {
+ /**
+ * Adds the given element and all of its descendents to this region.
+ * If the specified element is already included, or one of its
+ * ancestors is already included, this has no effect. If the element
+ * being added is an ancestor of an element already contained in this
+ * region, the ancestor subsumes the descendent.
+ */
+ void add(IJavaElement element);
+ /**
+ * Returns whether the given element is contained in this region.
+ */
+ boolean contains(IJavaElement element);
+ /**
+ * Returns the top level elements in this region.
+ * All descendents of these elements are also included in this region.
+ */
+ IJavaElement[] getElements();
+ /**
+ * Removes the specified element from the region and returns
+ * <code>true</code> if successful, <code>false</code> if the remove
+ * fails. If an ancestor of the given element is included, the
+ * remove fails (i.e. not possible to selectively
+ * exclude descendants of included ancestors).
+ */
+ boolean remove(IJavaElement element);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceManipulation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceManipulation.java
new file mode 100644
index 0000000000..6915e56e3e
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceManipulation.java
@@ -0,0 +1,121 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * Common protocol for Java elements that support source code manipulations such
+ * as copy, move, rename, and delete.
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ */
+public interface ISourceManipulation {
+ /**
+ * Copies this element to the given container.
+ *
+ * @param container the container
+ * @param sibling the sibling element before which the copy should be inserted,
+ * or <code>null</code> if the copy should be inserted as the last child of
+ * the container
+ * @param rename the new name for the element, or <code>null</code> if the copy
+ * retains the name of this element
+ * @param replace <code>true</code> if any existing child in the container with
+ * the target name should be replaced, and <code>false</code> to throw an
+ * exception in the event of a name collision
+ * @param monitor a progress monitor
+ * @exception JavaModelException if this element could not be copied. Reasons include:
+ * <ul>
+ * <li> This Java element, container element, or sibling does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource
+ * <li> The container is of an incompatible type (INVALID_DESTINATION)
+ * <li> The sibling is not a child of the given container (INVALID_SIBLING)
+ * <li> The new name is invalid (INVALID_NAME)
+ * <li> A child in the container already exists with the same name (NAME_COLLISION)
+ * and <code>replace</code> has been specified as <code>false</code>
+ * <li> The container or this element is read-only (READ_ONLY)
+ * </ul>
+ *
+ * @exception IllegalArgumentException if container is <code>null</code>
+ */
+ void copy(
+ IJavaElement container,
+ IJavaElement sibling,
+ String rename,
+ boolean replace,
+ IProgressMonitor monitor)
+ throws JavaModelException;
+ /**
+ * Deletes this element, forcing if specified and necessary.
+ *
+ * @param force a flag controlling whether underlying resources that are not
+ * in sync with the local file system will be tolerated (same as the force flag
+ * in IResource operations).
+ * @param monitor a progress monitor
+ * @exception JavaModelException if this element could not be deleted. Reasons include:
+ * <ul>
+ * <li> This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource (CORE_EXCEPTION)</li>
+ * <li> This element is read-only (READ_ONLY)</li>
+ * </ul>
+ */
+ void delete(boolean force, IProgressMonitor monitor) throws JavaModelException;
+ /**
+ * Moves this element to the given container.
+ *
+ * @param container the container
+ * @param sibling the sibling element before which the element should be inserted,
+ * or <code>null</code> if the element should be inserted as the last child of
+ * the container
+ * @param rename the new name for the element, or <code>null</code> if the
+ * element retains its name
+ * @param replace <code>true</code> if any existing child in the container with
+ * the target name should be replaced, and <code>false</code> to throw an
+ * exception in the event of a name collision
+ * @param monitor a progress monitor
+ * @exception JavaModelException if this element could not be moved. Reasons include:
+ * <ul>
+ * <li> This Java element, container element, or sibling does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource
+ * <li> The container is of an incompatible type (INVALID_DESTINATION)
+ * <li> The sibling is not a child of the given container (INVALID_SIBLING)
+ * <li> The new name is invalid (INVALID_NAME)
+ * <li> A child in the container already exists with the same name (NAME_COLLISION)
+ * and <code>replace</code> has been specified as <code>false</code>
+ * <li> The container or this element is read-only (READ_ONLY)
+ * </ul>
+ *
+ * @exception IllegalArgumentException if container is <code>null</code>
+ */
+ void move(
+ IJavaElement container,
+ IJavaElement sibling,
+ String rename,
+ boolean replace,
+ IProgressMonitor monitor)
+ throws JavaModelException;
+ /**
+ * Renames this element to the given name.
+ *
+ * @param name the new name for the element
+ * @param replace <code>true</code> if any existing element with the target name
+ * should be replaced, and <code>false</code> to throw an exception in the
+ * event of a name collision
+ * @param monitor a progress monitor
+ * @exception JavaModelException if this element could not be renamed. Reasons include:
+ * <ul>
+ * <li> This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource
+ * <li> The new name is invalid (INVALID_NAME)
+ * <li> A child in the container already exists with the same name (NAME_COLLISION)
+ * and <code>replace</code> has been specified as <code>false</code>
+ * <li> This element is read-only (READ_ONLY)
+ * </ul>
+ */
+ void rename(String name, boolean replace, IProgressMonitor monitor)
+ throws JavaModelException;
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceRange.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceRange.java
new file mode 100644
index 0000000000..1a9eb62aa4
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceRange.java
@@ -0,0 +1,15 @@
+package org.eclipse.jdt.core;
+
+public interface ISourceRange {
+
+ /**
+ * Returns the number of characters of the source code for this element,
+ * relative to the source buffer in which this element is contained.
+ */
+ int getLength();
+ /**
+ * Returns the 0-based index of the first character of the source code for this element,
+ * relative to the source buffer in which this element is contained.
+ */
+ int getOffset();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceReference.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceReference.java
new file mode 100644
index 0000000000..d92a6de117
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceReference.java
@@ -0,0 +1,33 @@
+package org.eclipse.jdt.core;
+
+public interface ISourceReference {
+ /**
+ * Returns the source code associated with this element.
+ * This extracts the substring from the source buffer containing this source
+ * element. This corresponds to the source range that would be returned by
+ * <code>getSourceRange</code>.
+ * <p>
+ * For class files, this returns the source of the entire compilation unit
+ * associated with the class file (if there is one).
+ * </p>
+ *
+ * @return the source code, or <code>null</code> if this element has no
+ * associated source code
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ String getSource() throws JavaModelException;
+ /**
+ * Returns the source range associated with this element.
+ * <p>
+ * For class files, this returns the range of the entire compilation unit
+ * associated with the class file (if there is one).
+ * </p>
+ *
+ * @return the source range, or <code>null</code> if if this element has no
+ * associated source code
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource
+ */
+ ISourceRange getSourceRange() throws JavaModelException;
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IType.java
new file mode 100644
index 0000000000..422560fa0b
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IType.java
@@ -0,0 +1,319 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * Represents either a source type in a compilation unit (either a top-level
+ * type or a member type) or a binary type in a class file.
+ * <p>
+ * If a binary type cannot be parsed, its structure remains unknown.
+ * Use <code>IJavaElement.isStructureKnown</code> to determine whether this
+ * is the case.
+ * </p>
+ * <p>
+ * The children are of type <code>IMember</code>, which includes <code>IField</code>,
+ * <code>IMethod</code>, <code>IInitializer</code> and <code>IType</code>.
+ * The children are listed in the order in which they appear in the source or class file.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ */
+public interface IType extends IMember, IParent {
+
+ /**
+ * Creates and returns a field in this type with the
+ * given contents.
+ * <p>
+ * Optionally, the new element can be positioned before the specified
+ * sibling. If no sibling is specified, the element will be inserted
+ * as the last field declaration in this type.
+ *
+ * <p>It is possible that a field with the same name already exists in this type.
+ * The value of the <code>force</code> parameter effects the resolution of
+ * such a conflict:<ul>
+ * <li> <code>true</code> - in this case the field is created with the new contents</li>
+ * <li> <code>false</code> - in this case a <code>JavaModelException</code> is thrown</li>
+ *
+ * @exception JavaModelException if the element could not be created. Reasons include:
+ * <ul>
+ * <li> This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource
+ * <li> The specified sibling is not a child of this type (INVALID_SIBLING)
+ * <li> The contents could not be recognized as a field declaration (INVALID_CONTENTS)
+ * <li> This type is read-only (binary) (READ_ONLY)
+ * <li> There was a naming collision with an existing field (NAME_COLLISION)
+ * </ul>
+ */
+ IField createField(
+ String contents,
+ IJavaElement sibling,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException;
+ /**
+ * Creates and returns a static initializer in this type with the
+ * given contents.
+ * <p>
+ * Optionally, the new element can be positioned before the specified
+ * sibling. If no sibling is specified, the new initializer is positioned
+ * after the last existing initializer declaration, or as the first member
+ * in the type if there are no
+ * initializers.
+ *
+ * @exception JavaModelException if the element could not be created. Reasons include:
+ * <ul>
+ * <li> This element does not exist
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource
+ * <li> The specified sibling is not a child of this type (INVALID_SIBLING)
+ * <li> The contents could not be recognized as an initializer declaration (INVALID_CONTENTS)
+ * <li> This type is read-only (binary) (READ_ONLY)
+ * </ul>
+ */
+ IInitializer createInitializer(
+ String contents,
+ IJavaElement sibling,
+ IProgressMonitor monitor)
+ throws JavaModelException;
+ /**
+ * Creates and returns a method or constructor in this type with the
+ * given contents.
+ * <p>
+ * Optionally, the new element can be positioned before the specified
+ * sibling. If no sibling is specified, the element will be appended
+ * to this type.
+ *
+ * <p>It is possible that a method with the same signature already exists in this type.
+ * The value of the <code>force</code> parameter effects the resolution of
+ * such a conflict:<ul>
+ * <li> <code>true</code> - in this case the method is created with the new contents</li>
+ * <li> <code>false</code> - in this case a <code>JavaModelException</code> is thrown</li>
+ *
+ * @exception JavaModelException if the element could not be created. Reasons include:
+ * <ul>
+ * <li> This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource
+ * <li> The specified sibling is not a child of this type (INVALID_SIBLING)
+ * <li> The contents could not be recognized as a method or constructor
+ * declaration (INVALID_CONTENTS)
+ * <li> This type is read-only (binary) (READ_ONLY)
+ * <li> There was a naming collision with an existing method (NAME_COLLISION)
+ * </ul>
+ */
+ IMethod createMethod(
+ String contents,
+ IJavaElement sibling,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException;
+ /**
+ * Creates and returns a type in this type with the
+ * given contents.
+ * <p>
+ * Optionally, the new type can be positioned before the specified
+ * sibling. If no sibling is specified, the type will be appended
+ * to this type.
+ *
+ * <p>It is possible that a type with the same name already exists in this type.
+ * The value of the <code>force</code> parameter effects the resolution of
+ * such a conflict:<ul>
+ * <li> <code>true</code> - in this case the type is created with the new contents</li>
+ * <li> <code>false</code> - in this case a <code>JavaModelException</code> is thrown</li>
+ *
+ * @exception JavaModelException if the element could not be created. Reasons include:
+ * <ul>
+ * <li> This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource
+ * <li> The specified sibling is not a child of this type (INVALID_SIBLING)
+ * <li> The contents could not be recognized as a type declaration (INVALID_CONTENTS)
+ * <li> This type is read-only (binary) (READ_ONLY)
+ * <li> There was a naming collision with an existing field (NAME_COLLISION)
+ * </ul>
+ */
+ IType createType(
+ String contents,
+ IJavaElement sibling,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException;
+ /**
+ * Returns the simple name of this type, unqualified by package or enclosing type.
+ * This is a handle-only method.
+ */
+ String getElementName();
+ /**
+ * Returns the field with the specified name
+ * in this type (for example, <code>"bar"</code>).
+ * This is a handle-only method. The field may or may not exist.
+ */
+ IField getField(String name);
+ /**
+ * Returns the fields declared by this type.
+ * If this is a source type, the results are listed in the order
+ * in which they appear in the source, otherwise, the results are
+ * in no particular order. For binary types, this includes synthetic fields.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ */
+ IField[] getFields() throws JavaModelException;
+ /**
+ * Returns the fully qualified name of this type,
+ * including qualification for any containing types and packages.
+ * This is the name of the package, followed by <code>'.'</code>,
+ * followed by the type-qualified name.
+ * This is a handle-only method.
+ *
+ * @see IType#getTypeQualifiedName()
+ */
+ String getFullyQualifiedName();
+ /**
+ * Returns the Initializer with the specified position relative to
+ * the order they are defined in the source.
+ * Numbering starts at 1 (i.e. the first occurrence is occurrence 1, not occurrence 0).
+ * This is a handle-only method. The initializer may or may not be present.
+ */
+ IInitializer getInitializer(int occurrenceCount);
+ /**
+ * Returns the initializers declared by this type.
+ * For binary types this is an empty collection.
+ * If this is a source type, the results are listed in the order
+ * in which they appear in the source.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ */
+ IInitializer[] getInitializers() throws JavaModelException;
+ /**
+ * Returns the method with the specified name and parameter types
+ * in this type (for example, <code>"foo", {"I", "QString;"}</code>). To get the
+ * handle for a constructor, the name specified must be the simple
+ * name of the enclosing type.
+ * This is a handle-only method. The method may or may not be present.
+ */
+ IMethod getMethod(String name, String[] parameterTypeSignatures);
+ /**
+ * Returns the methods and constructors declared by this type.
+ * For binary types, this may include the special <code>&lt;clinit&gt</code>; method
+ * and synthetic methods.
+ * If this is a source type, the results are listed in the order
+ * in which they appear in the source, otherwise, the results are
+ * in no particular order.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ */
+ IMethod[] getMethods() throws JavaModelException;
+ /**
+ * Returns the package fragment in which this element is defined.
+ * This is a handle-only method.
+ */
+ IPackageFragment getPackageFragment();
+ /**
+ * Returns the name of this type's superclass, or <code>null</code>
+ * for source types that do not specify a superclass.
+ * For interfaces, the superclass name is always <code>"java.lang.Object"</code>.
+ * For source types, the name as declared is returned, for binary types,
+ * the resolved, qualified name is returned.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ */
+ String getSuperclassName() throws JavaModelException;
+ /**
+ * Returns the names of interfaces that this type implements or extends,
+ * in the order in which they are listed in the source.
+ * For classes, this gives the interfaces that this class implements.
+ * For interfaces, this gives the interfaces that this interface extends.
+ * An empty collection is returned if this type does not implement or
+ * extend any interfaces. For source types, simples name are returned,
+ * for binary types, qualified names are returned.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ */
+ String[] getSuperInterfaceNames() throws JavaModelException;
+ /**
+ * Returns the member type declared in this type with the given simple name.
+ * This is a handle-only method. The type may or may not exist.
+ */
+ IType getType(String name);
+ /**
+ * Returns the type-qualified name of this type,
+ * including qualification for any enclosing types,
+ * but not including package qualification.
+ * For source types, this consists of the simple names of
+ * any enclosing types, separated by <code>"$"</code>, followed by the simple name of this type.
+ * For binary types, this is the name of the class file without the ".class" suffix.
+ * This is a handle-only method.
+ */
+ String getTypeQualifiedName();
+ /**
+ * Returns the immediate member types declared by this type.
+ * The results are listed in the order in which they appear in the source or class file.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ */
+ IType[] getTypes() throws JavaModelException;
+ /**
+ * Returns whether this type represents a class.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ */
+ boolean isClass() throws JavaModelException;
+ /**
+ * Returns whether this type represents an interface.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ */
+ boolean isInterface() throws JavaModelException;
+ /**
+ * Creates and returns a type hierarchy for this type containing
+ * this type and all of its supertypes.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ */
+ ITypeHierarchy newSupertypeHierarchy(IProgressMonitor monitor)
+ throws JavaModelException;
+ /**
+ * Creates and returns a type hierarchy for this type containing
+ * this type, all of its supertypes, and all its subtypes in the workspace.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ */
+ ITypeHierarchy newTypeHierarchy(IProgressMonitor monitor)
+ throws JavaModelException;
+ /**
+ * Creates and returns a type hierarchy for this type containing
+ * this type, all of its supertypes, and all its subtypes
+ * in the context of the given project.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ */
+ ITypeHierarchy newTypeHierarchy(IJavaProject project, IProgressMonitor monitor)
+ throws JavaModelException;
+ /**
+ * Resolves the given type name within the context of this type (depending on the type hierarchy
+ * and its imports). Multiple answers might be found in case there are ambiguous matches.
+ *
+ * Each matching type name is decomposed as an array of two strings, the first denoting the package
+ * name (dot-separated) and the second being the type name.
+ * Returns <code>null</code> if unable to find any matching type.
+ *
+ * For example, resolution of <code>"Object"</code> would typically return
+ * <code>{{"java.lang", "Object"}}</code>.
+ *
+ * @exception JavaModelException if code resolve could not be performed.
+ */
+ String[][] resolveType(String typeName) throws JavaModelException;
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeHierarchy.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeHierarchy.java
new file mode 100644
index 0000000000..aca73213be
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeHierarchy.java
@@ -0,0 +1,199 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * A type hierarchy provides navigations between a type and its resolved
+ * supertypes and subtypes for a specific type or for all types within a region.
+ * Supertypes may extend outside of the type hierarchy's region in which it was
+ * created such that the root of the hierarchy is always included. For example, if a type
+ * hierarchy is created for a <code>java.io.File</code>, and the region the hierarchy was
+ * created in is the package fragment <code>java.io</code>, the supertype
+ * <code>java.lang.Object</code> will still be included.
+ * <p>
+ * A type hierarchy is static and can become stale. Although consistent when
+ * created, it does not automatically track changes in the model.
+ * As changes in the model potentially invalidate the hierarchy, change notifications
+ * are sent to registered <code>ITypeHierarchyChangedListener</code>s. Listeners should
+ * use the <code>exists</code> method to determine if the hierarchy has become completely
+ * invalid (for example, when the type or project the hierarchy was created on
+ * has been removed). To refresh a hierarchy, use the <code>refresh</code> method.
+ * </p>
+ * <p>
+ * The type hierarchy may contain cycles due to malformed supertype declarations.
+ * Most type hierarchy queries are oblivious to cycles; the <code>getAll* </code>
+ * methods are implemented such that they are unaffected by cycles.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ */
+public interface ITypeHierarchy {
+ /**
+ * Adds the given listener for changes to this type hierarchy. Listeners are
+ * notified when this type hierarchy changes and needs to be refreshed.
+ * Has no effect if an identical listener is already registered.
+ *
+ * @param listener the listener
+ */
+ void addTypeHierarchyChangedListener(ITypeHierarchyChangedListener listener);
+ /**
+ * Returns whether the given type is part of this hierarchy.
+ */
+ boolean contains(IType type);
+ /**
+ * Returns whether the type and project this hierarchy was created on exist.
+ */
+ boolean exists();
+ /**
+ * Returns all classes in this type hierarchy's graph, in no particular
+ * order. Any classes in the creation region which were not resolved to
+ * have any subtypes or supertypes are not included in the result.
+ */
+ IType[] getAllClasses();
+ /**
+ * Returns all interfaces in this type hierarchy's graph, in no particular
+ * order. Any interfaces in the creation region which were not resolved to
+ * have any subtypes or supertypes are not included in the result.
+ */
+ IType[] getAllInterfaces();
+ /**
+ * Returns all resolved subtypes (direct and indirect) of the
+ * given type, in no particular order, limited to the
+ * types in this type hierarchy's graph. An empty array
+ * is returned if there are no resolved subtypes for the
+ * given type.
+ */
+ IType[] getAllSubtypes(IType type);
+ /**
+ * Returns all resolved superclasses of the
+ * given class, in bottom-up order. An empty array
+ * is returned if there are no resolved superclasses for the
+ * given class.
+ *
+ * <p>NOTE: once a type hierarchy has been created, it is more efficient to
+ * query the hierarchy for superclasses than to query a class recursively up
+ * the superclass chain. Querying an element performs a dynamic resolution,
+ * whereas the hierarchy returns a pre-computed result.
+ */
+ IType[] getAllSuperclasses(IType type);
+ /**
+ * Returns all resolved superinterfaces (direct and indirect) of the given type.
+ * If the given type is a class, this includes all superinterfaces of all superclasses.
+ * An empty array is returned if there are no resolved superinterfaces for the
+ * given type.
+ *
+ * <p>NOTE: once a type hierarchy has been created, it is more efficient to
+ * query the hierarchy for superinterfaces than to query a type recursively.
+ * Querying an element performs a dynamic resolution,
+ * whereas the hierarchy returns a pre-computed result.
+ */
+ IType[] getAllSuperInterfaces(IType type);
+ /**
+ * Returns all resolved supertypes of the
+ * given class, in bottom-up order. An empty array
+ * is returned if there are no resolved supertypes for the
+ * given class.
+ *
+ * <p>NOTE: once a type hierarchy has been created, it is more efficient to
+ * query the hierarchy for supertypes than to query a type recursively up
+ * the supertype chain. Querying an element performs a dynamic resolution,
+ * whereas the hierarchy returns a pre-computed result.
+ */
+ IType[] getAllSupertypes(IType type);
+ /**
+ * Returns all types in this type hierarchy's graph, in no particular
+ * order. Any types in the creation region which were not resolved to
+ * have any subtypes or supertypes are not included in the result.
+ */
+ IType[] getAllTypes();
+ /**
+ * Returns all interfaces resolved to extend the given interface,
+ * in no particular order, limited to the interfaces in this
+ * hierarchy's graph.
+ * Returns an empty collection if the given type is a class, or
+ * if no interfaces were resolved to extend the given interface.
+ */
+ IType[] getExtendingInterfaces(IType type);
+ /**
+ * Returns all classes resolved to implement the given interface,
+ * in no particular order, limited to the classes in this type
+ * hierarchy's graph. Returns an empty collection if the given type is a
+ * class, or if no classes were resolved to implement the given
+ * interface.
+ */
+ IType[] getImplementingClasses(IType type);
+ /**
+ * Returns all classes in the graph which have no resolved superclass,
+ * in no particular order.
+ */
+ IType[] getRootClasses();
+ /**
+ * Returns all interfaces in the graph which have no resolved superinterfaces,
+ * in no particular order.
+ */
+ IType[] getRootInterfaces();
+ /**
+ * Returns the direct resolved subclasses of the given class,
+ * in no particular order, limited to the classes in this
+ * type hierarchy's graph.
+ * Returns an empty collection if the given type is an interface,
+ * or if no classes were resolved to be subclasses of the given
+ * class.
+ */
+ IType[] getSubclasses(IType type);
+ /**
+ * Returns the direct resolved subtypes of the given type,
+ * in no particular order, limited to the types in this
+ * type hierarchy's graph.
+ * If the type is a class, this returns the resolved subclasses.
+ * If the type is an interface, this returns both the classes which implement
+ * the interface and the interfaces which extend it.
+ */
+ IType[] getSubtypes(IType type);
+ /**
+ * Returns the resolved superclass of the given class,
+ * or <code>null</code> if the given class has no superclass,
+ * the superclass could not be resolved, or if the given
+ * type is an interface.
+ */
+ IType getSuperclass(IType type);
+ /**
+ * Returns the direct resolved interfaces that the given type implements or extends,
+ * in no particular order, limited to the interfaces in this type
+ * hierarchy's graph.
+ * For classes, this gives the interfaces that the class implements.
+ * For interfaces, this gives the interfaces that the interface extends.
+ */
+ IType[] getSuperInterfaces(IType type);
+ /**
+ * Returns the resolved supertypes of the given type,
+ * in no particular order, limited to the types in this
+ * type hierarchy's graph.
+ * For classes, this returns its superclass and the interfaces that the class implements.
+ * For interfaces, this returns the interfaces that the interface extends.
+ */
+ IType[] getSupertypes(IType type);
+ /**
+ * Returns the type this hierarchy was computed for.
+ * Returns <code>null</code> if this hierarchy was computed for a region.
+ */
+ IType getType();
+ /**
+ * Re-computes the type hierarchy reporting progess.
+ *
+ * @exception JavaModelException if unable to refresh the hierarchy
+ */
+ void refresh(IProgressMonitor monitor) throws JavaModelException;
+ /**
+ * Removes the given listener from this type hierarchy.
+ * Has no affect if an identical listener is not registered.
+ *
+ * @param listener the listener
+ */
+ void removeTypeHierarchyChangedListener(ITypeHierarchyChangedListener listener);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeHierarchyChangedListener.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeHierarchyChangedListener.java
new file mode 100644
index 0000000000..d95b2d90f0
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeHierarchyChangedListener.java
@@ -0,0 +1,10 @@
+package org.eclipse.jdt.core;
+
+public interface ITypeHierarchyChangedListener {
+ /**
+ * Notifies that the given type hierarchy has changed in some way and should
+ * be refreshed at some point to make it consistent with the current state of
+ * the Java model.
+ */
+ void typeHierarchyChanged(ITypeHierarchy typeHierarchy);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IWorkingCopy.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IWorkingCopy.java
new file mode 100644
index 0000000000..a6b48e04c1
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IWorkingCopy.java
@@ -0,0 +1,147 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * Common protocol for Java elements that support working copies.
+ * <p>
+ * A working copy of a Java element acts just like a regular element (handle),
+ * except it is not attached to an underlying resource. A working copy is not
+ * visible to the rest of the Java model. Changes in a working copy's
+ * buffer are not realized in a resource. To bring the Java model up-to-date with a working
+ * copy's contents, an explicit commit must be performed on the working copy.
+ * Other operations performed on a working copy update the
+ * contents of the working copy's buffer but do not commit the contents
+ * of the working copy.
+ * </p>
+ * <p>
+ * Note: The contents of a working copy is determined when a working
+ * copy is created, based on the current content of the element the working
+ * copy is created from. If a working copy is an <code>IOpenable</code> and is explicitly
+ * closed, the working copy's buffer will be thrown away. However, clients should not
+ * explicitly open and close working copies.
+ * </p>
+ * <p>
+ * The client that creates a working copy is responsible for
+ * destroying the working copy. The Java model will never automatically
+ * destroy or close a working copy. (Note that destroying a working copy
+ * does not commit it to the model, it only frees up the memory occupied by
+ * the element). After a working copy is destroyed, the working copy cannot
+ * be accessed again. Non-handle methods will throw a
+ * <code>JavaModelException</code> indicating the Java element does not exist.
+ * </p>
+ * <p>
+ * A working copy cannot be created from another working copy.
+ * Calling <code>getWorkingCopy</code> on a working copy returns the receiver.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ */
+public interface IWorkingCopy {
+ /**
+ * Commits the contents of this working copy to its original element
+ * and underlying resource, bringing the Java model up-to-date with
+ * the current contents of the working copy.
+ *
+ * <p>It is possible that the contents of the original resource have changed
+ * since this working copy was created, in which case there is an update conflict.
+ * The value of the <code>force</code> parameter effects the resolution of
+ * such a conflict:<ul>
+ * <li> <code>true</code> - in this case the contents of this working copy are applied to
+ * the underlying resource even though this working copy was created before
+ * a subsequent change in the resource</li>
+ * <li> <code>false</code> - in this case a <code>JavaModelException</code> is thrown</li>
+ * </ul>
+ *
+ * @exception JavaModelException if this working copy could not commit. Reasons include:
+ * <ul>
+ * <li> The original Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource
+ * <li> This element is not a working copy (INVALID_ELEMENT_TYPES)
+ * <li> A update conflict (described above) (UPDATE_CONFLICT)
+ * </ul>
+ */
+ void commit(boolean force, IProgressMonitor monitor) throws JavaModelException;
+ /**
+ * Destroys this working copy, closing its buffer and discarding
+ * its structure. Subsequent attempts to access non-handle information
+ * for this working copy will result in <code>IJavaModelException</code>s. Has
+ * no effect if this element is not a working copy.
+ */
+ void destroy();
+ /**
+ * Returns the original element the specified working copy element was created from,
+ * or <code>null</code> if this is not a working copy element. This is a handle
+ * only method, the returned element may or may not exist.
+ */
+ IJavaElement getOriginal(IJavaElement workingCopyElement);
+ /**
+ * Returns the original element this working copy was created from,
+ * or <code>null</code> if this is not a working copy.
+ */
+ IJavaElement getOriginalElement();
+ /**
+ * Returns a working copy of this element if this element is not
+ * a working copy, or this element if this element is a working copy.
+ *
+ * @exception JavaModelException if the contents of this element can
+ * not be determined. Reasons include:
+ * <ul>
+ * <li> This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * </ul>
+ */
+ IJavaElement getWorkingCopy() throws JavaModelException;
+ /**
+ * Returns whether this working copy's original element's content
+ * has not changed since the inception of this working copy.
+ */
+ boolean isBasedOn(IResource resource);
+ /**
+ * Returns whether this element is a working copy.
+ */
+ boolean isWorkingCopy();
+ /**
+ * Reconciles the contents of this working copy.
+ * It performs the reconciliation by locally caching the contents of
+ * the working copy, updating the contents, then creating a delta
+ * over the cached contents and the new contents, and finally firing
+ * this delta.
+ * <p>
+ * Returns the syntax problems found in the new contents as transient markers
+ * associated with the original element. Returns <code>null</code> if no problems were found.
+ * <p>
+ * Note: It has been assumed that added inner types should
+ * not generate change deltas. The implementation has been
+ * modified to reflect this assumption.
+ *
+ * @exception JavaModelException if the contents of the original element
+ * cannot be accessed. Reasons include:
+ * <ul>
+ * <li> The original Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * </ul>
+ */
+ IMarker[] reconcile() throws JavaModelException;
+ /**
+ * Restores the contents of this working copy to the current contents of
+ * this working copy's original element. Has no effect if this element
+ * is not a working copy.
+ *
+ * <p>Note: This is the inverse of committing the content of the
+ * working copy to the original element with <code>commit(boolean, IProgressMonitor)</code>.
+ *
+ * @exception JavaModelException if the contents of the original element
+ * cannot be accessed. Reasons include:
+ * <ul>
+ * <li> The original Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * </ul>
+ */
+ void restore() throws JavaModelException;
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaConventions.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaConventions.java
new file mode 100644
index 0000000000..1e10089075
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaConventions.java
@@ -0,0 +1,398 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.jdt.internal.compiler.parser.InvalidInputException;
+import org.eclipse.jdt.internal.compiler.parser.Scanner;
+import org.eclipse.jdt.internal.compiler.parser.TerminalSymbols;
+
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+
+import java.util.StringTokenizer;
+
+/**
+ * Provides methods for checking Java-specific conventions such as name syntax.
+ * <p>
+ * This class provides static methods and constants only; it is not intended to be
+ * instantiated or subclassed by clients.
+ * </p>
+ */
+public final class JavaConventions {
+ private final static char fgDot = '.';
+ private final static String fgJAVA = "JAVA";
+ /**
+ * Not instantiable.
+ */
+ private JavaConventions() {
+ }
+
+ /**
+ * Returns whether the given package fragment root paths are considered
+ * to overlap.
+ * <p>
+ * Two root paths overlap if one is a prefix of the other, or they point to
+ * the same location. However, a JAR is allowed to be nested in a root.
+ *
+ */
+ public static boolean isOverlappingRoots(IPath rootPath1, IPath rootPath2) {
+ if (rootPath1 == null || rootPath2 == null) {
+ return false;
+ }
+ String extension1 = rootPath1.getFileExtension();
+ String extension2 = rootPath2.getFileExtension();
+ String jarExtension = "JAR";
+ String zipExtension = "ZIP";
+ if (extension1 != null
+ && (extension1.equalsIgnoreCase(jarExtension)
+ || extension1.equalsIgnoreCase(zipExtension))) {
+ return false;
+ }
+ if (extension2 != null
+ && (extension2.equalsIgnoreCase(jarExtension)
+ || extension2.equalsIgnoreCase(zipExtension))) {
+ return false;
+ }
+ return rootPath1.isPrefixOf(rootPath2) || rootPath2.isPrefixOf(rootPath1);
+ }
+
+ /**
+ * Returns the current identifier extracted by the scanner (ie. without unicodes)
+ * from the given id.
+ * Returns <code>null</code> if the id was not valid.
+ */
+ private static char[] scannedIdentifier(String id) {
+ if (id == null) {
+ return null;
+ }
+ String trimmed = id.trim();
+ if (!trimmed.equals(id)) {
+ return null;
+ }
+ try {
+ Scanner scanner = new Scanner();
+ scanner.setSourceBuffer(id.toCharArray());
+ int token = scanner.getNextToken();
+ char[] currentIdentifier;
+ try {
+ currentIdentifier = scanner.getCurrentIdentifierSource();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return null;
+ }
+ int nextToken = scanner.getNextToken();
+ if (token == TerminalSymbols.TokenNameIdentifier
+ && nextToken == TerminalSymbols.TokenNameEOF
+ && scanner.startPosition == scanner.source.length) {
+ // to handle case where we had an ArrayIndexOutOfBoundsException
+ // while reading the last token
+ return currentIdentifier;
+ } else {
+ return null;
+ }
+ } catch (InvalidInputException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Validate the given compilation unit name.
+ * A compilation unit name must obey the following rules:
+ * <ul>
+ * <li> it must not be null
+ * <li> it must include the <code>".java"</code> suffix
+ * <li> its prefix must be a valid identifier
+ * </ul>
+ * </p>
+ * @param name the name of a compilation unit
+ * @return a status object with code <code>IStatus.OK</code> if
+ * the given name is valid as a compilation unit name, otherwise a status
+ * object indicating what is wrong with the name
+ */
+ public static IStatus validateCompilationUnitName(String name) {
+ if (name == null) {
+ return new Status(
+ IStatus.ERROR,
+ JavaCore.PLUGIN_ID,
+ -1,
+ "Compilation unit name must not be null",
+ null);
+ }
+ String extension;
+ String identifier;
+ int index;
+ index = name.indexOf('.');
+ if (index == -1) {
+ return new Status(
+ IStatus.ERROR,
+ JavaCore.PLUGIN_ID,
+ -1,
+ "Compilation unit name must include the \".java\" suffix",
+ null);
+ }
+ identifier = name.substring(0, index);
+ extension = name.substring(index + 1);
+ IStatus status = validateIdentifier(identifier);
+ if (!status.isOK()) {
+ return status;
+ }
+ if (!extension.toUpperCase().equals(fgJAVA)) {
+ return new Status(
+ IStatus.ERROR,
+ JavaCore.PLUGIN_ID,
+ -1,
+ "Compilation unit name must include the \".java\" suffix",
+ null);
+ }
+ return new Status(IStatus.OK, JavaCore.PLUGIN_ID, -1, "OK", null);
+ }
+
+ /**
+ * Validate the given field name.
+ * <p>
+ * Syntax of a field name corresponds to VariableDeclaratorId (JLS2 8.3).
+ * For example, <code>"x"</code>.
+ *
+ * @param name the name of a field
+ * @return a status object with code <code>IStatus.OK</code> if
+ * the given name is valid as a field name, otherwise a status
+ * object indicating what is wrong with the name
+ */
+ public static IStatus validateFieldName(String name) {
+ return validateIdentifier(name);
+ }
+
+ /**
+ * Validate the given Java identifier.
+ * The identifier must have the same spelling as a Java keyword,
+ * boolean literal (<code>"true"</code>, <code>"false"</code>), or null literal (<code>"null"</code>).
+ * See section 3.8 of the <em>Java Language Specification, Second Edition</em> (JLS2).
+ * A valid identifier can act as a simple type name, method name or field name.
+ *
+ * @param id the Java identifier
+ * @return a status object with code <code>IStatus.OK</code> if
+ * the given identifier is a valid Java idetifier, otherwise a status
+ * object indicating what is wrong with the identifier
+ */
+ public static IStatus validateIdentifier(String id) {
+ if (scannedIdentifier(id) != null) {
+ return new Status(IStatus.OK, JavaCore.PLUGIN_ID, -1, "OK", null);
+ } else {
+ return new Status(
+ IStatus.ERROR,
+ JavaCore.PLUGIN_ID,
+ -1,
+ id + " is not a valid Java identifier",
+ null);
+ }
+ }
+
+ /**
+ * Validate the given import declaration name.
+ * <p>
+ * The name of an import corresponds to a fully qualified type name
+ * or an on-demand package name as defined by ImportDeclaration (JLS2 7.5).
+ * For example, <code>"java.util.*"</code> or <code>"java.util.Hashtable"</code>.
+ *
+ * @param name the import declaration
+ * @return a status object with code <code>IStatus.OK</code> if
+ * the given name is valid as an import declaration, otherwise a status
+ * object indicating what is wrong with the name
+ */
+ public static IStatus validateImportDeclaration(String name) {
+ if (name == null || name.length() == 0) {
+ return new Status(
+ IStatus.ERROR,
+ JavaCore.PLUGIN_ID,
+ -1,
+ "An import declaration must not be null",
+ null);
+ ;
+ }
+ if (name.charAt(name.length() - 1) == '*') {
+ if (name.charAt(name.length() - 2) == '.') {
+ return validatePackageName(name.substring(0, name.length() - 2));
+ } else {
+ return new Status(
+ IStatus.ERROR,
+ JavaCore.PLUGIN_ID,
+ -1,
+ "An import declaration must not end with an unqualified *",
+ null);
+ ;
+ }
+ }
+ return validatePackageName(name);
+ }
+
+ /**
+ * Validate the given Java type name, either simple or qualified.
+ * For example, <code>"java.lang.Object"</code>, or <code>"Object"</code>.
+ * <p>
+ *
+ * @param name the name of a type
+ * @return a status object with code <code>IStatus.OK</code> if
+ * the given name is valid as a Java type name,
+ * a status with code <code>IStatus.WARNING</code>
+ * indicating why the given name is discouraged,
+ * otherwise a status object indicating what is wrong with
+ * the name
+ */
+ public static IStatus validateJavaTypeName(String name) {
+ if (name == null) {
+ return new Status(
+ IStatus.ERROR,
+ JavaCore.PLUGIN_ID,
+ -1,
+ "A Java type name must not be null",
+ null);
+ }
+ String trimmed = name.trim();
+ if (!name.equals(trimmed)) {
+ return new Status(
+ IStatus.ERROR,
+ JavaCore.PLUGIN_ID,
+ -1,
+ "A Java type name must not start or end with a blank.",
+ null);
+ ;
+ }
+ int index = name.lastIndexOf('.');
+ char[] scannedID;
+ if (index == -1) {
+ // simple name
+ scannedID = scannedIdentifier(name);
+ } else {
+ // qualified name
+ String pkg = name.substring(0, index).trim();
+ IStatus status = validatePackageName(pkg);
+ if (!status.isOK()) {
+ return status;
+ }
+ String type = name.substring(index + 1).trim();
+ scannedID = scannedIdentifier(type);
+ }
+
+ if (scannedID != null) {
+ if (CharOperation.contains('$', scannedID)) {
+ return new Status(
+ IStatus.WARNING,
+ JavaCore.PLUGIN_ID,
+ -1,
+ "By convention, Java type names usually don't contain the $ character.",
+ null);
+ }
+ if ((scannedID.length > 0 && Character.isLowerCase(scannedID[0]))) {
+ return new Status(
+ IStatus.WARNING,
+ JavaCore.PLUGIN_ID,
+ -1,
+ "By convention, Java type names usually start with an uppercase letter.",
+ null);
+ }
+ return new Status(IStatus.OK, JavaCore.PLUGIN_ID, -1, "OK", null);
+ } else {
+ return new Status(
+ IStatus.ERROR,
+ JavaCore.PLUGIN_ID,
+ -1,
+ "The type name " + name + " is not a valid identifier.",
+ null);
+ }
+ }
+
+ /**
+ * Validate the given method name.
+ * The special names "&lt;init&gt;" and "&lt;clinit&gt;" are not valid.
+ * <p>
+ * The syntax for a method name is defined by Identifer
+ * of MethodDeclarator (JLS2 8.4). For example "println".
+ *
+ * @param name the name of a method
+ * @return a status object with code <code>IStatus.OK</code> if
+ * the given name is valid as a method name, otherwise a status
+ * object indicating what is wrong with the name
+ */
+ public static IStatus validateMethodName(String name) {
+ return validateIdentifier(name);
+ }
+
+ /**
+ * Validate the given package name.
+ * <p>
+ * The syntax of a package name corresponds to PackageName as
+ * defined by PackageDeclaration (JLS2 7.4). For example, <code>"java.lang"</code>.
+ *
+ * @param name the name of a package
+ * @return a status object with code <code>IStatus.OK</code> if
+ * the given name is valid as a package name, otherwise a status
+ * object indicating what is wrong with the name
+ */
+ public static IStatus validatePackageName(String name) {
+ if (name == null) {
+ return new Status(
+ IStatus.ERROR,
+ JavaCore.PLUGIN_ID,
+ -1,
+ "A package name must not be null",
+ null);
+ }
+ int length;
+ if ((length = name.length()) == 0) {
+ return new Status(
+ IStatus.ERROR,
+ JavaCore.PLUGIN_ID,
+ -1,
+ "A package name must not be empty",
+ null);
+ }
+ if (name.charAt(0) == fgDot || name.charAt(length - 1) == fgDot) {
+ return new Status(
+ IStatus.ERROR,
+ JavaCore.PLUGIN_ID,
+ -1,
+ "A package name cannot start or end with a dot",
+ null);
+ }
+ if (Character.isWhitespace(name.charAt(0))
+ || Character.isWhitespace(name.charAt(name.length() - 1))) {
+ return new Status(
+ IStatus.ERROR,
+ JavaCore.PLUGIN_ID,
+ -1,
+ "A package name must not start or end with a blank",
+ null);
+ ;
+ }
+ int dot = 0;
+ while (dot != -1 && dot < length - 1) {
+ if ((dot = name.indexOf(fgDot, dot + 1)) != -1
+ && dot < length - 1
+ && name.charAt(dot + 1) == fgDot) {
+ return new Status(
+ IStatus.ERROR,
+ JavaCore.PLUGIN_ID,
+ -1,
+ "A package name must not contain two consecutive dots",
+ null);
+ }
+ }
+ StringTokenizer st =
+ new StringTokenizer(name, new String(new char[] { fgDot }));
+ while (st.hasMoreTokens()) {
+ String typeName = st.nextToken();
+ typeName = typeName.trim(); // grammar allows spaces
+ IStatus status = validateIdentifier(typeName);
+ if (!status.isOK()) {
+ return status;
+ }
+ }
+ return new Status(IStatus.OK, JavaCore.PLUGIN_ID, -1, "OK", null);
+ }
+
+}
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
new file mode 100644
index 0000000000..fe8ccc1c76
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
@@ -0,0 +1,1198 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.core.resources.*;
+
+import java.io.*;
+import java.util.*;
+
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.core.builder.*;
+import org.eclipse.jdt.internal.core.*;
+import org.eclipse.jdt.internal.core.builder.impl.*;
+import org.eclipse.jdt.internal.core.builder.impl.ProblemFactory;
+import org.eclipse.jdt.internal.core.search.indexing.*;
+
+/**
+ * The plug-in runtime class for the Java model plug-in containing the core
+ * (UI-free) support for Java projects.
+ * <p>
+ * Like all plug-in runtime classes (subclasses of <code>Plugin</code>), this
+ * class is automatically instantiated by the platform when the plug-in gets
+ * activated. Clients must not attempt to instantiate plug-in runtime classes
+ * directly.
+ * </p>
+ * <p>
+ * The single instance of this class can be accessed from any plug-in declaring
+ * the Java model plug-in as a prerequisite via
+ * <code>JavaCore.getJavaCore()</code>. The Java model plug-in will be activated
+ * automatically if not already active.
+ * </p>
+ */
+public final class JavaCore extends Plugin implements IExecutableExtension {
+
+ private static Plugin JAVA_CORE_PLUGIN = null;
+ /**
+ * The plug-in identifier of the Java core support
+ * (value <code>"org.eclipse.jdt.core"</code>).
+ */
+ public static final String PLUGIN_ID = "org.eclipse.jdt.core";
+ // getPlugin().getDescriptor().getUniqueIdentifier();
+
+ /**
+ * The identifier for the Java builder
+ * (value <code>"org.eclipse.jdt.core.javabuilder"</code>).
+ */
+ public static final String BUILDER_ID = PLUGIN_ID + ".javabuilder";
+
+ /**
+ * The identifier for the Java model
+ * (value <code>"org.eclipse.jdt.core.javamodel"</code>).
+ */
+ public static final String MODEL_ID = PLUGIN_ID + ".javamodel";
+
+ /**
+ * The identifier for the Java nature
+ * (value <code>"org.eclipse.jdt.core.javanature"</code>).
+ * The presence of this nature on a project indicates that it is
+ * Java-capable.
+ *
+ * @see org.eclipse.core.resources.IProject#hasNature
+ */
+ public static final String NATURE_ID = PLUGIN_ID + ".javanature";
+
+ /**
+ * Name of the handle id attribute in a Java marker
+ */
+ private static final String ATT_HANDLE_ID =
+ "org.eclipse.jdt.internal.core.JavaModelManager.handleId";
+
+ /**
+ * Names of recognized configurable options
+ */
+ public static final String COMPILER_LOCAL_VARIABLE_ATTR =
+ PLUGIN_ID + ".compiler.debug.localVariable";
+ // possible values are GENERATE or DO_NOT_GENERATE (default is DO_NOT_GENERATE)
+
+ public static final String COMPILER_LINE_NUMBER_ATTR =
+ PLUGIN_ID + ".compiler.debug.lineNumber";
+ // possible values are GENERATE or DO_NOT_GENERATE (default is GENERATE)
+
+ public static final String COMPILER_SOURCE_FILE_ATTR =
+ PLUGIN_ID + ".compiler.debug.sourceFile";
+ // possible values are GENERATE or DO_NOT_GENERATE (default is GENERATE)
+
+ public static final String COMPILER_CODEGEN_UNUSED_LOCAL =
+ PLUGIN_ID + ".compiler.codegen.unusedLocal";
+ // possible values are PRESERVE or OPTIMIZE_OUT (default is OPTIMIZE_OUT)
+
+ public static final String COMPILER_CODEGEN_TARGET_PLATFORM =
+ PLUGIN_ID + ".compiler.codegen.targetPlatform";
+ // possible values are VERSION_1_1 or VERSION_1_2 (default is VERSION_1_1)
+
+ public static final String COMPILER_PB_UNREACHABLE_CODE =
+ PLUGIN_ID + ".compiler.problem.unreachableCode";
+ // possible values are ERROR or WARNING (default is ERROR)
+
+ public static final String COMPILER_PB_INVALID_IMPORT =
+ PLUGIN_ID + ".compiler.problem.invalidImport";
+ // possible values are ERROR or WARNING (default is ERROR)
+
+ public static final String COMPILER_PB_OVERRIDING_PACKAGE_DEFAULT_METHOD =
+ PLUGIN_ID + ".compiler.problem.overridingPackageDefaultMethod";
+ // possible values are WARNING or IGNORE (default is WARNING)
+
+ public static final String COMPILER_PB_METHOD_WITH_CONSTRUCTOR_NAME =
+ PLUGIN_ID + ".compiler.problem.methodWithConstructorName";
+ // possible values are WARNING or IGNORE (default is WARNING)
+
+ public static final String COMPILER_PB_DEPRECATION =
+ PLUGIN_ID + ".compiler.problem.deprecation";
+ // possible values are WARNING or IGNORE (default is WARNING)
+
+ public static final String COMPILER_PB_HIDDEN_CATCH_BLOCK =
+ PLUGIN_ID + ".compiler.problem.hiddenCatchBlock";
+ // possible values are WARNING or IGNORE (default is WARNING)
+
+ public static final String COMPILER_PB_UNUSED_LOCAL =
+ PLUGIN_ID + ".compiler.problem.unusedLocal";
+ // possible values are WARNING or IGNORE (default is WARNING)
+
+ public static final String COMPILER_PB_UNUSED_PARAMETER =
+ PLUGIN_ID + ".compiler.problem.unusedParameter";
+ // possible values are WARNING or IGNORE (default is WARNING)
+
+ public static final String COMPILER_PB_SYNTHETIC_ACCESS_EMULATION =
+ PLUGIN_ID + ".compiler.problem.syntheticAccessEmulation";
+ // possible values are WARNING or IGNORE (default is IGNORE)
+
+ public static final String CORE_JAVA_BUILD_ORDER =
+ PLUGIN_ID + ".computeJavaBuildOrder";
+ // possible values are COMPUTE or IGNORE (default is COMPUTE)
+ /**
+ * Possible values for configurable options
+ */
+ public static final String GENERATE = "generate";
+ public static final String DO_NOT_GENERATE = "do not generate";
+ public static final String PRESERVE = "preserve";
+ public static final String OPTIMIZE_OUT = "optimize out";
+ public static final String VERSION_1_1 = "1.1";
+ public static final String VERSION_1_2 = "1.2";
+ public static final String ERROR = "error";
+ public static final String WARNING = "warning";
+ public static final String IGNORE = "ignore";
+ public static final String COMPUTE = "compute";
+
+ private static Hashtable ConfigurableOptions;
+ private static Hashtable Variables = new Hashtable(5);
+ /**
+ * Creates the Java core plug-in.
+ */
+ public JavaCore(IPluginDescriptor pluginDescriptor) {
+ super(pluginDescriptor);
+ JAVA_CORE_PLUGIN = this;
+ }
+
+ /**
+ * Adds the given listener for changes to Java elements.
+ * Has no effect if an identical listener is already registered.
+ *
+ * @param listener the listener
+ */
+ public static void addElementChangedListener(IElementChangedListener listener) {
+ JavaModelManager.getJavaModelManager().addElementChangedListener(listener);
+ }
+
+ /**
+ * Configures the given marker attribute map for the given Java element.
+ * Used for markers which denote a Java element rather than a resource.
+ *
+ * @param attributes the mutable marker attribute map (key type: <code>String</code>,
+ * value type: <code>String</code>)
+ * @param element the Java element for which the marker needs to be configured
+ */
+ public static void addJavaElementMarkerAttributes(
+ Map attributes,
+ IJavaElement element) {
+ if (element instanceof IMember)
+ element = ((IMember) element).getClassFile();
+ if (attributes != null && element != null)
+ attributes.put(ATT_HANDLE_ID, element.getHandleIdentifier());
+ }
+
+ /**
+ * Configures the given marker for the given Java element.
+ * Used for markers which denote a Java element rather than a resource.
+ *
+ * @param marker the marker to be configured
+ * @param element the Java element for which the marker needs to be configured
+ * @exception CoreException if the <code>IMarker.setAttribute</code> on the marker fails
+ */
+ public void configureJavaElementMarker(IMarker marker, IJavaElement element)
+ throws CoreException {
+ if (element instanceof IMember)
+ element = ((IMember) element).getClassFile();
+ if (marker != null && element != null)
+ marker.setAttribute(ATT_HANDLE_ID, element.getHandleIdentifier());
+ }
+
+ /**
+ * Returns the Java model element corresponding to the given handle identifier
+ * generated by <code>IJavaElement.getHandleIdentifier()</code>, or
+ * <code>null</code> if unable to create the associated element.
+ */
+ public static IJavaElement create(String handleIdentifier) {
+ if (handleIdentifier == null) {
+ return null;
+ }
+ try {
+ return JavaModelManager.getJavaModelManager().getHandleFromMemento(
+ handleIdentifier);
+ } catch (JavaModelException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the Java element corresponding to the given file, or
+ * <code>null</code> if unable to associate the given file
+ * with a Java element.
+ *
+ * <p>The file must be one of:<ul>
+ * <li>a <code>.java</code> file - the element returned is the corresponding <code>ICompilationUnit</code></li>
+ * <li>a <code>.class</code> file - the element returned is the corresponding <code>IClassFile</code></li>
+ * <li>a <code>.jar</code> file - the element returned is the corresponding <code>IPackageFragmentRoot</code></li>
+ * </ul>
+ * <p>
+ * Creating a Java element has the side effect of creating and opening all of the
+ * element's parents if they are not yet open.
+ */
+ public static IJavaElement create(IFile file) {
+ if (file == null) {
+ return null;
+ }
+ String extension = file.getProjectRelativePath().getFileExtension();
+ if (extension != null) {
+ extension = extension.toLowerCase();
+ if (extension.equals("java")) {
+ return createCompilationUnitFrom(file);
+ } else
+ if (extension.equals("class")) {
+ return createClassFileFrom(file);
+ } else
+ if (extension.equals("jar") || extension.equals("zip")) {
+ return createJarPackageFragmentRootFrom(file);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the package fragment or package fragment root corresponding to the given folder, or
+ * <code>null</code> if unable to associate the given folder with a Java element.
+ * <p>
+ * Note that a package fragment root is returned rather than a default package.
+ * <p>
+ * Creating a Java element has the side effect of creating and opening all of the
+ * element's parents if they are not yet open.
+ */
+ public static IJavaElement create(IFolder folder) {
+ if (folder == null) {
+ return null;
+ }
+ if (folder.getName().indexOf('.') < 0) {
+ JavaProject project = (JavaProject) create(folder.getProject());
+ if (project == null)
+ return null;
+ IJavaElement element = determineIfOnClasspath(folder, project);
+ try {
+ IPath outputLocation = project.getOutputLocation();
+ if (outputLocation == null)
+ return null;
+ if (outputLocation.isPrefixOf(folder.getFullPath())) {
+ if (project.getClasspathEntryFor(outputLocation) != null) {
+ // if the output location is the same as an input location, return the element
+ return element;
+ } else {
+ // otherwise, do not create elements for folders in the output location
+ return null;
+ }
+ } else {
+ return element;
+ }
+ } catch (JavaModelException e) {
+ return null;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the Java project corresponding to the given project, or
+ * <code>null</code> if unable to associate the given project
+ * with a Java project.
+ * <p>
+ * Creating a Java Project has the side effect of creating and opening all of the
+ * project's parents if they are not yet open.
+ */
+ public static IJavaProject create(IProject project) {
+ if (project == null) {
+ return null;
+ }
+ JavaModel javaModel = JavaModelManager.getJavaModel(project.getWorkspace());
+ return javaModel.getJavaProject(project);
+ }
+
+ /**
+ * Returns the Java element corresponding to the given resource, or
+ * <code>null</code> if unable to associate the given resource
+ * with a Java element.
+ * <p>
+ * The resource must be one of:<ul>
+ * <li>a project - the element returned is the corresponding <code>IJavaProject</code></li>
+ * <li>a <code>.java</code> file - the element returned is the corresponding <code>ICompilationUnit</code></li>
+ * <li>a <code>.class</code> file - the element returned is the corresponding <code>IClassFile</code></li>
+ * <li>a <code>.jar</code> file - the element returned is the corresponding <code>IPackageFragmentRoot</code></li>
+ * <li>a folder - the element returned is the corresponding <code>IPackageFragmentRoot</code>
+ * or <code>IPackageFragment</code></li>
+ * <li>the workspace root resource - the element returned is the <code>IJavaModel</code></li>
+ * </ul>
+ * <p>
+ * Creating a Java element has the side effect of creating and opening all of the
+ * element's parents if they are not yet open.
+ */
+ public static IJavaElement create(IResource resource) {
+ if (resource == null) {
+ return null;
+ }
+ int type = resource.getType();
+ switch (type) {
+ case IResource.PROJECT :
+ return create((IProject) resource);
+ case IResource.FILE :
+ return create((IFile) resource);
+ case IResource.FOLDER :
+ return create((IFolder) resource);
+ case IResource.ROOT :
+ return create((IWorkspaceRoot) resource);
+ default :
+ return null;
+ }
+ }
+
+ /**
+ * Returns the Java model.
+ */
+ public static IJavaModel create(IWorkspaceRoot root) {
+ if (root == null) {
+ return null;
+ }
+ return JavaModelManager.getJavaModel(root.getWorkspace());
+ }
+
+ /**
+ * Creates and returns a class file element for
+ * the given <code>.class</code> file. Returns <code>null</code> if unable
+ * to recognize the class file.
+ */
+ public static IClassFile createClassFileFrom(IFile file) {
+ IJavaProject project = (IJavaProject) create(file.getProject());
+ IPackageFragment pkg = (IPackageFragment) determineIfOnClasspath(file, project);
+ if (pkg == null) {
+ // fix for 1FVS7WE
+ // not on classpath - make the root its folder, and a default package
+ IPackageFragmentRoot root = project.getPackageFragmentRoot(file.getParent());
+ pkg = root.getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME);
+ }
+ return pkg.getClassFile(file.getName());
+ }
+
+ /**
+ * Creates and returns a compilation unit element for
+ * the given <code>.java</code> file. Returns <code>null</code> if unable
+ * to recognize the compilation unit.
+ */
+ public static ICompilationUnit createCompilationUnitFrom(IFile file) {
+ IProject fileProject = file.getProject();
+ IJavaProject project = (IJavaProject) create(fileProject);
+ IPackageFragment pkg = (IPackageFragment) determineIfOnClasspath(file, project);
+ if (pkg == null) {
+ // fix for 1FVS7WE
+ // not on classpath - make the root its folder, and a default package
+ IPackageFragmentRoot root = project.getPackageFragmentRoot(file.getParent());
+ pkg = root.getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME);
+ }
+ return pkg.getCompilationUnit(file.getName());
+ }
+
+ /**
+ * Creates and returns a handle for the given JAR file.
+ * The Java model associated with the JAR's project may be
+ * created as a side effect.
+ * Returns <code>null</code> if unable to create a JAR package fragment root.
+ * (for example, if the JAR file represents a non-Java resource)
+ */
+ public static IPackageFragmentRoot createJarPackageFragmentRootFrom(IFile file) {
+ IJavaProject project = (IJavaProject) create(file.getProject());
+
+ // Create a jar package fragment root only if on the classpath
+ IPath resourcePath = file.getFullPath();
+ try {
+ IClasspathEntry[] entries = project.getResolvedClasspath(true);
+ for (int i = 0, length = entries.length; i < length; i++) {
+ IClasspathEntry entry = entries[i];
+ IPath rootPath = entry.getPath();
+ if (rootPath.equals(resourcePath)) {
+ return project.getPackageFragmentRoot(file);
+ }
+ }
+ } catch (JavaModelException e) {
+ }
+ return null;
+ }
+
+ /**
+ * Returns the package fragment root represented by the resource, or
+ * the package fragment the given resource is located in, or <code>null</code>
+ * if the given resource is not on the classpath of the given project.
+ */
+ private static IJavaElement determineIfOnClasspath(
+ IResource resource,
+ IJavaProject project) {
+ IPath resourcePath = resource.getFullPath();
+ try {
+ IClasspathEntry[] entries = project.getResolvedClasspath(true);
+ for (int i = 0; i < entries.length; i++) {
+ IClasspathEntry entry = entries[i];
+ IPath rootPath = entry.getPath();
+ if (rootPath.equals(resourcePath)) {
+ return project.getPackageFragmentRoot(resource);
+ } else
+ if (rootPath.isPrefixOf(resourcePath)) {
+ IPackageFragmentRoot root =
+ ((JavaProject) project).getPackageFragmentRoot(rootPath);
+ IPath pkgPath = resourcePath.removeFirstSegments(rootPath.segmentCount());
+ if (resource.getType() == IResource.FILE) {
+ // if the resource is a file, then remove the last segment which
+ // is the file name in the package
+ pkgPath = pkgPath.removeLastSegments(1);
+ }
+ StringBuffer pkgName = new StringBuffer(IPackageFragment.DEFAULT_PACKAGE_NAME);
+ for (int j = 0, max = pkgPath.segmentCount(); j < max; j++) {
+ String segment = pkgPath.segment(j);
+ if (segment.indexOf('.') >= 0) {
+ return null;
+ }
+ pkgName.append(segment);
+ if (j < pkgPath.segmentCount() - 1) {
+ pkgName.append(".");
+ }
+ }
+ return root.getPackageFragment(pkgName.toString());
+ }
+ }
+ } catch (JavaModelException npe) {
+ return null;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the path held in the given classpath variable.
+ * Returns <node>null</code> if unable to bind.
+ * <p>
+ * Classpath variable values are persisted locally to the workspace, and
+ * are preserved from session to session.
+ * <p>
+ *
+ * @param variableName the name of the classpath variable
+ * @return the path, or <code>null</code> if none
+ * @see #setClasspathVariable
+ */
+ public static IPath getClasspathVariable(String variableName) {
+ return (IPath) Variables.get(variableName);
+ }
+
+ /**
+ * Returns the names of all known classpath variables.
+ * <p>
+ * Classpath variable values are persisted locally to the workspace, and
+ * are preserved from session to session.
+ * <p>
+ *
+ * @return the list of classpath variable names
+ * @see #setClasspathVariable
+ */
+ public static String[] getClasspathVariableNames() {
+ int length = Variables.size();
+ String[] result = new String[length];
+ Enumeration vars = Variables.keys();
+ int index = 0;
+ while (vars.hasMoreElements()) {
+ result[index++] = (String) vars.nextElement();
+ }
+ return result;
+ }
+
+ /**
+ * Answers a set of configurable options with their default values.
+ * These options allow to configure the behavior of the underlying components.
+ *
+ * Recognized options are listed below, optionName = possibleValue1 / possibleValue2
+ * where [] are enclosing the default value of the corresponding option.
+ *
+ * Note: more options might be added in further releases.
+ *
+ * RECOGNIZED OPTIONS:
+ *
+ * COMPILER_LOCAL_VARIABLE_ATTR = [GENERATE] | DO_NOT_GENERATE
+ * When generated, this attribute will enable local variable names to be displayed
+ * in debugger, only in place where variables are definitely assigned
+ * (.class file is then bigger)
+ *
+ * COMPILER_LINE_NUMBER_ATTR = [GENERATE] | DO_NOT_GENERATE
+ * When generated, this attribute will enable source code highlighting in debugger
+ * (.class file is then bigger).
+ *
+ * COMPILER_SOURCE_FILE_ATTR = [GENERATE] | DO_NOT_GENERATE
+ * When generated, this attribute will enable the debugger to present the
+ * corresponding source code.
+ *
+ * COMPILER_CODEGEN_UNUSED_LOCAL = [PRESERVE] | OPTIMIZE_OUT
+ * Unless requested to preserve unused local variables (i.e. never read), the
+ * compiler will optimize them out, potentially altering debugging
+ *
+ * COMPILER_CODEGEN_TARGET_PLATFORM = [VERSION_1_1] | VERSION_1_2
+ * Generate .class files either backward compatible with JVM 1.1 or only executable
+ * on JVM 1.2 and later
+ *
+ * COMPILER_PB_UNREACHABLE_CODE = [ERROR] | WARNING
+ * Unreachable code can either be reported as an error or a warning
+ *
+ * COMPILER_PB_INVALID_IMPORT = [ERROR] | WARNING
+ * An import statement that cannot be resolved might either be reported
+ * either as an error or as a warning
+ *
+ * COMPILER_PB_OVERRIDING_PACKAGE_DEFAULT_METHOD = [WARNING] | IGNORE
+ * A package default method is not visible in a different package, and thus
+ * cannot be overriden. When enabling this option, the compiler will signal
+ * such scenarii.
+ *
+ * COMPILER_PB_METHOD_WITH_CONSTRUCTOR_NAME = [WARNING] | IGNORE
+ * Naming a method with a constructor name is generally considered poor
+ * style programming. When enabling this option, the compiler will signal such
+ * scenarii
+ *
+ * COMPILER_PB_DEPRECATION = [WARNING] | IGNORE
+ * When enabled, the compiler will signal use of deprecated API.
+ *
+ * COMPILER_PB_HIDDEN_CATCH_BLOCK = [WARNING] | IGNORE
+ * Locally to a try statement, some catch blocks may hide others
+ * (e.g. try { throw new java.io.CharConversionException();
+ * } catch (java.io.CharConversionException e) {
+ * } catch (java.io.IOException e) {}).
+ * When enabling this option, the compiler will issue a warning for hidden catch
+ * blocks corresponding to checked exceptions
+ *
+ * COMPILER_PB_UNUSED_LOCAL = WARNING | [IGNORE]
+ * When enabled, the compiler will issue a warning for unused local variables
+ * (i.e. variables never read from)
+ *
+ * COMPILER_PB_UNUSED_PARAMETER = WARNING | [IGNORE]
+ * When enabled, the compiler will issue a warning for unused method parameters
+ * (i.e. parameters never read from)
+ *
+ * COMPILER_PB_SYNTHETIC_ACCESS_EMULATION = WARNING | [IGNORE]
+ * When enabled, the compiler will issue a warning whenever it emulates access
+ * to a non-accessible member of an enclosing type
+ *
+ * CORE_JAVA_BUILD_ORDER = [COMPUTE] | IGNORE
+ * When enabled, the build order is automatically reflecting the classpath on each
+ * classpath change action. It can still be modified manually afterwards.
+ */
+
+ public static Hashtable getDefaultOptions() {
+
+ Hashtable defaultOptions = new Hashtable(10);
+
+ // Compiler settings
+ defaultOptions.put(COMPILER_LOCAL_VARIABLE_ATTR, GENERATE);
+ defaultOptions.put(COMPILER_LINE_NUMBER_ATTR, GENERATE);
+ defaultOptions.put(COMPILER_SOURCE_FILE_ATTR, GENERATE);
+ defaultOptions.put(COMPILER_CODEGEN_UNUSED_LOCAL, PRESERVE);
+ defaultOptions.put(COMPILER_CODEGEN_TARGET_PLATFORM, VERSION_1_1);
+ defaultOptions.put(COMPILER_PB_UNREACHABLE_CODE, ERROR);
+ defaultOptions.put(COMPILER_PB_INVALID_IMPORT, ERROR);
+ defaultOptions.put(COMPILER_PB_OVERRIDING_PACKAGE_DEFAULT_METHOD, WARNING);
+ defaultOptions.put(COMPILER_PB_METHOD_WITH_CONSTRUCTOR_NAME, WARNING);
+ defaultOptions.put(COMPILER_PB_DEPRECATION, WARNING);
+ defaultOptions.put(COMPILER_PB_HIDDEN_CATCH_BLOCK, WARNING);
+ defaultOptions.put(COMPILER_PB_UNUSED_LOCAL, IGNORE);
+ defaultOptions.put(COMPILER_PB_UNUSED_PARAMETER, IGNORE);
+ defaultOptions.put(COMPILER_PB_SYNTHETIC_ACCESS_EMULATION, IGNORE);
+
+ // JavaCore settings
+ defaultOptions.put(CORE_JAVA_BUILD_ORDER, IGNORE);
+
+ return defaultOptions;
+ }
+
+ /**
+ * Returns the single instance of the Java core plug-in runtime class.
+ * Equivalent to <code>(JavaCore) getPlugin()</code>.
+ */
+ public static JavaCore getJavaCore() {
+ return (JavaCore) getPlugin();
+ }
+
+ /**
+ * Returns the <code>IJavaProject</code> associated with the
+ * given <code>IProject</code>, or <code>null</code> if the
+ * project does not have a Java nature.
+ */
+ private IJavaProject getJavaProject(IProject project) {
+ try {
+ if (project.hasNature(NATURE_ID)) {
+ JavaModel model = JavaModelManager.getJavaModel(project.getWorkspace());
+ if (model != null) {
+ return model.getJavaProject(project);
+ }
+ }
+ } catch (CoreException e) {
+ }
+ return null;
+ }
+
+ /**
+ * Answers a copy of the current set of configurable options supported by the Java core.
+ * These options allow to configure the behavior of the underlying components.
+ *
+ * Changes on the set of options are not committed until invoking <code>JavaCore.setOptions</code>
+ *
+ * For a list of recognized options, refer to <code>JavaCore.getDefaultOptions</code>
+ */
+ public static Hashtable getOptions() {
+
+ if (ConfigurableOptions == null)
+ return ConfigurableOptions = getDefaultOptions();
+ return (Hashtable) ConfigurableOptions.clone();
+ }
+
+ /**
+ * Returns the single instance of the Java core plug-in runtime class.
+ */
+ public static Plugin getPlugin() {
+ return JAVA_CORE_PLUGIN;
+ }
+
+ /**
+ * This is a helper method which returns the resolved classpath entry denoted
+ * by a given entry (if it is a variable entry). It is obtained by resolving the variable
+ * reference in the first segment. Returns <node>null</code> if unable to resolve using
+ * the following algorithm:
+ * <ul>
+ * <li> if variable segment cannot be resolved, returns <code>null</code></li>
+ * <li> finds a project, JAR or binary folder in the workspace at the resolved path location</li>
+ * <li> if none finds an external JAR file or folder outside the workspace at the resolved path location </li>
+ * <li> if none returns <code>null</code></li>
+ * </ul>
+ * <p>
+ * Variable source attachment path and root path are also resolved and recorded in the resulting classpath entry.
+ * <p>
+ * @return the resolved library or project classpath entry, or <code>null</code>
+ * if the given variable entry could not be resolved to a valid classpath entry
+ */
+ public static IClasspathEntry getResolvedClasspathEntry(IClasspathEntry entry) {
+
+ if (entry.getEntryKind() != IClasspathEntry.CPE_VARIABLE)
+ return entry;
+
+ IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
+ IPath resolvedPath = JavaCore.getResolvedVariablePath(entry.getPath());
+ if (resolvedPath == null)
+ return null;
+
+ Object target = JavaModel.getTarget(workspaceRoot, resolvedPath);
+ if (target == null)
+ return null;
+
+ // inside the workspace
+ if (target instanceof IResource) {
+ IResource resolvedResource = (IResource) target;
+ if (resolvedResource != null) {
+ switch (resolvedResource.getType()) {
+ case IResource.PROJECT :
+ return JavaCore.newProjectEntry(resolvedPath); // internal project
+ case IResource.FILE :
+ String extension = resolvedResource.getFileExtension();
+ if ("jar".equalsIgnoreCase(extension)
+ || "zip".equalsIgnoreCase(extension)) { // internal binary archive
+ return JavaCore.newLibraryEntry(
+ resolvedPath,
+ getResolvedVariablePath(entry.getSourceAttachmentPath()),
+ getResolvedVariablePath(entry.getSourceAttachmentRootPath()));
+ }
+ break;
+ case IResource.FOLDER : // internal binary folder
+ return JavaCore.newLibraryEntry(
+ resolvedPath,
+ getResolvedVariablePath(entry.getSourceAttachmentPath()),
+ getResolvedVariablePath(entry.getSourceAttachmentRootPath()));
+ }
+ }
+ }
+ // outside the workspace
+ if (target instanceof File) {
+ File externalFile = (File) target;
+ if (externalFile.isFile()) {
+ String fileName = externalFile.getName().toLowerCase();
+ if (fileName.endsWith(".jar")
+ || fileName.endsWith(".zip")) { // external binary archive
+ return JavaCore.newLibraryEntry(
+ resolvedPath,
+ getResolvedVariablePath(entry.getSourceAttachmentPath()),
+ getResolvedVariablePath(entry.getSourceAttachmentRootPath()));
+ }
+ } else { // external binary folder
+ return JavaCore.newLibraryEntry(
+ resolvedPath,
+ getResolvedVariablePath(entry.getSourceAttachmentPath()),
+ getResolvedVariablePath(entry.getSourceAttachmentRootPath()));
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Resolve a variable path (helper method)
+ */
+ public static IPath getResolvedVariablePath(IPath variablePath) {
+
+ if (variablePath == null)
+ return null;
+ int count = variablePath.segmentCount();
+ if (count == 0)
+ return null;
+
+ // lookup variable
+ String variableName = variablePath.segment(0);
+ IPath resolvedPath = JavaCore.getClasspathVariable(variableName);
+ if (resolvedPath == null || resolvedPath.isEmpty())
+ return null;
+
+ // append path suffix
+ if (count > 1) {
+ resolvedPath = resolvedPath.append(variablePath.removeFirstSegments(1));
+ }
+ return resolvedPath;
+ }
+
+ /**
+ * Returns whether the given marker references the given Java element.
+ * Used for markers which denote a Java element rather than a resource.
+ *
+ * @param element the element
+ * @param marker the marker
+ * @return <code>true</code> if the marker references the element
+ * @exception CoreException if the <code>IMarker.getAttribute</code> on the marker fails
+ */
+ public static boolean isReferencedBy(IJavaElement element, IMarker marker)
+ throws CoreException {
+ if (element instanceof IMember)
+ element = ((IMember) element).getClassFile();
+ return (
+ element != null
+ && marker != null
+ && element.getHandleIdentifier().equals(marker.getAttribute(ATT_HANDLE_ID)));
+ }
+
+ /**
+ * Returns whether the given marker delta references the given Java element.
+ * Used for markers deltas which denote a Java element rather than a resource.
+ *
+ * @param element the element
+ * @param markerDelta the marker delta
+ * @return <code>true</code> if the marker delta references the element
+ * @exception CoreException if the <code>IMarkerDelta.getAttribute</code> on the marker delta fails
+ */
+ public static boolean isReferencedBy(
+ IJavaElement element,
+ IMarkerDelta markerDelta)
+ throws CoreException {
+ if (element instanceof IMember)
+ element = ((IMember) element).getClassFile();
+ return element != null
+ && markerDelta != null
+ && element.getHandleIdentifier().equals(markerDelta.getAttribute(ATT_HANDLE_ID));
+ }
+
+ /**
+ * Creates and returns a new classpath entry of kind <code>CPE_LIBRARY</code> for the JAR or folder
+ * identified by the given absolute path. This specifies that all package fragments within the root
+ * will have children of type <code>IClassFile</code>.
+ * <p>
+ * A library entry is used to denote a prerequisite JAR or root folder containing binaries.
+ * The target JAR or folder can either be defined internally to the workspace (absolute path relative
+ * to the workspace root) or externally to the workspace (absolute path in the file system).
+ *
+ * e.g. Here are some examples of binary path usage<ul>
+ * <li><code> "c:/jdk1.2.2/jre/lib/rt.jar" </code> - reference to an external JAR</li>
+ * <li><code> "/Project/someLib.jar" </code> - reference to an internal JAR </li>
+ * <li><code> "c:/classes/" </code> - reference to an external binary folder</li>
+ * </ul>
+ * Note that this operation does not attempt to validate or access the
+ * resources at the given paths.
+ * <p>
+ * @param path the absolute path of the binary archive
+ * @param sourceAttachmentPath the absolute path of the corresponding source archive,
+ * or <code>null</code> if none
+ * @param sourceAttachmentRootPath the location of the root within the source archive
+ * or <code>null</code> if <code>archivePath</code> is also <code>null</code>
+ */
+
+ public static IClasspathEntry newLibraryEntry(
+ IPath path,
+ IPath sourceAttachmentPath,
+ IPath sourceAttachmentRootPath) {
+ Assert.isTrue(path.isAbsolute(), "path for IClasspathEntry must be absolute");
+ return new ClasspathEntry(
+ IPackageFragmentRoot.K_BINARY,
+ IClasspathEntry.CPE_LIBRARY,
+ JavaProject.canonicalizedPath(path),
+ sourceAttachmentPath,
+ sourceAttachmentRootPath);
+ }
+
+ /**
+ * Creates and returns a new classpath entry of kind <code>CPE_PROJECT</code>
+ * for the project identified by the given absolute path.
+ * <p>
+ * A project entry is used to denote a prerequisite project on a classpath.
+ * The referenced project will be contributed as a whole, either as sources (in the Java Model, it
+ * contributes all its package fragment roots) or as binaries (when building, it contributes its
+ * whole output location).
+ * <p>
+ * A project reference allows to indirect through another project, independently from its internal layout.
+ * <p>
+ * The prerequisite project is referred to using an absolute path relative to the workspace root.
+ */
+ public static IClasspathEntry newProjectEntry(IPath path) {
+ Assert.isTrue(path.isAbsolute(), "path for IClasspathEntry must be absolute");
+ return new ClasspathEntry(
+ IPackageFragmentRoot.K_SOURCE,
+ IClasspathEntry.CPE_PROJECT,
+ path,
+ null,
+ null);
+ }
+
+ /**
+ * Returns a new empty region.
+ */
+ public static IRegion newRegion() {
+ return new Region();
+ }
+
+ /**
+ * Creates and returns a new classpath entry of kind <code>CPE_SOURCE</code> for the project's source folder
+ * identified by the given absolute path. This specifies that all package fragments within the root will
+ * have children of type <code>ICompilationUnit</code>.
+ * <p>
+ * The source folder is referred to using an absolute path relative to the workspace root, e.g. <code>"/Project/src"</code>.
+ * <p>
+ * A source entry is used to setup the internal source layout of a project, and cannot be used out of the
+ * context of the containing project (a source entry "Proj1/src" cannot be used on the classpath of Proj2).
+ */
+ public static IClasspathEntry newSourceEntry(IPath path) {
+ Assert.isTrue(path.isAbsolute(), "path for IClasspathEntry must be absolute");
+ return new ClasspathEntry(
+ IPackageFragmentRoot.K_SOURCE,
+ IClasspathEntry.CPE_SOURCE,
+ path,
+ null,
+ null);
+ }
+
+ /**
+ * Creates and returns a new classpath entry of kind <code>CPE_VARIABLE</code>
+ * for the given path. The first segment of the the path is the name of a classpath variable.
+ * The trailing segments of the path will be appended to resolved variable path.
+ * <p>
+ * A variable entry allows to express indirect references on a classpath to other projects or libraries,
+ * depending on what the classpath variable is referring.
+ * <p>
+ * e.g. Here are some examples of variable path usage<ul>
+ * <li><"JDTCORE" where variable <code>JDTCORE</code> is
+ * bound to "c:/jars/jdtcore.jar". The resoved classpath entry is denoting the library "c:\jars\jdtcore.jar"</li>
+ * <li> "JDTCORE" where variable <code>JDTCORE</code> is
+ * bound to "/Project_JDTCORE". The resoved classpath entry is denoting the project "/Project_JDTCORE"</li>
+ * <li> "PLUGINS/com.example/example.jar" where variable <code>PLUGINS</code>
+ * is bound to "c:/eclipse/plugins". The resolved classpath entry is denoting the library "c:/eclipse/plugins/com.example/example.jar"</li>
+ * </ul>
+ * <p>
+ * Note that this operation does not attempt to validate classpath variables
+ * or access the resources at the given paths.
+ * <p>
+ * @param variablePath the path of the binary archive; first segment is the
+ * name of a classpath variable
+ * @param variableSourceAttachmentPath the path of the corresponding source archive,
+ * or <code>null</code> if none; if present, the first segment is the
+ * name of a classpath variable (not necessarily the same variable
+ * as the one that begins <code>variablePath</code>)
+ * @param sourceAttachmentRootPath the location of the root within the source archive
+ * or <code>null</code> if <code>archivePath</code> is also <code>null</code>
+ */
+ public static IClasspathEntry newVariableEntry(
+ IPath variablePath,
+ IPath variableSourceAttachmentPath,
+ IPath sourceAttachmentRootPath) {
+ Assert.isTrue(
+ variablePath != null && variablePath.segmentCount() >= 1,
+ "invalid variable path");
+ return new ClasspathEntry(
+ IPackageFragmentRoot.K_SOURCE,
+ IClasspathEntry.CPE_VARIABLE,
+ variablePath,
+ variableSourceAttachmentPath,
+ sourceAttachmentRootPath);
+ }
+
+ /**
+ * Removed the given classpath variable. Does nothing if no value was
+ * set for this classpath variable.
+ * <p>
+ * This functionality cannot be used while the resource tree is locked.
+ * <p>
+ * Classpath variable values are persisted locally to the workspace, and
+ * are preserved from session to session.
+ * <p>
+ *
+ * @param variableName the name of the classpath variable
+ * @see #setClasspathVariable
+ *
+ * @deprecated - use version with extra IProgressMonitor
+ */
+ public static void removeClasspathVariable(String variableName) {
+
+ removeClasspathVariable(variableName, null);
+ }
+
+ /**
+ * Removed the given classpath variable. Does nothing if no value was
+ * set for this classpath variable.
+ * <p>
+ * This functionality cannot be used while the resource tree is locked.
+ * <p>
+ * Classpath variable values are persisted locally to the workspace, and
+ * are preserved from session to session.
+ * <p>
+ *
+ * @param variableName the name of the classpath variable
+ * @param monitor the progress monitor to report progress
+ * @see #setClasspathVariable
+ */
+ public static void removeClasspathVariable(
+ String variableName,
+ IProgressMonitor monitor) {
+
+ try {
+ updateVariableValue(variableName, null, monitor);
+ } catch (JavaModelException e) {
+ }
+ }
+
+ /**
+ * Removes the given element changed listener.
+ * Has no affect if an identical listener is not registered.
+ *
+ * @param listener the listener
+ */
+ public static void removeElementChangedListener(IElementChangedListener listener) {
+ JavaModelManager.getJavaModelManager().removeElementChangedListener(listener);
+ }
+
+ /**
+ * Sets the value of the given classpath variable.
+ * The path must have at least one segment.
+ * <p>
+ * This functionality cannot be used while the resource tree is locked.
+ * <p>
+ * Classpath variable values are persisted locally to the workspace, and
+ * are preserved from session to session.
+ * <p>
+ *
+ * @param variableName the name of the classpath variable
+ * @param path the path
+ * @see #getClasspathVariable
+ *
+ * @deprecated - use API with IProgressMonitor
+ */
+ public static void setClasspathVariable(String variableName, IPath path)
+ throws JavaModelException {
+
+ setClasspathVariable(variableName, path, null);
+ }
+
+ /**
+ * Sets the value of the given classpath variable.
+ * The path must have at least one segment.
+ * <p>
+ * This functionality cannot be used while the resource tree is locked.
+ * <p>
+ * Classpath variable values are persisted locally to the workspace, and
+ * are preserved from session to session.
+ * <p>
+ *
+ * @param variableName the name of the classpath variable
+ * @param path the path
+ * @param monitor a monitor to report progress
+ * @see #getClasspathVariable
+ */
+ public static void setClasspathVariable(
+ String variableName,
+ IPath path,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+
+ Assert.isTrue(path != null, "variable path cannot be null");
+ updateVariableValue(variableName, path, monitor);
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IExecutableExtension.
+ * Record any necessary initialization data from the plugin.
+ */
+ public void setInitializationData(
+ IConfigurationElement cfig,
+ String propertyName,
+ Object data)
+ throws CoreException {
+ }
+
+ /**
+ * Set current set of configurable options supported by the Java core.
+ * These options allow to configure the behavior of the underlying components.
+ *
+ * For a list of recognized options, refer to <code>JavaCore.getDefaultOptions</code>
+ */
+ public static void setOptions(Hashtable configurableOptions) {
+ ConfigurableOptions = (Hashtable) configurableOptions.clone();
+ }
+
+ /**
+ * Shutdown the JavaCore plugin
+ * <p>
+ * De-registers the JavaModelManager as a resource changed listener and save participant.
+ * <p>
+ * @see Plugin#shutdown
+ */
+ public void shutdown() {
+
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ workspace.removeResourceChangeListener(JavaModelManager.getJavaModelManager());
+ workspace.removeSaveParticipant(this);
+
+ ((JavaModelManager) JavaModelManager.getJavaModelManager()).shutdown();
+ }
+
+ /**
+ * Initiate the background indexing process.
+ * This should be deferred after the plugin activation.
+ */
+ private void startIndexing() {
+
+ JavaModelManager manager =
+ (JavaModelManager) JavaModelManager.getJavaModelManager();
+ IndexManager indexManager = manager.getIndexManager();
+ if (indexManager != null)
+ indexManager.reset();
+ /*
+ // if there is a desktop defer the start of the indexing by posting a runnable
+ if (getDesktopPlugin() != null) {
+ IDesktop desktop= getDesktop();
+ ApplicationWindow window= (ApplicationWindow) desktop.getActiveDesktopWindow();
+ Display display= null;
+ if (window != null)
+ display= window.getDisplay();
+ if (display != null) {
+ display.asyncExec(start);
+ return;
+ }
+ }
+ */
+ }
+
+ /**
+ * Startup of the JavaCore plugin
+ * <p>
+ * Registers the JavaModelManager as a resource changed listener and save participant.
+ * Starts the background indexing, and restore saved classpath variable values.
+ * <p>
+ * @see Plugin#startup
+ */
+ public void startup() {
+ JavaModelManager manager = JavaModelManager.getJavaModelManager();
+ try {
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ IndexManager indexManager = manager.getIndexManager();
+ if (indexManager != null) {
+ // need to initialize workbench now since a query may be done before indexing starts
+ indexManager.workspace = workspace;
+ }
+ workspace.addResourceChangeListener(
+ manager,
+ IResourceChangeEvent.PRE_AUTO_BUILD
+ | IResourceChangeEvent.POST_CHANGE
+ | IResourceChangeEvent.PRE_DELETE
+ | IResourceChangeEvent.PRE_CLOSE);
+
+ startIndexing();
+
+ workspace.addSaveParticipant(this, manager);
+ manager.loadVariables();
+ } catch (CoreException e) {
+ } catch (RuntimeException e) {
+ manager.shutdown();
+ throw e;
+ }
+ }
+
+ /**
+ * Internal updating of a variable value (null path meaning removal).
+ */
+ private static void updateVariableValue(
+ String variableName,
+ IPath path,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+
+ // gather classpath information for updating
+ Hashtable affectedProjects = new Hashtable(5);
+ JavaModelManager manager = JavaModelManager.getJavaModelManager();
+ try {
+ IJavaModel model = manager.getJavaModel();
+ if (model != null) {
+ IJavaProject[] projects = model.getJavaProjects();
+ nextProject : for (int i = 0, max = projects.length; i < max; i++) {
+ IClasspathEntry[] entries = projects[i].getRawClasspath();
+ for (int j = 0, cplength = entries.length; j < cplength; j++) {
+ IClasspathEntry oldEntry = entries[j];
+ if (oldEntry.getEntryKind() == IClasspathEntry.CPE_VARIABLE) {
+ IPath sourcePath, sourceRootPath;
+ if (oldEntry.getPath().segment(0).equals(variableName)
+ || ((sourcePath = oldEntry.getSourceAttachmentPath()) != null
+ && sourcePath.segment(0).equals(variableName))
+ || ((sourceRootPath = oldEntry.getSourceAttachmentRootPath()) != null
+ && sourceRootPath.segment(0).equals(variableName))) {
+ affectedProjects.put(projects[i], projects[i].getResolvedClasspath(true));
+ continue nextProject;
+ }
+ }
+ }
+ }
+ }
+ } catch (JavaModelException e) {
+ }
+
+ if (path == null) {
+ Variables.remove(variableName);
+ } else {
+ // new variable value is assigned
+ Variables.put(variableName, path);
+ }
+
+ if (!affectedProjects.isEmpty()) {
+ boolean wasFiring = manager.isFiring();
+ try {
+ if (wasFiring)
+ manager.stopDeltas();
+ // propagate classpath change
+ Enumeration projectsToUpdate = affectedProjects.keys();
+ while (projectsToUpdate.hasMoreElements()) {
+ JavaProject project = (JavaProject) projectsToUpdate.nextElement();
+ project
+ .setRawClasspath(
+ project.getRawClasspath(),
+ monitor,
+ project.getWorkspace().isAutoBuilding(),
+ // force build if in auto build mode
+ (IClasspathEntry[]) affectedProjects.get(project));
+ }
+ } finally {
+ manager.mergeDeltas();
+ if (wasFiring) {
+ manager.startDeltas();
+ manager.fire();
+ }
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaModelException.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaModelException.java
new file mode 100644
index 0000000000..336ff45d97
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaModelException.java
@@ -0,0 +1,124 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+
+import org.eclipse.jdt.internal.core.JavaModelStatus;
+
+/**
+ * A checked exception representing a failure in the Java model.
+ * Java model exceptions contain a Java-specific status object describing the
+ * cause of the exception.
+ * <p>
+ * This class is not intended to be subclassed by clients. Instances of this
+ * class are automatically created by the Java model when problems arise, so
+ * there is generally no need for clients to create instances.
+ * </p>
+ *
+ * @see IJavaModelStatus
+ * @see IJavaModelStatusConstants
+ */
+public class JavaModelException extends CoreException {
+ /**
+ * Creates a Java model exception that wrappers the given <code>Throwable</code>.
+ * The exception contains a Java-specific status object with severity
+ * <code>IStatus.ERROR</code> and the given status code.
+ *
+ * @param exception the <code>Throwable</code>
+ * @param code one of the Java-specific status codes declared in
+ * <code>IJavaModelStatusConstants</code>
+ * @return the new Java model exception
+ * @see IJavaModelStatusConstants
+ * @see org.eclipse.core.runtime.IStatus#ERROR
+ */
+ public JavaModelException(Throwable e, int code) {
+ this(new JavaModelStatus(code, e));
+ }
+
+ /**
+ * Creates a Java model exception for the given <code>CoreException</code>.
+ * Equivalent to
+ * <code>JavaModelException(exception,IJavaModelStatusConstants.CORE_EXCEPTION</code>.
+ *
+ * @param exception the <code>CoreException</code>
+ * @return the new Java model exception
+ */
+ public JavaModelException(CoreException exception) {
+ this(new JavaModelStatus(exception));
+ }
+
+ /**
+ * Creates a Java model exception for the given Java-specific status object.
+ *
+ * @param status the Java-specific status object
+ * @return the new Java model exception
+ */
+ public JavaModelException(IJavaModelStatus status) {
+ super(status);
+ }
+
+ /**
+ * Returns the underlying <code>Throwable</code> that caused the failure.
+ *
+ * @return the wrappered <code>Throwable</code>, or <code>null</code> if the
+ * direct case of the failure was at the Java model layer
+ */
+ public Throwable getException() {
+ return getStatus().getException();
+ }
+
+ /**
+ * Returns the Java model status object for this exception.
+ * Equivalent to <code>(IJavaModelStatus) getStatus()</code>.
+ *
+ * @return a status object
+ */
+ public IJavaModelStatus getJavaModelStatus() {
+ return (IJavaModelStatus) getStatus();
+ }
+
+ /**
+ * Returns whether this exception indicates that a Java model element does not
+ * exist. Such exceptions have a status with a code of
+ * <code>IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST</code>.
+ * This is a convenience method.
+ *
+ * @return <code>true</code> if this exception indicates that a Java model
+ * element does not exist
+ * @see IJavaModelStatus#isDoesNotExist
+ * @see IJavaModelStatusConstants#ELEMENT_DOES_NOT_EXIST
+ */
+ public boolean isDoesNotExist() {
+ IJavaModelStatus javaModelStatus = getJavaModelStatus();
+ return javaModelStatus != null && javaModelStatus.isDoesNotExist();
+ }
+
+ /**
+ * Returns a printable representation of this exception suitable for debugging
+ * purposes only.
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("Java Model Exception: ");
+ if (getException() != null) {
+ if (getException() instanceof CoreException) {
+ CoreException c = (CoreException) getException();
+ buffer.append("Core Exception [code ");
+ buffer.append(c.getStatus().getCode());
+ buffer.append("] ");
+ buffer.append(c.getStatus().getMessage());
+ } else {
+ buffer.append(getException().toString());
+ }
+ } else {
+ buffer.append(getStatus().toString());
+ }
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Signature.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Signature.java
new file mode 100644
index 0000000000..fdec35ba68
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Signature.java
@@ -0,0 +1,908 @@
+package org.eclipse.jdt.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.jdt.internal.compiler.parser.InvalidInputException;
+import org.eclipse.jdt.internal.compiler.parser.Scanner;
+import org.eclipse.jdt.internal.compiler.parser.TerminalSymbols;
+
+/**
+ * Provides methods for encoding and decoding type and method signature strings.
+ * <p>
+ * The syntax for a type signature is:
+ * <pre>
+ * typeSignature ::=
+ * "B" // byte
+ * | "C" // char
+ * | "D" // double
+ * | "F" // float
+ * | "I" // int
+ * | "J" // long
+ * | "S" // short
+ * | "V" // void
+ * | "Z" // boolean
+ * | "L" + binaryTypeName + ";" // resolved named type (i.e., in compiled code)
+ * | "Q" + sourceTypeName + ";" // unresolved named type (i.e., in source code)
+ * | "[" + typeSignature // array of type denoted by typeSignature
+ * </pre>
+ * </p>
+ * <p>
+ * Examples:
+ * <ul>
+ * <li><code>"[[I"</code> denotes <code>int[][]</code></li>
+ * <li><code>"Ljava.lang.String;"</code> denotes <code>java.lang.String</code> in compiled code</li>
+ * <li><code>"QString"</code> denotes <code>String</code> in source code</li>
+ * <li><code>"Qjava.lang.String"</code> denotes <code>java.lang.String</code> in source code</li>
+ * <li><code>"[QString"</code> denotes <code>String[]</code> in source code</li>
+ * </ul>
+ * </p>
+ * <p>
+ * The syntax for a method signature is:
+ * <pre>
+ * methodSignature ::= "(" + paramTypeSignature* + ")" + returnTypeSignature
+ * paramTypeSignature ::= typeSignature
+ * returnTypeSignature ::= typeSignature
+ * </pre>
+ * <p>
+ * Examples:
+ * <ul>
+ * <li><code>"()I"</code> denotes <code>int foo()</code></li>
+ * <li><code>"([Ljava.lang.String;)V"</code> denotes <code>void foo(java.lang.String[])</code> in compiled code</li>
+ * <li><code>"(QString;)QObject;"</code> denotes <code>Object foo(String)</code> in source code</li>
+ * </ul>
+ * </p>
+ * <p>
+ * This class provides static methods and constants only; it is not intended to be
+ * instantiated or subclassed by clients.
+ * </p>
+ */
+public final class Signature {
+
+ /**
+ * Character constant indicating the primitive type boolean in a signature.
+ * Value is <code>'Z'</code>.
+ */
+ public static final char C_BOOLEAN = 'Z';
+
+ /**
+ * Character constant indicating the primitive type byte in a signature.
+ * Value is <code>'B'</code>.
+ */
+ public static final char C_BYTE = 'B';
+
+ /**
+ * Character constant indicating the primitive type char in a signature.
+ * Value is <code>'C'</code>.
+ */
+ public static final char C_CHAR = 'C';
+
+ /**
+ * Character constant indicating the primitive type double in a signature.
+ * Value is <code>'D'</code>.
+ */
+ public static final char C_DOUBLE = 'D';
+
+ /**
+ * Character constant indicating the primitive type float in a signature.
+ * Value is <code>'F'</code>.
+ */
+ public static final char C_FLOAT = 'F';
+
+ /**
+ * Character constant indicating the primitive type int in a signature.
+ * Value is <code>'I'</code>.
+ */
+ public static final char C_INT = 'I';
+
+ /**
+ * Character constant indicating the semicolon in a signature.
+ * Value is <code>';'</code>.
+ */
+ public static final char C_SEMICOLON = ';';
+
+ /**
+ * Character constant indicating the primitive type long in a signature.
+ * Value is <code>'J'</code>.
+ */
+ public static final char C_LONG = 'J';
+
+ /**
+ * Character constant indicating the primitive type short in a signature.
+ * Value is <code>'S'</code>.
+ */
+ public static final char C_SHORT = 'S';
+
+ /**
+ * Character constant indicating result type void in a signature.
+ * Value is <code>'V'</code>.
+ */
+ public static final char C_VOID = 'V';
+
+ /**
+ * Character constant indicating the dot in a signature.
+ * Value is <code>'.'</code>.
+ */
+ public static final char C_DOT = '.';
+
+ /**
+ * Character constant indicating the dollar in a signature.
+ * Value is <code>'$'</code>.
+ */
+ public static final char C_DOLLAR = '$';
+
+ /**
+ * Character constant indicating an array type in a signature.
+ * Value is <code>'['</code>.
+ */
+ public static final char C_ARRAY = '[';
+
+ /**
+ * Character constant indicating the start of a resolved, named type in a
+ * signature. Value is <code>'L'</code>.
+ */
+ public static final char C_RESOLVED = 'L';
+
+ /**
+ * Character constant indicating the start of an unresolved, named type in a
+ * signature. Value is <code>'Q'</code>.
+ */
+ public static final char C_UNRESOLVED = 'Q';
+
+ /**
+ * Character constant indicating the end of a named type in a signature.
+ * Value is <code>';'</code>.
+ */
+ public static final char C_NAME_END = ';';
+
+ /**
+ * Character constant indicating the start of a parameter type list in a
+ * signature. Value is <code>'('</code>.
+ */
+ public static final char C_PARAM_START = '(';
+
+ /**
+ * Character constant indicating the end of a parameter type list in a
+ * signature. Value is <code>')'</code>.
+ */
+ public static final char C_PARAM_END = ')';
+
+ /**
+ * String constant for the signature of the primitive type boolean.
+ * Value is <code>"Z"</code>.
+ */
+ public static final String SIG_BOOLEAN = "Z";
+
+ /**
+ * String constant for the signature of the primitive type byte.
+ * Value is <code>"B"</code>.
+ */
+ public static final String SIG_BYTE = "B";
+
+ /**
+ * String constant for the signature of the primitive type char.
+ * Value is <code>"C"</code>.
+ */
+ public static final String SIG_CHAR = "C";
+
+ /**
+ * String constant for the signature of the primitive type double.
+ * Value is <code>"D"</code>.
+ */
+ public static final String SIG_DOUBLE = "D";
+
+ /**
+ * String constant for the signature of the primitive type float.
+ * Value is <code>"F"</code>.
+ */
+ public static final String SIG_FLOAT = "F";
+
+ /**
+ * String constant for the signature of the primitive type int.
+ * Value is <code>"I"</code>.
+ */
+ public static final String SIG_INT = "I";
+
+ /**
+ * String constant for the signature of the primitive type long.
+ * Value is <code>"J"</code>.
+ */
+ public static final String SIG_LONG = "J";
+
+ /**
+ * String constant for the signature of the primitive type short.
+ * Value is <code>"S"</code>.
+ */
+ public static final String SIG_SHORT = "S";
+
+ /** String constant for the signature of result type void.
+ * Value is <code>"V"</code>.
+ */
+ public static final String SIG_VOID = "V";
+
+ /**
+ * Not instantiable.
+ */
+ private Signature() {
+ }
+
+ /**
+ * Internal - Adds array brackets to a readable type name.
+ */
+ private static String arrayIfy(String typeName, int arrayCount) {
+ if (arrayCount == 0) {
+ return typeName;
+ }
+ StringBuffer sb = new StringBuffer(typeName.length() + arrayCount * 2);
+ sb.append(typeName);
+ for (int i = 0; i < arrayCount; ++i) {
+ sb.append("[]");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Creates a new type signature with the given amount of array nesting added
+ * to the given type signature.
+ *
+ * @param typeSignature the type signature
+ * @param arrayCount the desired number of levels of array nesting
+ * @return the encoded array type signature
+ */
+ public static String createArraySignature(
+ String typeSignature,
+ int arrayCount) {
+ if (arrayCount == 0)
+ return typeSignature;
+ StringBuffer sb = new StringBuffer(typeSignature.length() + arrayCount);
+ for (int i = 0; i < arrayCount; ++i) {
+ sb.append(C_ARRAY);
+ }
+ sb.append(typeSignature);
+ return sb.toString();
+ }
+
+ /**
+ * Creates a method signature from the given parameter and return type
+ * signatures.
+ *
+ * @param parameterTypes the list of parameter type signatures
+ * @param returnType the return type signature
+ * @return the encoded method signature
+ */
+ public static String createMethodSignature(
+ String[] parameterTypes,
+ String returnType) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(C_PARAM_START);
+ for (int i = 0; i < parameterTypes.length; ++i) {
+ sb.append(parameterTypes[i]);
+ }
+ sb.append(C_PARAM_END);
+ sb.append(returnType);
+ return sb.toString();
+ }
+
+ /**
+ * Creates a new type signature from the given type name encoded as a character
+ * array. This method is equivalent to
+ * <code>createTypeSignature(new String(typeName),isResolved)</code>, although
+ * more efficient for callers with character arrays rather than strings.
+ *
+ * @param typeName the possibly qualified type name
+ * @param isResolved <code>true</code> if the type name is to be considered
+ * resolved (for example, a type name from a binary class file), and
+ * <code>false</code> if the type name is to be considered unresolved
+ * (for example, a type name found in source code)
+ * @return the encoded type signature
+ * @see #createTypeSignature(java.lang.String,boolean)
+ */
+ public static String createTypeSignature(char[] typeName, boolean isResolved) {
+ int len = typeName.length;
+ if (typeName[len - 1] != ']') {
+ switch (len) {
+ case 3 :
+ if (typeName[0] == 'i' && typeName[1] == 'n' && typeName[2] == 't')
+ return SIG_INT;
+ break;
+ case 4 :
+ if (typeName[0] == 'v'
+ && typeName[1] == 'o'
+ && typeName[2] == 'i'
+ && typeName[3] == 'd')
+ return SIG_VOID;
+ case 6 :
+ if (typeName[0] == 'S'
+ && typeName[1] == 't'
+ && typeName[2] == 'r'
+ && typeName[3] == 'i'
+ && typeName[4] == 'n'
+ && typeName[5] == 'g')
+ if (!isResolved)
+ return "QString;";
+ break;
+ case 7 :
+ if (typeName[0] == 'b'
+ && typeName[1] == 'o'
+ && typeName[2] == 'o'
+ && typeName[3] == 'l'
+ && typeName[4] == 'e'
+ && typeName[5] == 'a'
+ && typeName[6] == 'n')
+ return SIG_BOOLEAN;
+ }
+ }
+ return createTypeSignature(new String(typeName), isResolved);
+ }
+
+ /**
+ * Creates a new type signature from the given type name.
+ * <p>
+ * For example:
+ * <pre>
+ * <code>
+ * createTypeSignature("int", hucairz) -> "I"
+ * createTypeSignature("java.lang.String", true) -> "Ljava.lang.String;"
+ * createTypeSignature("String", false) -> "QString;"
+ * createTypeSignature("java.lang.String", false) -> "Qjava.lang.String;"
+ * createTypeSignature("int []", false) -> "[I"
+ * </code>
+ * </pre>
+ * </p>
+ *
+ * @param typeName the possibly qualified type name
+ * @param isResolved <code>true</code> if the type name is to be considered
+ * resolved (for example, a type name from a binary class file), and
+ * <code>false</code> if the type name is to be considered unresolved
+ * (for example, a type name found in source code)
+ * @return the encoded type signature
+ */
+ public static String createTypeSignature(String typeName, boolean isResolved) {
+ try {
+ Scanner scanner = new Scanner();
+ scanner.setSourceBuffer(typeName.toCharArray());
+ int token = scanner.getNextToken();
+ StringBuffer sig = new StringBuffer();
+ int arrayCount = 0;
+ boolean primitive = true;
+ switch (token) {
+ case TerminalSymbols.TokenNameIdentifier :
+ sig.append(scanner.getCurrentIdentifierSource());
+ primitive = false;
+ break;
+ case TerminalSymbols.TokenNameboolean :
+ sig.append(Signature.SIG_BOOLEAN);
+ break;
+ case TerminalSymbols.TokenNamebyte :
+ sig.append(Signature.SIG_BYTE);
+ break;
+ case TerminalSymbols.TokenNamechar :
+ sig.append(Signature.SIG_CHAR);
+ break;
+ case TerminalSymbols.TokenNamedouble :
+ sig.append(Signature.SIG_DOUBLE);
+ break;
+ case TerminalSymbols.TokenNamefloat :
+ sig.append(Signature.SIG_FLOAT);
+ break;
+ case TerminalSymbols.TokenNameint :
+ sig.append(Signature.SIG_INT);
+ break;
+ case TerminalSymbols.TokenNamelong :
+ sig.append(Signature.SIG_LONG);
+ break;
+ case TerminalSymbols.TokenNameshort :
+ sig.append(Signature.SIG_SHORT);
+ break;
+ case TerminalSymbols.TokenNamevoid :
+ sig.append(Signature.SIG_VOID);
+ break;
+ default :
+ throw new IllegalArgumentException();
+ }
+ token = scanner.getNextToken();
+ while (!primitive && token == TerminalSymbols.TokenNameDOT) {
+ sig.append(scanner.getCurrentIdentifierSource());
+ token = scanner.getNextToken();
+ if (token == TerminalSymbols.TokenNameIdentifier) {
+ sig.append(scanner.getCurrentIdentifierSource());
+ token = scanner.getNextToken();
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+ while (token == TerminalSymbols.TokenNameLBRACKET) {
+ token = scanner.getNextToken();
+ if (token != TerminalSymbols.TokenNameRBRACKET)
+ throw new IllegalArgumentException();
+ arrayCount++;
+ token = scanner.getNextToken();
+ }
+ if (token != TerminalSymbols.TokenNameEOF)
+ throw new IllegalArgumentException();
+ if (!primitive) {
+ sig.insert(0, isResolved ? C_RESOLVED : C_UNRESOLVED);
+ }
+ if (arrayCount == 0) {
+ if (primitive)
+ return sig.toString();
+ } else {
+ char[] brackets = new char[arrayCount];
+ while (arrayCount-- != 0) {
+ brackets[arrayCount] = C_ARRAY;
+ }
+ sig.insert(0, brackets);
+ }
+ if (!primitive) {
+ sig.append(C_NAME_END);
+ }
+ return sig.toString();
+ } catch (InvalidInputException e) {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Returns the array count (array nesting depth) of the given type signature.
+ *
+ * @param typeSignature the type signature
+ * @return the array nesting depth, or 0 if not an array
+ * @exception IllegalArgumentException if the signature is not syntactically
+ * correct
+ */
+ public static int getArrayCount(String typeSignature)
+ throws IllegalArgumentException {
+ try {
+ int count = 0;
+ while (typeSignature.charAt(count) == C_ARRAY) {
+ ++count;
+ }
+ return count;
+ } catch (StringIndexOutOfBoundsException e) {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Returns the type signature without any array nesting.
+ * <p>
+ * For example:
+ * <pre>
+ * <code>
+ * getElementType("[[I") --> "I".
+ * </code>
+ * </pre>
+ * </p>
+ *
+ * @param typeSignature the type signature
+ * @return the type signature without arrays
+ * @exception IllegalArgumentException if the signature is not syntactically
+ * correct
+ */
+ public static String getElementType(String typeSignature)
+ throws IllegalArgumentException {
+ try {
+ int count = 0;
+ while (typeSignature.charAt(count) == C_ARRAY) {
+ ++count;
+ }
+ return typeSignature.substring(count);
+ } catch (StringIndexOutOfBoundsException e) {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Returns the number of parameter types in the given method signature.
+ *
+ * @param methodSignature the method signature
+ * @return the number of parameters
+ * @exception IllegalArgumentException if the signature is not syntactically
+ * correct
+ */
+ public static int getParameterCount(String methodSignature)
+ throws IllegalArgumentException {
+ try {
+ int count = 0;
+ int i = methodSignature.indexOf(C_PARAM_START) + 1;
+ if (i == 0)
+ throw new IllegalArgumentException();
+ int start = i;
+ for (;;) {
+ char c = methodSignature.charAt(i++);
+ switch (c) {
+ case C_ARRAY :
+ break;
+ case C_BOOLEAN :
+ case C_BYTE :
+ case C_CHAR :
+ case C_DOUBLE :
+ case C_FLOAT :
+ case C_INT :
+ case C_LONG :
+ case C_SHORT :
+ case C_VOID :
+ ++count;
+ break;
+ case C_RESOLVED :
+ case C_UNRESOLVED :
+ i = methodSignature.indexOf(C_SEMICOLON, i) + 1;
+ if (i == 0)
+ throw new IllegalArgumentException();
+ ++count;
+ break;
+ case C_PARAM_END :
+ return count;
+ default :
+ throw new IllegalArgumentException();
+ }
+ }
+ } catch (StringIndexOutOfBoundsException e) {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Extracts the parameter type signatures from the given method signature.
+ *
+ * @param methodSignature the method signature
+ * @return the list of parameter type signatures
+ * @exception IllegalArgumentException if the signature is syntactically
+ * incorrect
+ */
+ public static String[] getParameterTypes(String methodSignature)
+ throws IllegalArgumentException {
+ try {
+ int count = getParameterCount(methodSignature);
+ String[] result = new String[count];
+ if (count == 0)
+ return result;
+ int i = methodSignature.indexOf(C_PARAM_START) + 1;
+ count = 0;
+ int start = i;
+ for (;;) {
+ char c = methodSignature.charAt(i++);
+ switch (c) {
+ case C_ARRAY :
+ // array depth is i - start;
+ break;
+ case C_BOOLEAN :
+ case C_BYTE :
+ case C_CHAR :
+ case C_DOUBLE :
+ case C_FLOAT :
+ case C_INT :
+ case C_LONG :
+ case C_SHORT :
+ case C_VOID :
+ // common case of base types
+ if (i - start == 1) {
+ switch (c) {
+ case C_BOOLEAN :
+ result[count++] = SIG_BOOLEAN;
+ break;
+ case C_BYTE :
+ result[count++] = SIG_BYTE;
+ break;
+ case C_CHAR :
+ result[count++] = SIG_CHAR;
+ break;
+ case C_DOUBLE :
+ result[count++] = SIG_DOUBLE;
+ break;
+ case C_FLOAT :
+ result[count++] = SIG_FLOAT;
+ break;
+ case C_INT :
+ result[count++] = SIG_INT;
+ break;
+ case C_LONG :
+ result[count++] = SIG_LONG;
+ break;
+ case C_SHORT :
+ result[count++] = SIG_SHORT;
+ break;
+ case C_VOID :
+ result[count++] = SIG_VOID;
+ break;
+ }
+ } else {
+ result[count++] = methodSignature.substring(start, i);
+ }
+ start = i;
+ break;
+ case C_RESOLVED :
+ case C_UNRESOLVED :
+ i = methodSignature.indexOf(C_SEMICOLON, i) + 1;
+ if (i == 0)
+ throw new IllegalArgumentException();
+ result[count++] = methodSignature.substring(start, i);
+ start = i;
+ break;
+ case C_PARAM_END :
+ return result;
+ default :
+ throw new IllegalArgumentException();
+ }
+ }
+ } catch (StringIndexOutOfBoundsException e) {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Returns a string containing all but the last segment of the given
+ * dot-separated qualified name. Returns the empty string if it is not qualified.
+ * <p>
+ * For example:
+ * <pre>
+ * <code>
+ * getQualifier("java.lang.Object") -> "java.lang"
+ * getQualifier("Outer.Inner") -> "Outer"
+ * </code>
+ * </pre>
+ * </p>
+ *
+ * @param name the name
+ * @return the qualifier prefix, or the empty string if the name contains no
+ * dots
+ */
+ public static String getQualifier(String name) {
+ int lastDot = name.lastIndexOf(C_DOT);
+ if (lastDot == -1) {
+ return "";
+ }
+ return name.substring(0, lastDot);
+ }
+
+ /**
+ * Extracts the return type from the given method signature.
+ *
+ * @param methodSignature the method signature
+ * @return the type signature of the return type
+ * @exception IllegalArgumentException if the signature is syntactically
+ * incorrect
+ */
+ public static String getReturnType(String methodSignature)
+ throws IllegalArgumentException {
+ int i = methodSignature.lastIndexOf(C_PARAM_END);
+ if (i == -1) {
+ throw new IllegalArgumentException();
+ }
+ return methodSignature.substring(i + 1);
+ }
+
+ /**
+ * Returns the last segment of the given dot-separated qualified name.
+ * Returns the given name if it is not qualified.
+ * <p>
+ * For example:
+ * <pre>
+ * <code>
+ * getSimpleName("java.lang.Object") -> "Object"
+ * </code>
+ * </pre>
+ * </p>
+ *
+ * @param name the name
+ * @return the last segment of the qualified name
+ */
+ public static String getSimpleName(String name) {
+ int lastDot = name.lastIndexOf(C_DOT);
+ if (lastDot == -1) {
+ return name;
+ }
+ return name.substring(lastDot + 1);
+ }
+
+ /**
+ * Returns all segments of the given dot-separated qualified name.
+ * Returns an array with only the given name if it is not qualified.
+ * Returns an empty array if the name is empty.
+ * <p>
+ * For example:
+ * <pre>
+ * <code>
+ * getSimpleNames("java.lang.Object") -> {"java", "lang", "Object"}
+ * getSimpleNames("Object") -> {"Object"}
+ * getSimpleNames("") -> {}
+ * </code>
+ * </pre>
+ *
+ * @param name the name
+ * @return the list of simple names, possibly empty
+ */
+ public static String[] getSimpleNames(String name) {
+ if (name.length() == 0) {
+ return new String[0];
+ }
+ int dot = name.indexOf(C_DOT);
+ if (dot == -1) {
+ return new String[] { name };
+ }
+ int n = 1;
+ while ((dot = name.indexOf(C_DOT, dot + 1)) != -1) {
+ ++n;
+ }
+ String[] result = new String[n + 1];
+ int segStart = 0;
+ for (int i = 0; i < n; ++i) {
+ dot = name.indexOf(C_DOT, segStart);
+ result[i] = name.substring(segStart, dot);
+ segStart = dot + 1;
+ }
+ result[n] = name.substring(segStart);
+ return result;
+ }
+
+ /**
+ * Converts the given array of qualified name segments to a qualified name.
+ * <p>
+ * For example:
+ * <pre>
+ * <code>
+ * toQualifiedName(new String[] {"java", "lang", "Object"}) -> "java.lang.Object"
+ * toQualifiedName(new String[] {"Object"}) -> "Object"
+ * toQualifiedName(new String[0]) -> ""
+ * </code>
+ * </pre>
+ * </p>
+ *
+ * @param segments the list of name segments, possibly empty
+ * @return the dot-separated qualified name, or the empty string
+ */
+ public static String toQualifiedName(String[] segments) {
+ if (segments.length == 0) {
+ return "";
+ }
+ if (segments.length == 1) {
+ return segments[0];
+ }
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < segments.length; ++i) {
+ if (i != 0)
+ sb.append(C_DOT);
+ sb.append(segments[i]);
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Converts the given type signature to a readable string.
+ * <p>
+ * For example:
+ * <pre>
+ * <code>
+ * toString("[Ljava.lang.String;") -> "java.lang.String[]"
+ * toString("I") -> "int"
+ * </code>
+ * </pre>
+ * </p>
+ * <p>
+ * Note: This method assumes that a type signature containing a <code>'$'</code>
+ * is an inner type signature. While this is correct in most cases, someone could
+ * define a non-inner type name containing a <code>'$'</code>. Handling this
+ * correctly in all cases would have required resolving the signature, which
+ * generally not feasible.
+ * </p>
+ *
+ * @param signature the type signature
+ * @return the string representation of the type
+ * @exception IllegalArgumentException if the signature is not syntactically
+ * correct
+ */
+ public static String toString(String signature)
+ throws IllegalArgumentException {
+ try {
+ if (signature.charAt(0) == C_PARAM_START) {
+ return toString(signature, "", null, true, true);
+ }
+ int arrayCount = getArrayCount(signature);
+ switch (signature.charAt(arrayCount)) {
+ case C_BOOLEAN :
+ return arrayIfy("boolean", arrayCount);
+ case C_BYTE :
+ return arrayIfy("byte", arrayCount);
+ case C_CHAR :
+ return arrayIfy("char", arrayCount);
+ case C_DOUBLE :
+ return arrayIfy("double", arrayCount);
+ case C_FLOAT :
+ return arrayIfy("float", arrayCount);
+ case C_INT :
+ return arrayIfy("int", arrayCount);
+ case C_LONG :
+ return arrayIfy("long", arrayCount);
+ case C_SHORT :
+ return arrayIfy("short", arrayCount);
+ case C_VOID :
+ return arrayIfy("void", arrayCount);
+ case C_RESOLVED :
+ case C_UNRESOLVED :
+ int semi = signature.indexOf(C_SEMICOLON, arrayCount + 1);
+ if (semi == -1)
+ throw new IllegalArgumentException();
+
+ /**
+ * Converts '$' separated type signatures into '.' separated type signature.
+ * NOTE: This assumes that the type signature is an inner type signature.
+ * This is true in most cases, but someone can define a non-inner type
+ * name containing a '$'. However to tell the difference, we would have
+ * to resolve the signature, which cannot be done at this point.
+ */
+ String qualifiedTypeName =
+ signature.substring(arrayCount + 1, semi).replace(C_DOLLAR, C_DOT);
+
+ return arrayIfy(qualifiedTypeName, arrayCount);
+ default :
+ throw new IllegalArgumentException();
+ }
+ } catch (StringIndexOutOfBoundsException e) {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Converts the given method signature to a readable string.
+ * <p>
+ * For example:
+ * <pre>
+ * <code>
+ * toString("([Ljava.lang.String;)V", "main", new String[] {"args"}, false, true) -> "void main(String[] args)"
+ * </code>
+ * </pre>
+ * </p>
+ *
+ * @param methodSignature the method signature to convert
+ * @param methodName the name of the method to insert in the result, or
+ * <code>null</code> if no method name is to be included
+ * @param parameterNames the parameter names to insert in the result, or
+ * <code>null</code> if no parameter names are to be included; if supplied,
+ * the number of parameter names must match that of the method signature
+ * @param fullyQualifyTypeNames <code>true</code> if type names should be fully
+ * qualified, and <code>false</code> to use only simple names
+ * @param includeReturnType <code>true</code> if the return type is to be
+ * included
+ * @return the string representation of the method signature
+ */
+ public static String toString(
+ String methodSignature,
+ String methodName,
+ String[] parameterNames,
+ boolean fullyQualifyTypeNames,
+ boolean includeReturnType) {
+ StringBuffer sb = new StringBuffer();
+ String[] paramTypes = getParameterTypes(methodSignature);
+ if (includeReturnType) {
+ String returnType = getReturnType(methodSignature);
+ if (returnType.length() != 0) {
+ sb.append(toString(returnType));
+ sb.append(' ');
+ }
+ }
+ if (methodName != null)
+ sb.append(methodName);
+ sb.append(C_PARAM_START);
+ for (int i = 0; i < paramTypes.length; ++i) {
+ if (i != 0)
+ sb.append(", ");
+ String readableParamType = toString(paramTypes[i]);
+ if (!fullyQualifyTypeNames) {
+ int lastDot = readableParamType.lastIndexOf(C_DOT);
+ if (lastDot != -1) {
+ readableParamType = readableParamType.substring(lastDot + 1);
+ }
+ }
+ sb.append(readableParamType);
+ if (parameterNames != null) {
+ sb.append(' ');
+ sb.append(parameterNames[i]);
+ }
+ }
+ sb.append(C_PARAM_END);
+ return sb.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/ICodeSnippetRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/ICodeSnippetRequestor.java
new file mode 100644
index 0000000000..8fb9c58aa1
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/ICodeSnippetRequestor.java
@@ -0,0 +1,180 @@
+package org.eclipse.jdt.core.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.jdt.internal.eval.EvaluationConstants;
+
+/**
+ * A code snippet requestor implements a callback interface for installing
+ * the class files for a code snippet on the target and running it.
+ * In addition, it receives compilation problems detected during code snippet
+ * compilation.
+ * <p>
+ * Clients may implement this interface to provide a bridge a running Java VM.
+ * </p>
+ *
+ * @see IEvaluationContext#evaluateCodeSnippet
+ */
+public interface ICodeSnippetRequestor {
+
+ /*
+ * RETRIEVING THE VALUE OF THE CODE SNIPPET AFTER EVALUATION
+ */
+
+ /**
+ * The prefix of fields that represent the local variables in a snippet
+ * class.
+ */
+ public static final String LOCAL_VAR_PREFIX =
+ new String(EvaluationConstants.LOCAL_VAR_PREFIX);
+
+ /**
+ * The name of the field that represent 'this' in a snippet class
+ * instance.
+ */
+ public static final String DELEGATE_THIS =
+ new String(EvaluationConstants.DELEGATE_THIS);
+
+ /**
+ * The name of the instance method in the snippet class that runs the code
+ * snippet.
+ */
+ public static final String RUN_METHOD = EvaluationConstants.RUN_METHOD;
+
+ /**
+ * The name of the field (of type <code>java.lang.Object</code>) on the code
+ * snippet instance that contains the returned value.
+ */
+ public static final String RESULT_VALUE_FIELD =
+ EvaluationConstants.RESULT_VALUE_FIELD;
+
+ /*
+ * The field of type java.lang.Class on the code snippet instance that contains the type of the returned value.
+ * The name of the field (of type <code>java.lang.Class</code>) on the code
+ * snippet instance that contains the runtime type of the returned value.
+ */
+ public static final String RESULT_TYPE_FIELD =
+ EvaluationConstants.RESULT_TYPE_FIELD;
+
+ /*
+ * REPORTING A PROBLEM OF COMPILATION IN THE CODE SNIPPET
+ */
+
+ /**
+ * Indicates a compilation problem related to a global variable.
+ * <p>
+ * Note: if the problem is on the type of the variable, the marker
+ * source line number is -1; if the name of the variable, line number is 0;
+ * otherwise, the marker source line number is relative to the initializer
+ * code.
+ * </p>
+ *
+ * @see #acceptProblem
+ */
+ public static final int VARIABLE = 1;
+
+ /**
+ * Indicates a compilation problem related to a code snippet.
+ *
+ * @see #acceptProblem
+ */
+ public static final int CODE_SNIPPET = 2;
+
+ /*
+ * Indicates a compilation problem related to an import declaration.
+ *
+ * @see #acceptProblem
+ */
+ public static final int IMPORT = 3;
+
+ /*
+ * Indicates a compilation problem related to a package declaration.
+ *
+ * @see #acceptProblem
+ */
+ public static final int PACKAGE = 4;
+
+ /*
+ * Indicates an internal problem.
+ *
+ * @see #acceptProblem
+ */
+ public static final int INTERNAL = 5;
+ /**
+ * Sends the given class files to the target and loads them. If the given
+ * class name is not <code>null</code>, run the code snippet with this class
+ * name. Returns whether the code snippet could be deployed. Note it must
+ * return <code>true</code> even if running the code snippet threw an exception.
+ * <p>
+ * The details of sending and loading the class files are left up to
+ * implementations.
+ * </p>
+ * <p>
+ * To run a code snippet, an implementation should create a new instance of
+ * the given code snippet class and call (directly or using another means) its
+ * <code>RUN_METHOD</code>.
+ * </p>
+ * <p>
+ * Also before the call, the implementation should copy the values of the local
+ * variables (if any) into the corresponding fields of the code snippet instance.
+ * A field name is formed of <code>LOCAL_VAR_PREFIX</code>
+ * prepended the name of the local variable. For example, the field name for
+ * local variable <code>"myLocal"</code> is <code>"val$myLocal"</code> (assuming the
+ * value of <code>LOCAL_VAR_PREFIX</code> is "val$"). In the
+ * same way, the implementation should copy the value of the 'this' object into the
+ * field called <code>DELEGATE_THIS</code>.
+ * </p>
+ * <p>
+ * After calling the <code>RUN_METHOD</code>, the values of the local
+ * variables may have been modified. The implementation must copy the
+ * values of the fields back into the local variables.
+ * </p>
+ * <p>
+ * Finally, the overall value returned by the code snippet can be retrieved
+ * from the special field <code>RESULT_VALUE_FIELD</code>
+ * on the code snippet instance.
+ * The <code>Class</code> that is the runtime type of the returned value can be
+ * retrieved from the special field <code>RESULT_TYPE_FIELD</code>.
+ * </p>
+ *
+ * @param classFileBytes the list of class file bytes
+ * @param classFileCompoundNames the corresponding list of class file type
+ * compound names (example of a compound name: {"java", "lang", "Object"})
+ * @param codeSnippetClassName name of the actual class to instantiate and run,
+ * or <code>null</code> if none
+ * @return <code>true</code> if the code snippet was successfully deployed
+ */
+ public boolean acceptClassFiles(
+ byte[][] classFileBytes,
+ String[][] classFileCompoundNames,
+ String codeSnippetClassName);
+ /**
+ * Notifies of an evaluation problem.
+ * Problems can arise for source of the following kinds:
+ * <p>
+ * <ul>
+ * <li>global variable (<code>VARIABLE</code>) - fragment source is name of
+ * variable</li>
+ * <li>code snippet (<code>CODE_SNIPPET</code>) - fragment source is code
+ * snippet</li>
+ * <li>import declaration (<code>IMPORT</code>) - fragment source is
+ * import</li>
+ * <li>package declaration (<code>PACKAGE</code>) - fragment source is
+ * package declaration</li>
+ * <li>other (<code>INTERNAL</code>) - no fragment source is involved, internal error occurred.</li>
+ * </ul>
+ * </p>
+ * @param problemMarker the problem marker (cannot be null)
+ * @param fragmentSource the fragment source
+ * @param fragmentKind the kind of source fragment; one of:
+ * <code>VARIABLE</code>, <code>CODE_SNIPPET</code>, <code>IMPORT</code>,
+ * <code>PACKAGE</code>, or <code>INTERNAL</code>
+ */
+ public void acceptProblem(
+ IMarker problemMarker,
+ String fragmentSource,
+ int fragmentKind);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/IEvaluationContext.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/IEvaluationContext.java
new file mode 100644
index 0000000000..7ec02189ed
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/IEvaluationContext.java
@@ -0,0 +1,302 @@
+package org.eclipse.jdt.core.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.core.*;
+
+/**
+ * An evaluation context supports evaluating code snippets.
+ * <p>
+ * A code snippet is pretty much any valid piece of Java code that could be
+ * pasted into the body of a method and compiled. However, there are two
+ * areas where the rules are slightly more liberal.
+ * <p>
+ * First, a code snippet can return heterogeneous types. Inside the same code
+ * snippet an <code>int</code> could be returned on one line, and a
+ * <code>String</code> on the next, etc. For example, the following would be
+ * considered a valid code snippet:
+ * <pre>
+ * <code>
+ * char c = '3';
+ * switch (c) {
+ * case '1': return 1;
+ * case '2': return '2';
+ * case '3': return "3";
+ * default: return null;
+ * }
+ * </code>
+ * </pre>
+ * </p>
+ * <p>
+ * Second, if the last statement is only an expression, the <code>return</code>
+ * keyword is implied. For example, the following returns <code>false</code>:
+ * <pre>
+ * <code>
+ * int i = 1;
+ * i == 2
+ * </code>
+ * </pre>
+ * </p>
+ * <p>
+ * Global variables are an additional feature of evaluation contexts. Within an
+ * evaluation context, global variables maintain their value across evaluations.
+ * These variables are particularly useful for storing the result of an
+ * evaluation for use in subsequent evaluations.
+ * </p>
+ * <p>
+ * The evaluation context remembers the name of the package in which code
+ * snippets are run. The user can set this to any package, thereby gaining
+ * access to types that are normally only visible within that package.
+ * </p>
+ * <p>
+ * Finally, the evaluation context remembers a list of import declarations. The
+ * user can import any packages and types so that the code snippets may refer
+ * to types by their shorter simple names.
+ * </p>
+ * <p>
+ * Example of use:
+ * <pre>
+ * <code>
+ * IJavaProject project = getJavaProject();
+ * IEvaluationContext context = project.newEvaluationContext();
+ * String codeSnippet = "int i= 0; i++";
+ * ICodeSnippetRequestor requestor = ...;
+ * context.evaluateCodeSnippet(codeSnippet, requestor, progressMonitor);
+ * </code>
+ * </pre>
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * <code>IJavaProject.newEvaluationContext</code> can be used to obtain an
+ * instance.
+ * </p>
+ *
+ * @see IJavaProject#newEvaluationContext
+ */
+public interface IEvaluationContext {
+ /**
+ * Returns the global variables declared in this evaluation context.
+ * The variables are maintained in the order they are created in.
+ *
+ * @return the list of global variables
+ */
+ public IGlobalVariable[] allVariables();
+ /**
+ * Performs a code completion at the given position in the given code snippet,
+ * reporting results to the given completion requestor.
+ * <p>
+ * Note that code completion does not involve evaluation.
+ * <p>
+ *
+ * @param codeSnippet the code snippet to complete in
+ * @param position the character position in the code snippet to complete at,
+ * or -1 indicating the beginning of the snippet
+ * @param requestor the code completion requestor capable of accepting all
+ * possible types of completions
+ * @exception JavaModelException if code completion could not be performed. Reasons include:
+ * <ul>
+ * <li>The position specified is less than -1 or is greater than the snippet's
+ * length (INDEX_OUT_OF_BOUNDS)</li>
+ * </ul>
+ */
+ public void codeComplete(
+ String codeSnippet,
+ int position,
+ ICodeCompletionRequestor requestor)
+ throws JavaModelException;
+ /**
+ * Resolves and returns a collection of Java elements corresponding to the source
+ * code at the given positions in the given code snippet.
+ * <p>
+ * Note that code select does not involve evaluation, and problems are never
+ * reported.
+ * <p>
+ *
+ * @param codeSnippet the code snippet to resolve in
+ * @param offset the position in the code snippet of the first character
+ * of the code to resolve
+ * @param length the length of the selected code to resolve
+ * @return the (possibly empty) list of selection Java elements
+ * @exception JavaModelException if code resolve could not be performed.
+ * Reasons include:
+ * <ul>
+ * <li>The position specified is less than -1 or is greater than the snippet's
+ * length (INDEX_OUT_OF_BOUNDS)</li>
+ * </ul>
+ */
+ public IJavaElement[] codeSelect(String codeSnippet, int offset, int length)
+ throws JavaModelException;
+ /**
+ * Deletes the given variable from this evaluation context. Does nothing if
+ * the given variable has already been deleted.
+ *
+ * @param variable the global variable
+ */
+ public void deleteVariable(IGlobalVariable variable);
+ /**
+ * Evaluates the given code snippet in the context of a suspended thread.
+ * The code snippet is compiled along with this context's package declaration,
+ * imports, and global variables. The given requestor's
+ * <code>acceptProblem</code> method is called for each compilation problem that
+ * is detected. Then the resulting class files are handed to the given
+ * requestor's <code>acceptClassFiles</code> method to deploy and run.
+ * <p>
+ * The requestor is expected to:
+ * <ol>
+ * <li>send the class files to the target VM,
+ * <li>load them (starting with the code snippet class),
+ * <li>create a new instance of the code snippet class,
+ * <li>run the method <code>run()</code> of the code snippet,
+ * <li>retrieve the values of the local variables,
+ * <li>retrieve the returned value of the code snippet
+ * </ol>
+ * </p>
+ * <p>
+ * This method is long-running; progress and cancelation are provided
+ * by the given progress monitor.
+ * </p>
+ *
+ * @param codeSnippet the code snippet
+ * @param localVariableTypeNames the dot-separated fully qualified names of the types of the local variables.
+ * @param localVariableNames the names of the local variables as they are declared in the user's code.
+ * @param localVariableModifiers the modifiers of the local variables (default modifier or final modifier).
+ * @param declaringType the type in which the code snippet is evaluated.
+ * @param isStatic whether the code snippet is evaluated in a static member of the declaring type.
+ * @param isConstructorCall whether the code snippet is evaluated in a constructor of the declaring type.
+ * @param requestor the code snippet requestor
+ * @param progressMonitor a progress monitor
+ * @exception JavaModelException if a runtime problem occurred or if this
+ * context's project has no build state
+ */
+ public void evaluateCodeSnippet(
+ String codeSnippet,
+ String[] localVariableTypeNames,
+ String[] localVariableNames,
+ int[] localVariableModifiers,
+ IType declaringType,
+ boolean isStatic,
+ boolean isConstructorCall,
+ ICodeSnippetRequestor requestor,
+ IProgressMonitor progressMonitor)
+ throws JavaModelException;
+ /**
+ * Evaluates the given code snippet. The code snippet is
+ * compiled along with this context's package declaration, imports, and
+ * global variables. The given requestor's <code>acceptProblem</code> method
+ * is called for each compilation problem that is detected. Then the resulting
+ * class files are handed to the given requestor's <code>acceptClassFiles</code>
+ * method to deploy and run. The requestor is also responsible for getting the
+ * result back.
+ * <p>
+ * This method is long-running; progress and cancelation are provided
+ * by the given progress monitor.
+ * </p>
+ *
+ * @param codeSnippet the code snippet
+ * @param requestor the code snipper requestor
+ * @param progressMonitor a progress monitor
+ * @exception JavaModelException if a runtime problem occurred or if this
+ * context's project has no build state
+ */
+ public void evaluateCodeSnippet(
+ String codeSnippet,
+ ICodeSnippetRequestor requestor,
+ IProgressMonitor progressMonitor)
+ throws JavaModelException;
+ /**
+ * Evaluates the given global variable. During this operation,
+ * this context's package declaration, imports, and <it>all</it> its declared
+ * variables are verified. The given requestor's <code>acceptProblem</code>
+ * method will be called for each problem that is detected.
+ * <p>
+ * This method is long-running; progress and cancelation are provided
+ * by the given progress monitor.
+ * </p>
+ *
+ * @param variable the global variable
+ * @param requestor the code snipper requestor
+ * @param progressMonitor a progress monitor
+ * @exception JavaModelException if a runtime problem occurred or if this
+ * context's project has no build state
+ */
+ public void evaluateVariable(
+ IGlobalVariable variable,
+ ICodeSnippetRequestor requestor,
+ IProgressMonitor progressMonitor)
+ throws JavaModelException;
+ /**
+ * Returns the import declarations for this evaluation context. Returns and empty
+ * list if there are no imports (the default if the imports have never been set).
+ * The syntax for the import corresponds to a fully qualified type name, or to
+ * an on-demand package name as defined by ImportDeclaration (JLS2 7.5). For
+ * example, <code>"java.util.Hashtable"</code> or <code>"java.util.*"</code>.
+ *
+ * @return the list of import names
+ */
+ public String[] getImports();
+ /**
+ * Returns the name of the package in which code snippets are to be compiled and
+ * run. Returns an empty string for the default package (the default if the
+ * package name has never been set). For example, <code>"com.example.myapp"</code>.
+ *
+ * @return the dot-separated package name, or the empty string indicating the
+ * default package
+ */
+ public String getPackageName();
+ /**
+ * Returns the Java project this evaluation context was created for.
+ *
+ * @return the Java project
+ */
+ public IJavaProject getProject();
+ /**
+ * Creates a new global variable with the given name, type, and initializer.
+ * <p>
+ * The <code>typeName</code> and <code>initializer</code> are interpreted in
+ * the context of this context's package and import declarations.
+ * </p>
+ * <p>
+ * The syntax for a type name corresponds to Type in Field Declaration (JLS2 8.3).
+ * </p>
+ *
+ * @param typeName the type name
+ * @param name the name of the global variable
+ * @param initializer the initializer expression, or <code>null</code> if the
+ * variable is not initialized
+ */
+ public IGlobalVariable newVariable(
+ String typeName,
+ String name,
+ String initializer);
+ /**
+ * Sets the import declarations for this evaluation context. An empty
+ * list indicates there are no imports. The syntax for the import corresponds to a
+ * fully qualified type name, or to an on-demand package name as defined by
+ * ImportDeclaration (JLS2 7.5). For example, <code>"java.util.Hashtable"</code>
+ * or <code>"java.util.*"</code>.
+ *
+ * @param imports the list of import names
+ */
+ public void setImports(String[] imports);
+ /**
+ * Sets the dot-separated name of the package in which code snippets are
+ * to be compiled and run. For example, <code>"com.example.myapp"</code>.
+ *
+ * @param packageName the dot-separated package name, or the empty string
+ * indicating the default package
+ */
+ public void setPackageName(String packageName);
+ /**
+ * Validates this evaluation context's import declarations. The given requestor's
+ * <code>acceptProblem</code> method is called for each problem that is detected.
+ *
+ * @param requestor the code snipper requestor
+ * @exception JavaModelException if this context's project has no build state
+ */
+ public void validateImports(ICodeSnippetRequestor requestor)
+ throws JavaModelException;
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/IGlobalVariable.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/IGlobalVariable.java
new file mode 100644
index 0000000000..069f535875
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/IGlobalVariable.java
@@ -0,0 +1,28 @@
+package org.eclipse.jdt.core.eval;
+
+public interface IGlobalVariable {
+ /**
+ * Returns the initializer of this global variable.
+ * The syntax for an initializer corresponds to VariableInitializer (JLS2 8.3).
+ *
+ * @return the initializer expression, or <code>null</code> if this global does
+ * not have an initializer
+ */
+ public String getInitializer();
+ /**
+ * Returns the name of this global variable.
+ *
+ * @return the name of the global variable
+ */
+ public String getName();
+ /**
+ * Returns the fully qualified name of the type of this global
+ * variable, or its simple representation if it is a primitive type
+ * (<code>int</code>, <code>boolean</code>, etc.).
+ * <p>
+ * The syntax for a type name corresponds to Type in Field Declaration (JLS2 8.3).
+ * </p>
+ * @return the type name
+ */
+ public String getTypeName();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/DOMException.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/DOMException.java
new file mode 100644
index 0000000000..0be5c73514
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/DOMException.java
@@ -0,0 +1,19 @@
+package org.eclipse.jdt.core.jdom;
+
+public class DOMException extends RuntimeException {
+ /**
+ * Creates a new exception with no detail message.
+ */
+ public DOMException() {
+ }
+
+ /**
+ * Creates a new exception with the given detail message.
+ *
+ * @param message the deatil message
+ */
+ public DOMException(String message) {
+ super(message);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/DOMFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/DOMFactory.java
new file mode 100644
index 0000000000..bf9e68ae5a
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/DOMFactory.java
@@ -0,0 +1,169 @@
+package org.eclipse.jdt.core.jdom;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.jdom.*;
+import org.eclipse.jdt.internal.core.JavaModelManager;
+
+/**
+ * Standard implementation of <code>IDOMFactory</code>, and the only means
+ * of creating JDOMs and document fragments.
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ */
+public class DOMFactory implements IDOMFactory {
+ /**
+ * Creates a new DOM factory.
+ */
+ public DOMFactory() {
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IDOMFactory.
+ */
+ public IDOMCompilationUnit createCompilationUnit() {
+ return (new DOMBuilder()).createCompilationUnit();
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IDOMFactory.
+ */
+ public IDOMCompilationUnit createCompilationUnit(
+ char[] sourceCode,
+ String name) {
+ if (sourceCode == null) {
+ return null;
+ }
+ return (new SimpleDOMBuilder()).createCompilationUnit(
+ sourceCode,
+ name.toCharArray());
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IDOMFactory.
+ */
+ public IDOMCompilationUnit createCompilationUnit(
+ String sourceCode,
+ String name) {
+ if (sourceCode == null) {
+ return null;
+ }
+ return (new SimpleDOMBuilder()).createCompilationUnit(
+ sourceCode.toCharArray(),
+ name.toCharArray());
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IDOMFactory.
+ */
+ public IDOMField createField() {
+ return createField("Object aField;" + JavaModelManager.LINE_SEPARATOR);
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IDOMFactory.
+ */
+ public IDOMField createField(String sourceCode) {
+ if (sourceCode == null) {
+ return null;
+ }
+ return (new DOMBuilder()).createField(sourceCode.toCharArray());
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IDOMFactory.
+ */
+ public IDOMImport createImport() {
+ return (new DOMBuilder()).createImport();
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IDOMFactory.
+ */
+ public IDOMImport createImport(String sourceCode) {
+ if (sourceCode == null) {
+ return null;
+ }
+ return (new DOMBuilder()).createImport(sourceCode.toCharArray());
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IDOMFactory.
+ */
+ public IDOMInitializer createInitializer() {
+ return createInitializer("static {}" + JavaModelManager.LINE_SEPARATOR);
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IDOMFactory.
+ */
+ public IDOMInitializer createInitializer(String sourceCode) {
+ if (sourceCode == null) {
+ return null;
+ }
+ return (new DOMBuilder()).createInitializer(sourceCode.toCharArray());
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IDOMFactory.
+ */
+ public IDOMMethod createMethod() {
+ return createMethod(
+ "public void newMethod() {"
+ + JavaModelManager.LINE_SEPARATOR
+ + "}"
+ + JavaModelManager.LINE_SEPARATOR);
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IDOMFactory.
+ */
+ public IDOMMethod createMethod(String sourceCode) {
+ if (sourceCode == null) {
+ return null;
+ }
+ return (new DOMBuilder()).createMethod(sourceCode.toCharArray());
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IDOMFactory.
+ */
+ public IDOMPackage createPackage() {
+ return (new DOMBuilder()).createPackage();
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IDOMFactory.
+ */
+ public IDOMPackage createPackage(String sourceCode) {
+ if (sourceCode == null) {
+ return null;
+ }
+ return (new DOMBuilder()).createPackage(sourceCode.toCharArray());
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IDOMFactory.
+ */
+ public IDOMType createType() {
+ return createType(
+ "public class AClass {"
+ + JavaModelManager.LINE_SEPARATOR
+ + "}"
+ + JavaModelManager.LINE_SEPARATOR);
+ }
+
+ /* (non-Javadoc)
+ * Method declared on IDOMFactory.
+ */
+ public IDOMType createType(String sourceCode) {
+ if (sourceCode == null) {
+ return null;
+ }
+ return (new DOMBuilder()).createType(sourceCode.toCharArray());
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMCompilationUnit.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMCompilationUnit.java
new file mode 100644
index 0000000000..6f3fffbeb5
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMCompilationUnit.java
@@ -0,0 +1,45 @@
+package org.eclipse.jdt.core.jdom;
+
+public interface IDOMCompilationUnit extends IDOMNode {
+ /**
+ * Returns the header comment for this compilation unit. The header comment
+ * appears before the first declaration in a compilation unit.
+ * The syntax for a comment corresponds to Comments (JLS2 3.7), <b>including</b>
+ * comment delimiters.
+ *
+ * @return the header comment for this compilation unit, or <code>null</code> if
+ * no header comment is present
+ */
+ public String getHeader();
+ /**
+ * The <code>IDOMCompilationNode</code> refinement of this <code>IDOMNode</code>
+ * method returns the name of this compilation unit.
+ *
+ * <p>The name of a compilation unit is the name of the first top-level public type
+ * defined in the compilation unit, suffixed with ".java". For example, if the first
+ * top-level public type defined in this compilation unit has the name "Hanoi",
+ * then name of this compilation unit is "Hanoi.java".</p>
+ *
+ * <p>In the absence of a public top-level type, the name of the first top-level
+ * type is used. In the absence of any type, the name of the compilation unit
+ * is <code>null</code>.</p>
+ *
+ * @return the name of this compilation unit, or <code>null</code> if none
+ */
+ public String getName();
+ /**
+ * Sets the header comment for this compilation unit. The header comment
+ * appears before the first declaration in a compilation unit.
+ * The syntax for a comment corresponds to Comments (JLS2 3.7), <b>including</b>
+ * comment delimiters.
+ *
+ * @param comment the header comment for this compilation unit, or <code>null</code> if
+ * indicating no header comment
+ */
+ public void setHeader(String comment);
+ /**
+ * The <code>IDOMCompilationNode</code> refinement of this <code>IDOMNode</code>
+ * method has no effect (the name is computed from the types declared within it).
+ */
+ public void setName(String name);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMFactory.java
new file mode 100644
index 0000000000..69e26dc8cf
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMFactory.java
@@ -0,0 +1,137 @@
+package org.eclipse.jdt.core.jdom;
+
+public interface IDOMFactory {
+ /**
+ * Creates and return an empty JDOM. The initial content is an empty string.
+ *
+ * @return the new compilation unit
+ */
+ public IDOMCompilationUnit createCompilationUnit();
+ /**
+ * Creates a JDOM on the given source code. The syntax for the given source
+ * code corresponds to CompilationUnit (JLS2 7.3).
+ *
+ * @param sourceCode the source code character array, or <code>null</code>
+ * @param name the name of the compilation unit
+ * @return the new compilation unit, or <code>null</code> if unable to recognize
+ * the source code, or if the source code is <code>null</code>
+ */
+ public IDOMCompilationUnit createCompilationUnit(
+ char[] sourceCode,
+ String name);
+ /**
+ * Creates a JDOM on the given source code. The syntax for the given source
+ * code corresponds to CompilationUnit (JLS2 7.3).
+ *
+ * @param sourceCode the source code string, or <code>null</code>
+ * @param name the name of the compilation unit
+ * @return the new compilation unit, or <code>null</code> if unable to recognize
+ * the source code, or if the source code is <code>null</code>
+ */
+ public IDOMCompilationUnit createCompilationUnit(
+ String sourceCode,
+ String name);
+ /**
+ * Creates a default field document fragment. Initially the field will have
+ * default protection, type <code>"Object"</code>, name <code>"aField"</code>,
+ * no comment, and no initializer.
+ *
+ * @return the new field
+ */
+ public IDOMField createField();
+ /**
+ * Creates a field document fragment on the given source code. The given source
+ * string corresponds to FieldDeclaration (JLS2 8.3) and ConstantDeclaration
+ * (JLS2 9.3) restricted to a single VariableDeclarator clause.
+ *
+ * @param sourceCode the source code
+ * @return the new field, or <code>null</code> if unable to recognize
+ * the source code, if the source code is <code>null</code>, or when the source
+ * contains more than one VariableDeclarator clause
+ */
+ public IDOMField createField(String sourceCode);
+ /**
+ * Creates an empty import document fragment. Initially the import will have
+ * name <code>"java.lang.*"</code>.
+ *
+ * @return the new import
+ */
+ public IDOMImport createImport();
+ /**
+ * Creates an import document fragment on the given source code. The syntax for
+ * the given source string corresponds to ImportDeclaration (JLS2 7.5).
+ *
+ * @param sourceCode the source code
+ * @return the new import, or <code>null</code> if unable to recognize
+ * the source code, or if the source code is <code>null</code>
+ */
+ public IDOMImport createImport(String sourceCode);
+ /**
+ * Creates an empty initializer document fragment. Initially the initializer
+ * will be static and have no body or comment.
+ *
+ * @return the new initializer
+ */
+ public IDOMInitializer createInitializer();
+ /**
+ * Creates an initializer document fragment from the given source code. The
+ * syntax for the given source string corresponds to InstanceInitializer
+ * (JLS2 8.6) and StaticDeclaration (JLS2 8.7).
+ *
+ * @param sourceCode the source code
+ * @return the new initializer, or <code>null</code> if unable to recognize
+ * the source code, or if the source code is <code>null</code>
+ */
+ public IDOMInitializer createInitializer(String sourceCode);
+ /**
+ * Creates a default method document fragment. Initially the method
+ * will have public visibility, return type <code>"void"</code>, be named
+ * <code>"newMethod"</code>, have no parameters, no comment, and an empty body.
+ *
+ * @return the new method
+ */
+ public IDOMMethod createMethod();
+ /**
+ * Creates a method document fragment on the given source code. The syntax for
+ * the given source string corresponds to MethodDeclaration (JLS2 8.4),
+ * ConstructorDeclaration (JLS2 8.8), and AbstractMethodDeclaration (JLS2 9.4).
+ *
+ * @param sourceCode the source code
+ * @return the new method, or <code>null</code> if unable to recognize
+ * the source code, or if the source code is <code>null</code>
+ */
+ public IDOMMethod createMethod(String sourceCode);
+ /**
+ * Creates an empty package document fragment. Initially the package
+ * declaration will have no name.
+ *
+ * @return the new package
+ */
+ public IDOMPackage createPackage();
+ /**
+ * Creates a package document fragment on the given source code. The syntax for
+ * the given source string corresponds to PackageDeclaration (JLS2 7.4).
+ *
+ * @param sourceCode the source code
+ * @return the new package, or <code>null</code> if unable to recognize
+ * the source code, or if the source code is <code>null</code>
+ */
+ public IDOMPackage createPackage(String sourceCode);
+ /**
+ * Creates a default type document fragment. Initially the type will be
+ * a public class named <code>"AClass"</code>, with no members or comment.
+ *
+ * @return the new type
+ */
+ public IDOMType createType();
+ /**
+ * Creates a type document fragment on the given source code. The syntax for the
+ * given source string corresponds to ClassDeclaration (JLS2 8.1) and
+ * InterfaceDeclaration (JLS2 9.1).
+ *
+ * @param sourceCode the source code
+ * @return the new type, or <code>null</code> if unable to recognize
+ * the source code, or if the source code is <code>null</code>
+ */
+ public IDOMType createType(String sourceCode);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMField.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMField.java
new file mode 100644
index 0000000000..28cf0e4006
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMField.java
@@ -0,0 +1,57 @@
+package org.eclipse.jdt.core.jdom;
+
+public interface IDOMField extends IDOMMember {
+ /**
+ * Returns the initializer expression for this field.
+ * The syntax for an initializer corresponds to VariableInitializer (JLS2 8.3).
+ * <p>
+ * Note: The expression does not include a "<code>=</code>".
+ * </p>
+ *
+ * @return the initializer expression, or <code>null</code> if this field does
+ * not have an initializer
+ */
+ public String getInitializer();
+ /**
+ * The <code>IDOMField</code> refinement of this <code>IDOMNode</code>
+ * method returns the name of this field. The syntax for the name of a field
+ * corresponds to VariableDeclaratorId (JLS2 8.3).
+ */
+ public String getName();
+ /**
+ * Returns the type name of this field. The syntax for a type name of a field
+ * corresponds to Type in Field Declaration (JLS2 8.3).
+ *
+ * @return the type name
+ */
+ public String getType();
+ /**
+ * Sets the initializer expression for this field.
+ * The syntax for an initializer corresponds to VariableInitializer (JLS2 8.3).
+ * <p>
+ * Note: The expression does not include a "<code>=</code>".
+ * </p>
+ *
+ * @param initializer the initializer expression, or <code>null</code> indicating
+ * the field does not have an initializer
+ */
+ public void setInitializer(String initializer);
+ /**
+ * The <code>IDOMField</code> refinement of this <code>IDOMNode</code>
+ * method sets the name of this field. The syntax for the name of a field
+ * corresponds to VariableDeclaratorId (JLS2 8.3).
+ *
+ * @exception IllegalArgumentException if <code>null</code> is specified
+ */
+ public void setName(String name) throws IllegalArgumentException;
+ /**
+ * Sets the type name of this field. The syntax for a type name of a field
+ * corresponds to Type in Field Declaration (JLS2 8.3). Type names must be
+ * specified as they should appear in source code. For example:
+ * <code>"String"</code>, <code>"int[]"</code>, or <code>"java.io.File"</code>.
+ *
+ * @param typeName the type name
+ * @exception IllegalArgumentException if <code>null</code> is specified
+ */
+ public void setType(String typeName) throws IllegalArgumentException;
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMImport.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMImport.java
new file mode 100644
index 0000000000..23dbb6c23a
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMImport.java
@@ -0,0 +1,26 @@
+package org.eclipse.jdt.core.jdom;
+
+public interface IDOMImport extends IDOMNode {
+ /**
+ * The <code>IDOMImport</code> refinement of this <code>IDOMNode</code>
+ * method returns the name of this import. The syntax for an import name
+ * corresponds to a fully qualified type name, or to an on-demand package name
+ * as defined by ImportDeclaration (JLS2 7.5).
+ */
+ public String getName();
+ /**
+ * Returns whether this import declaration ends with <code>".*"</code>.
+ *
+ * @return <code>true</code> if this in an on-demand import
+ */
+ public boolean isOnDemand();
+ /**
+ * The <code>IDOMImport</code> refinement of this <code>IDOMNode</code>
+ * method sets the name of this import. The syntax for an import name
+ * corresponds to a fully qualified type name, or to an on-demand package name
+ * as defined by ImportDeclaration (JLS2 7.5).
+ *
+ * @exception IllegalArgumentException if <code>null</code> is specified
+ */
+ public void setName(String name);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMInitializer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMInitializer.java
new file mode 100644
index 0000000000..df25caf7c1
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMInitializer.java
@@ -0,0 +1,31 @@
+package org.eclipse.jdt.core.jdom;
+
+public interface IDOMInitializer extends IDOMMember {
+ /**
+ * Returns the body of this initializer. The syntax for a body corresponds to
+ * InstanceInitializer (JLS2 8.6) and StaticDeclaration (JLS2 8.7).
+ *
+ * @return an initializer body, including braces, or <code>null</code> if
+ * no body is present
+ */
+ public String getBody();
+ /**
+ * The <code>IDOMInitializer</code> refinement of this <code>IDOMNode</code>
+ * method returns <code>null</code>. An initializer does not have a name.
+ */
+ public String getName();
+ /**
+ * Sets the body of this initializer. The syntax for a body corresponds to
+ * InstanceInitializer (JLS2 8.6) and StaticDeclaration (JLS2 8.7). No formatting
+ * or syntax checking is performed on the body. Braces <b>must</b> be included.
+ *
+ * @param body an initializer body, including braces, or <code>null</code>
+ * indicating no body
+ */
+ public void setBody(String body);
+ /**
+ * The <code>IDOMInitializer</code> refinement of this <code>IDOMNode</code>
+ * method does nothing.
+ */
+ public void setName(String name);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMMember.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMMember.java
new file mode 100644
index 0000000000..53a12182e9
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMMember.java
@@ -0,0 +1,39 @@
+package org.eclipse.jdt.core.jdom;
+
+public interface IDOMMember extends IDOMNode {
+ /**
+ * Returns the comment associated with this member (including comment delimiters).
+ *
+ * @return the comment, or <code>null</code> if this member has no associated
+ * comment
+ */
+ public String getComment();
+ /**
+ * Returns the flags for this member. The flags can be examined using the
+ * <code>Flags</code> class.
+ *
+ * @return the flags
+ * @see org.eclipse.jdt.core.Flags
+ */
+ public int getFlags();
+ /**
+ * Sets the comment associated with this member. The comment will appear
+ * before the member in the source. The comment must be properly formatted, including
+ * delimiters. A <code>null</code> comment indicates no comment. This member's
+ * deprecated flag is automatically set to reflect the deprecated tag in the
+ * comment.
+ *
+ * @param comment the comment, including comment delimiters, or
+ * <code>null</code> indicating this member should have no associated comment
+ * @see #setFlags
+ */
+ public void setComment(String comment);
+ /**
+ * Sets the flags for this member. The flags can be examined using the
+ * <code>Flags</code> class. The deprecated flag passed in is ignored.
+ *
+ * @param flags the flags
+ * @see org.eclipse.jdt.core.Flags
+ */
+ public void setFlags(int flags);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMMethod.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMMethod.java
new file mode 100644
index 0000000000..3a98b3525e
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMMethod.java
@@ -0,0 +1,164 @@
+package org.eclipse.jdt.core.jdom;
+
+public interface IDOMMethod extends IDOMMember {
+ /**
+ * Adds the given exception to the end of the list of exceptions this method
+ * is declared to throw.
+ * The syntax for an exception type name is defined by Method Throws (JLS2 8.4.4).
+ * Type names must be specified as they would appear in source code. For
+ * example: <code>"IOException"</code> or <code>"java.io.IOException"</code>.
+ * This is a convenience method for <code>setExceptions</code>.
+ *
+ * @param exceptionType the exception type
+ * @exception IllegalArgumentException if <code>null</code> is specified
+ * @see #setExceptions
+ */
+ public void addException(String exceptionType) throws IllegalArgumentException;
+ /**
+ * Adds the given parameter to the end of the parameter list.
+ * This is a convenience method for <code>setParameters</code>.
+ * The syntax for parameter names is defined by Formal Parameters (JLS2 8.4.1).
+ * The syntax for type names is defined by Formal Parameters (JLS2 8.4.1).
+ * Type names must be specified as they would appear in source code. For
+ * example: <code>"File"</code>, <code>"java.io.File"</code>, or
+ * <code>"int[]"</code>.
+ *
+ * @param type the type name
+ * @param name the parameter name
+ * @exception IllegalArgumentException if <code>null</code> is specified for
+ * either the type or the name
+ * @see #setParameters
+ */
+ public void addParameter(String type, String name)
+ throws IllegalArgumentException;
+ /**
+ * Returns the body of this method. The method body includes all code following
+ * the method declaration, including the enclosing braces.
+ *
+ * @return the body, or <code>null</code> if the method has no body (for
+ * example, for an abstract or native method)
+ */
+ public String getBody();
+ /**
+ * Returns the names of the exception types this method throws
+ * in the order in which they are declared in the source, or an empty array
+ * if this method declares no exception types.
+ * The syntax for an exception type name is defined by Method Throws (JLS2 8.4.4).
+ * Type names appear as they would in source code. For example:
+ * <code>"IOException"</code> or <code>"java.io.IOException"</code>.
+ *
+ * @return the list of exception types
+ */
+ public String[] getExceptions();
+ /**
+ * The <code>IDOMMethod</code> refinement of this <code>IDOMNode</code>
+ * method returns the name of this method. Returns <code>null</code> for
+ * constructors. The syntax for a method name is defined by Identifer
+ * of MethodDeclarator (JLS2 8.4).
+ */
+ public String getName();
+ /**
+ * Returns the names of parameters in this method in the order they are declared,
+ * or <code>null</code> if no parameters are declared.
+ * The syntax for parameter names is defined by Formal Parameters (JLS2 8.4.1).
+ *
+ * @return the list of parameter names, or <code>null</code> if no parameters
+ * are declared
+ */
+ public String[] getParameterNames();
+ /**
+ * Returns the type names for the parameters of this method in the order they are declared,
+ * or <code>null</code> if no parameters are declared.
+ * The syntax for type names is defined by Formal Parameters (JLS2 8.4.1).
+ * Type names must be specified as they would appear in source code. For
+ * example: <code>"File"</code>, <code>"java.io.File"</code>, or
+ * <code>"int[]"</code>.
+ *
+ * @return the list of parameter types, or <code>null</code> if no parameters
+ * are declared
+ */
+ public String[] getParameterTypes();
+ /**
+ * Returns the return type name, or <code>"void"</code>.
+ * Returns <code>"void"</code> for constructors.
+ * The syntax for return type name corresponds to ReturnType in
+ * MethodDeclaration (JLS2 8.4). Names are returned as they appear in the source
+ * code; for example: <code>"File"</code>, <code>"java.io.File"</code>,
+ * <code>"int[]"</code>, or <code>"void"</code>.
+ *
+ * @return the return type
+ */
+ public String getReturnType();
+ /**
+ * Returns whether this method is a constructor.
+ *
+ * @return <code>true</code> for constructors, and <code>false</code> for methods
+ */
+ public boolean isConstructor();
+ /**
+ * Sets the body of this method. The method body includes all code following
+ * the method declaration, including the enclosing braces. No formatting or
+ * syntax checking is performed on the body.
+ *
+ * @return the body, or <code>null</code> indicating the method has no body (for
+ * example, for an abstract or native method)
+ */
+ public void setBody(String body);
+ /**
+ * Sets whether this method represents a constructor.
+ *
+ * @param b <code>true</code> for constructors, and <code>false</code> for methods
+ */
+ public void setConstructor(boolean b);
+ /**
+ * Sets the names of the exception types this method throws,
+ * in the order in which they are declared in the source. An empty array
+ * indicates this method declares no exception types.
+ * The syntax for an exception type name is defined by Method Throws (JLS2 8.4.4).
+ * Type names must be specified as they would appear in source code. For
+ * example: <code>"IOException"</code> or <code>"java.io.IOException"</code>.
+ *
+ * @param exceptionTypes the list of exception types
+ */
+ public void setExceptions(String[] exceptionTypes);
+ /**
+ * The <code>IDOMMethod</code> refinement of this <code>IDOMNode</code>
+ * method sets the name of this method. The syntax for a method
+ * name is defined by Identifer of MethodDeclarator (JLS2 8.4).
+ * <p>
+ * The name of a constructor is always <code>null</code> and thus it
+ * must not be set.
+ * </p>
+ *
+ * @exception IllegalArgumentException if <code>null</code> is specified
+ */
+ public void setName(String name) throws IllegalArgumentException;
+ /**
+ * Sets the types and names of parameters in this method in the order they are
+ * to be declared. If both <code>types</code> and <code>names</code> are <code>null</code>
+ * this indicates that this method has no parameters.
+ * The syntax for parameter names is defined by Formal Parameters (JLS2 8.4.1).
+ * The syntax for type names is defined by Formal Parameters (JLS2 8.4.1).
+ * Type names must be specified as they would appear in source code. For
+ * example: <code>"File"</code>, <code>"java.io.File"</code>, or
+ * <code>"int[]"</code>.
+ *
+ * @param types the list of type names
+ * @param names the list of parameter name
+ * @exception IllegalArgumentException if the number of types and names do not
+ * match, or if either argument is <code>null</code>
+ */
+ public void setParameters(String[] types, String[] names)
+ throws IllegalArgumentException;
+ /**
+ * Sets the return type name. This has no effect on constructors.
+ * The syntax for return type name corresponds to ReturnType in
+ * MethodDeclaration (JLS2 8.4). Type names are specified as they appear in the
+ * source code; for example: <code>"File"</code>, <code>"java.io.File"</code>,
+ * <code>"int[]"</code>, or <code>"void"</code>.
+ *
+ * @param type the return type
+ * @exception IllegalArgumentException if <code>null</code> is specified
+ */
+ public void setReturnType(String type) throws IllegalArgumentException;
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMNode.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMNode.java
new file mode 100644
index 0000000000..ae6d79fda2
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMNode.java
@@ -0,0 +1,273 @@
+package org.eclipse.jdt.core.jdom;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.core.IJavaElement;
+import java.util.Enumeration;
+
+/**
+ * Nodes represent structural fragments of a Java source file, also known as document fragments. Their implementation
+ * is known as a DOM (Document Object Model) - in this case a JDOM (Java DOM). A root node (node
+ * with no parent or siblings) represents the root of a document fragment (DF). A complete Java document is
+ * represented by a compilation unit node (<code>IDOMCompilationUnit</code>). In this way, a DF is
+ * comprised of DFs, and a document itself (compilation unit) is also a DF.
+ * <p>
+ * A DF may be created empty and programmatically filled, or it may be created from
+ * a source code string. The <code>IDOMFactory</code> allows the creation of all kinds
+ * of nodes from source code strings. Manipulations performed on a DF are immediately
+ * reflected in the DF's contents.
+ * </p>
+ * <p>
+ * Children fragments are represented as a linked list of nodes. Children are inserted via their parent node, and
+ * are automatically linked up with previous and next nodes.
+ * </p>
+ * <p>
+ * The contents of any node (DF) may be retrieved at any time. In this way it is possible to retrieve
+ * source code representing fragments of the compilation unit (for example, a type or a method), since
+ * the contents of any node (not just the root node) may be obtained.
+ * </p>
+ * <p>
+ * The following manipulations on DFs are distinct:
+ * <ul>
+ * <li>clone - this creates a stand-alone copy of the DF that is in no way dependent on the DF that it was cloned from</li>
+ * <li>remove - this orphans a DF from its host DF. The removed DF may still be dependent on its previous host
+ * (perhaps to generate its contents), and hanging onto the fragment means that its previous host is also
+ * retained in memory.</li>
+ * <li>add/insert - this splices an un-parented DF (one that has been cloned, removed, or created stand-alone),
+ * into an existing DF such that the newly inserted DF is only dependent on its new host.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Wherever types are specified in DOM APIs, type names must be specified as they would appear
+ * in source code. The DOM does not have a notion of type signatures, only raw text. Example type
+ * names are <code>"Object"</code>, <code>"java.io.File"</code>, and <code>"int[]"</code>.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ */
+public interface IDOMNode extends Cloneable {
+
+ /**
+ * Node type constant indicating a compilation unit.
+ * Nodes of this type maybe by safely cast to <code>IDOMCompilationUnit</code>.
+ * @see #getNodeType
+ */
+ public static int COMPILATION_UNIT = 1;
+
+ /**
+ * Node type constant indicating a package declaration.
+ * Nodes of this type maybe by safely cast to <code>IDOMPackage</code>.
+ * @see #getNodeType
+ */
+ public static int PACKAGE = 2;
+
+ /**
+ * Node type constant indicating an import declaration.
+ * Nodes of this type maybe by safely cast to <code>IDOMImport</code>.
+ * @see #getNodeType
+ */
+ public static int IMPORT = 3;
+
+ /**
+ * Node type constant indicating a type declaration.
+ * Nodes of this type maybe by safely cast to <code>IDOMType</code>.
+ * @see #getNodeType
+ */
+ public static int TYPE = 4;
+
+ /**
+ * Node type constant indicating a field declaration.
+ * Nodes of this type maybe by safely cast to <code>IDOMField</code>.
+ * @see #getNodeType
+ */
+ public static int FIELD = 5;
+
+ /**
+ * Node type constant indicating a method (or constructor) declaration.
+ * Nodes of this type maybe by safely cast to <code>IDOMMethod</code>.
+ * @see #getNodeType
+ */
+ public static int METHOD = 6;
+
+ /**
+ * Node type constant indicating an initializer declaration.
+ * Nodes of this type maybe by safely cast to <code>IDOMInitializer</code>.
+ * @see #getNodeType
+ */
+ public static int INITIALIZER = 7;
+
+ /**
+ * Adds the given un-parented node (document fragment) as the last child of this node.
+ *
+ * @param child the new child node
+ * @exception DOMException if any of the following conditions hold:<ul>
+ * <li>this node is not allowed to have children,</li>
+ * <li>the child is not of an allowable type</li>
+ * <li>the child already has a parent</li>
+ * <li>the child is an ancestor of this node</li>
+ * </ul>
+ * @exception IllegalArgumentException if the child is <code>null</code>
+ *
+ * @see #insertSibling
+ * @see #remove
+ */
+ public void addChild(IDOMNode child)
+ throws DOMException, IllegalArgumentException;
+ /**
+ * Returns whether this node is allowed to have children.
+ *
+ * @return <code>true</code> if this node can have children
+ */
+ public boolean canHaveChildren();
+ /**
+ * Returns a stand-alone copy of the document fragment represented by this node that
+ * is in no way dependent on the document this node is part of.
+ *
+ * @return a copy of type <code>IDOMNode</code>
+ * @see #addChild
+ * @see #insertSibling
+ * @see #remove
+ */
+ public Object clone();
+ /**
+ * Returns the current contents of this document fragment as a character array.
+ * <p>
+ * Note: To obtain complete source for the".java" file, ask a compilation unit
+ * node for its contents.
+ * </p>
+ *
+ * @return the contents, or <code>null</code> if this node has no contents
+ */
+ public char[] getCharacters();
+ /**
+ * Returns the first named child of this node with the given name.
+ *
+ * @param name the name
+ * @return the child node, or <code>null</code> if no such child exists
+ */
+ public IDOMNode getChild(String name);
+ /**
+ * Returns an enumeration of children of this node. Returns an empty enumeration
+ * if this node has no children (including nodes that cannot have children).
+ * Children appear in the order in which they are declared in the source code.
+ *
+ * @return an enumeration of the children
+ */
+ public Enumeration getChildren();
+ /**
+ * Returns the current contents of this document fragment.
+ * <p>
+ * Note: To obtain complete source for the".java" file, ask a compilation unit
+ * node for its contents.
+ * </p>
+ *
+ * @return the contents, or <code>null</code> if this node has no contents
+ */
+ public String getContents();
+ /**
+ * Returns the first child of this node.
+ * Children appear in the order in which they exist in the source code.
+ *
+ * @return the first child, or <code>null</code> if this node has no children
+ * @see #getChildren
+ */
+ public IDOMNode getFirstChild();
+ /**
+ * Returns a handle for the Java element associated with this
+ * document fragment, based on the parent Java element.
+ *
+ * @param parent the parent Java element
+ * @exception IllegalArgumentException if the parent element is not
+ * of a valid parent type for this node
+ */
+ public IJavaElement getJavaElement(IJavaElement parent)
+ throws IllegalArgumentException;
+ /**
+ * Returns the name of this node.
+ * More details are provided in each of the subtypes.
+ *
+ * @return the name, or <code>null</code> if it has no name
+ */
+ public String getName();
+ /**
+ * Returns the sibling node immediately following this node.
+ *
+ * @return the next node, or <code>null</code> if there is no following node
+ */
+ public IDOMNode getNextNode();
+ /**
+ * Returns the type of this node.
+ *
+ * @return one of the node type constants defined in <code>IDOMNode</code>
+ */
+ public int getNodeType();
+ /**
+ * Returns the parent of this node.
+ *
+ * @return the parent node, or <code>null</code> if this node does not have a
+ * parent
+ */
+ public IDOMNode getParent();
+ /**
+ * Returns the sibling node immediately preceding this node.
+ *
+ * @return the previous node, or <code>null</code> if there is no preceding node
+ */
+ public IDOMNode getPreviousNode();
+ /**
+ * Inserts the given un-parented node as a sibling of this node, immediately before
+ * this node.
+ *
+ * @param sibling the new sibling node
+ * @exception DOMException if any of the following conditions hold:<ul>
+ * <li>this node is a document fragment root</li>
+ * <li>the sibling is not of the correct type</li>
+ * <li>the sibling already has a parent</li>
+ * <li>this sibling is an ancestor of this node</li>
+ * </ul>
+ * @exception IllegalArgumentException if the sibling is <code>null</code>
+ *
+ * @see #addChild
+ * @see #clone
+ * @see #remove
+ */
+ public void insertSibling(IDOMNode sibling)
+ throws DOMException, IllegalArgumentException;
+ /**
+ * Returns whether the given node is an allowable child for this node.
+ *
+ * @param node the potential child node
+ * @return <code>true</code> if the given node is an allowable child
+ */
+ public boolean isAllowableChild(IDOMNode node);
+ /**
+ * Returns whether this node's signature is equivalent to the given
+ * node's signature. In other words, if the nodes were siblings,
+ * would the declarations collide because they represent the same declaration.
+ *
+ * @param node the other node
+ * @return <code>true</code> if the nodes have equivalent signatures
+ */
+ public boolean isSignatureEqual(IDOMNode node);
+ /**
+ * Separates this node from its parent and siblings, maintaing any ties that this node
+ * has to the underlying document fragment. A document fragment that is removed
+ * from its host document may still be dependent on that host document until it is
+ * inserted into a different document. Removing a root node has no effect.
+ *
+ * @see #addChild
+ * @see #clone
+ * @see #insertSibling
+ */
+ public void remove();
+ /**
+ * Sets the name of this node. Name format depends on node type.
+ * More details are provided in each of the subtypes.
+ *
+ * @param name the name, or <code>null</code> to clear the name
+ */
+ public void setName(String name);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMPackage.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMPackage.java
new file mode 100644
index 0000000000..2771fdef74
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMPackage.java
@@ -0,0 +1,19 @@
+package org.eclipse.jdt.core.jdom;
+
+public interface IDOMPackage extends IDOMNode {
+ /**
+ * The <code>IDOMPackage</code> refinement of this <code>IDOMNode</code>
+ * method returns the name of this package declaration, or <code>null</code>
+ * if it has none. The syntax for a package name corresponds to PackageName
+ * as defined by PackageDeclaration (JLS2 7.4).
+ */
+ public String getName();
+ /**
+ * The <code>IDOMPackage</code> refinement of this <code>IDOMNode</code>
+ * method sets the name of this package declaration. The syntax for a package
+ * name corresponds to PackageName as defined by PackageDeclaration (JLS2 7.4).
+ * A <code>null</code> name indicates an empty package declaration; that is,
+ * <code>getContents</code> returns the empty string.
+ */
+ public void setName(String name);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMType.java
new file mode 100644
index 0000000000..a760db7d41
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMType.java
@@ -0,0 +1,105 @@
+package org.eclipse.jdt.core.jdom;
+
+public interface IDOMType extends IDOMMember {
+ /**
+ * Adds the given interface name to the names of interfaces that this type implements or extends
+ * (the name will be added after the existing interface names). This is a convenience method.
+ *
+ * For classes, this represents the interfaces that this class implements.
+ * For interfaces, this represents the interfaces that this interface extends.
+ * The name may or may not be fully qualified.
+ *
+ * @param interfaceName the syntax for an interface name is defined by
+ * Interfaces in ClassDeclaration (JLS2 8.1). Type names must be specified as they would
+ * appear in source code. For example: "Cloneable", "java.io.Serializable".
+ *
+ * @exception IllegalArgumentException if <code>null</code> is specified
+ */
+ public void addSuperInterface(String interfaceName)
+ throws IllegalArgumentException;
+ /**
+ * The <code>IDOMType</code> refinement of this <code>IDOMNode</code>
+ * method returns the name of this type. The name of a class is defined by
+ * ClassDeclaration (JLS2 8.1); the name of an interface is defined by
+ * InterfaceDeclaration (JLS2 9.1).
+ */
+ public String getName();
+ /**
+ * Returns the name of this type's superclass. The syntax for a superclass name
+ * is specified by Super in ClassDeclaration (JLS2 8.1). Type names must be
+ * specified as they would appear in source code. For example:
+ * <code>"Object"</code>, or <code>"java.io.File"</code>.
+ *
+ * @return the superclass name, or <code>null</code> if this type represents
+ * an interface or if no superclass has been assigned to this class
+ */
+ public String getSuperclass();
+ /**
+ * Returns the names of interfaces that this type implements or extends,
+ * in the order in which they are listed in the source, or an empty array
+ * if no superinterfaces are present. The syntax for interface names is
+ * defined by Interfaces in ClassDeclaration (JLS2 8.1). Type names appear
+ * as they would in source code. For example: <code>"Cloneable"</code>,
+ * or <code>"java.io.Serializable"</code>.
+ * <p>
+ * For classes, this method returns the interfaces that this class implements.
+ * For interfaces, this method returns the interfaces that this interface extends.
+ * </p>
+ *
+ * @return the list of interface names
+ */
+ public String[] getSuperInterfaces();
+ /**
+ * Returns whether this type is a class.
+ *
+ * @return <code>true</code> for classes, and <code>false</code> for interfaces
+ */
+ public boolean isClass();
+ /**
+ * Sets whether this type is a class or an interface. If this type is
+ * a class, and is changed to an interface, this type's superclass
+ * becomes <code>null</code>. When a class becomes an interface or an
+ * interface becomes a class, superinterfaces remain (as part of an
+ * <code>implements</code> clause for classes, or an <code>extends</code>
+ * clause for interfaces).
+ *
+ * @param b <code>true</code> for classes, and <code>false</code> for interfaces
+ */
+ public void setClass(boolean b);
+ /**
+ * The <code>IDOMType</code> refinement of this <code>IDOMNode</code>
+ * method sets the name of this type. The name of a class is defined by
+ * ClassDeclaration (JLS2 8.1); the name of an interface is defined by
+ * InterfaceDeclaration (JLS2 9.1).
+ *
+ * @exception IllegalArgumentException if <code>null</code> is specified
+ */
+ public void setName(String name) throws IllegalArgumentException;
+ /**
+ * Sets the name of this type's superclass. Has nbo effect if this type
+ * represents an interface. A <code>null</code> name indicates that no
+ * superclass name (extends clause) should appear in the source code.
+ * The syntax for a superclass name is specified by Super in ClassDeclaration
+ * (JLS2 8.1). Type names must be specified as they would appear in source code.
+ * For example: <code>"Object"</code>, or <code>"java.io.File"</code>.
+ *
+ * @param superclassName the superclass name, or <code>null</code> if this type
+ * should have to no explicitly specified superclass
+ */
+ public void setSuperclass(String superclassName);
+ /**
+ * Sets the names of interfaces that this type implements or extends,
+ * in the order in which they are to be listed in the source. An empty array
+ * parameter indicates that no superinterfaces are present. The syntax for
+ * interface names is defined by Interfaces in ClassDeclaration (JLS2 8.1).
+ * Type names appear as they would in source code. For example:
+ * <code>"Cloneable"</code>, or <code>"java.io.Serializable"</code>.
+ * <p>
+ * For classes, this method sets the interfaces that this class implements.
+ * For interfaces, this method sets the interfaces that this interface extends.
+ * </p>
+ *
+ * @param interfaceNames the list of interface names
+ */
+ public void setSuperInterfaces(String[] interfaceNames);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Assert.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Assert.java
new file mode 100644
index 0000000000..e11344898d
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Assert.java
@@ -0,0 +1,100 @@
+package org.eclipse.jdt.internal.core;
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.core.*;
+
+public final class Assert {
+ /* This class is not intended to be instantiated. */
+ private Assert() {
+ }
+
+ /** Asserts that an argument is legal. If the given boolean is
+ * not <code>true</code>, an <code>IllegalArgumentException</code>
+ * is thrown.
+ *
+ * @param expression the outcode of the check
+ * @return <code>true</code> if the check passes (does not return
+ * if the check fails)
+ * @exception IllegalArgumentException if the legality test failed
+ */
+ public static boolean isLegal(boolean expression) {
+ return isLegal(expression, "");
+ }
+
+ /** Asserts that an argument is legal. If the given boolean is
+ * not <code>true</code>, an <code>IllegalArgumentException</code>
+ * is thrown.
+ * The given message is included in that exception, to aid debugging.
+ *
+ * @param expression the outcode of the check
+ * @param message the message to include in the exception
+ * @return <code>true</code> if the check passes (does not return
+ * if the check fails)
+ * @exception IllegalArgumentException if the legality test failed
+ */
+ public static boolean isLegal(boolean expression, String message) {
+ if (!expression)
+ throw new IllegalArgumentException(message);
+ return expression;
+ }
+
+ /** Asserts that the given object is not <code>null</code>. If this
+ * is not the case, some kind of unchecked exception is thrown.
+ *
+ * @param object the value to test
+ * @exception IllegalArgumentException if the object is <code>null</code>
+ */
+ public static void isNotNull(Object object) {
+ isNotNull(object, "");
+ }
+
+ /** Asserts that the given object is not <code>null</code>. If this
+ * is not the case, some kind of unchecked exception is thrown.
+ * The given message is included in that exception, to aid debugging.
+ *
+ * @param object the value to test
+ * @param message the message to include in the exception
+ * @exception IllegalArgumentException if the object is <code>null</code>
+ */
+ public static void isNotNull(Object object, String message) {
+ if (object == null)
+ throw new AssertionFailedException("null argument;" + message);
+ }
+
+ /** Asserts that the given boolean is <code>true</code>. If this
+ * is not the case, some kind of unchecked exception is thrown.
+ *
+ * @param expression the outcode of the check
+ * @return <code>true</code> if the check passes (does not return
+ * if the check fails)
+ */
+ public static boolean isTrue(boolean expression) {
+ return isTrue(expression, "");
+ }
+
+ /** Asserts that the given boolean is <code>true</code>. If this
+ * is not the case, some kind of unchecked exception is thrown.
+ * The given message is included in that exception, to aid debugging.
+ *
+ * @param expression the outcode of the check
+ * @param message the message to include in the exception
+ * @return <code>true</code> if the check passes (does not return
+ * if the check fails)
+ */
+ public static boolean isTrue(boolean expression, String message) {
+ if (!expression)
+ throw new AssertionFailedException("assertion failed; " + message);
+ return expression;
+ }
+
+ public static class AssertionFailedException extends RuntimeException {
+ public AssertionFailedException() {
+ }
+ public AssertionFailedException(String detail) {
+ super(detail);
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BasicCompilationUnit.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BasicCompilationUnit.java
new file mode 100644
index 0000000000..531fb5fa4a
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BasicCompilationUnit.java
@@ -0,0 +1,85 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+import java.io.*;
+
+/**
+ * A basic implementation of <code>ICompilationUnit</code>
+ * for use in the <code>SourceMapper</code>./
+ * @see ICompilationUnit
+ */
+
+public class BasicCompilationUnit implements ICompilationUnit {
+ protected char[] contents;
+ protected char[] fileName;
+ protected char[] mainTypeName;
+ public BasicCompilationUnit(char[] contents, String fileName) {
+ this.contents = contents;
+ this.fileName = fileName.toCharArray();
+
+ int start = fileName.lastIndexOf("/") + 1;
+ if (start == 0 || start < fileName.lastIndexOf("\\"))
+ start = fileName.lastIndexOf("\\") + 1;
+
+ int end = fileName.lastIndexOf(".");
+ if (end == -1)
+ end = fileName.length();
+
+ this.mainTypeName = fileName.substring(start, end).toCharArray();
+ }
+
+ public char[] getContents() {
+ if (contents != null)
+ return contents; // answer the cached source
+
+ // otherwise retrieve it
+ BufferedReader reader = null;
+ try {
+ File file = new File(new String(fileName));
+ reader = new BufferedReader(new FileReader(file));
+ int length;
+ char[] contents = new char[length = (int) file.length()];
+ int len = 0;
+ int readSize = 0;
+ while ((readSize != -1) && (len != length)) {
+ // See PR 1FMS89U
+ // We record first the read size. In this case len is the actual read size.
+ len += readSize;
+ readSize = reader.read(contents, len, length - len);
+ }
+ reader.close();
+ // See PR 1FMS89U
+ // Now we need to resize in case the default encoding used more than one byte for each
+ // character
+ if (len != length)
+ System.arraycopy(contents, 0, (contents = new char[len]), 0, len);
+ return contents;
+ } catch (FileNotFoundException e) {
+ } catch (IOException e) {
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (IOException ioe) {
+ }
+ }
+ };
+ return new char[0];
+ }
+
+ public char[] getFileName() {
+ return fileName;
+ }
+
+ public char[] getMainTypeName() {
+ return mainTypeName;
+ }
+
+ public String toString() {
+ return "CompilationUnit: " + new String(fileName);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryField.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryField.java
new file mode 100644
index 0000000000..567c08dace
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryField.java
@@ -0,0 +1,57 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.internal.compiler.env.IBinaryField;
+import org.eclipse.jdt.core.*;
+
+/**
+ * @see IField
+ */
+
+/* package */
+class BinaryField extends BinaryMember implements IField {
+
+ /**
+ * Constructs a handle to the field with the given name in the specified type.
+ */
+ protected BinaryField(IType parent, String name) {
+ super(FIELD, parent, name);
+ }
+
+ /**
+ * @see IField
+ */
+ public Object getConstant() throws JavaModelException {
+ IBinaryField info = (IBinaryField) getRawInfo();
+ return convertConstant(info.getConstant());
+ }
+
+ /**
+ * @see IMember
+ */
+ public int getFlags() throws JavaModelException {
+ IBinaryField info = (IBinaryField) getRawInfo();
+ return info.getModifiers();
+ }
+
+ /**
+ * @see JavaElement#getHandleMemento()
+ */
+ protected char getHandleMementoDelimiter() {
+ return JavaElement.JEM_FIELD;
+ }
+
+ /**
+ * @see IField
+ */
+ public String getTypeSignature() throws JavaModelException {
+ IBinaryField info = (IBinaryField) getRawInfo();
+ return new String(ClassFile.translatedName(info.getTypeName()));
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMember.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMember.java
new file mode 100644
index 0000000000..944507d67e
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMember.java
@@ -0,0 +1,128 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.jdt.core.*;
+
+/**
+ * Common functionality for Binary member handles.
+ */
+public class BinaryMember extends Member {
+ /**
+ * Constructs a binary member.
+ */
+ protected BinaryMember(int type, IJavaElement parent, String name) {
+ super(type, parent, name);
+ }
+
+ /**
+ * @see ISourceManipulation
+ */
+ public void copy(
+ IJavaElement container,
+ IJavaElement sibling,
+ String rename,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this));
+ }
+
+ /**
+ * @see ISourceReference
+ */
+ public ISourceRange getNameRange() {
+ SourceMapper mapper = getSourceMapper();
+ if (mapper != null) {
+ return mapper.getNameRange(this);
+ } else {
+ return SourceMapper.fgUnknownRange;
+ }
+ }
+
+ /**
+ * @see ISourceReference
+ */
+ public ISourceRange getSourceRange() throws JavaModelException {
+ SourceMapper mapper = getSourceMapper();
+ if (mapper != null) {
+ return mapper.getSourceRange(this);
+ } else {
+ return SourceMapper.fgUnknownRange;
+ }
+ }
+
+ /**
+ * @see IMember
+ */
+ public boolean isBinary() {
+ return true;
+ }
+
+ /**
+ * @see IJavaElement
+ */
+ public boolean isStructureKnown() throws JavaModelException {
+ return ((IJavaElement) getOpenableParent()).isStructureKnown();
+ }
+
+ /**
+ * @see ISourceManipulation
+ */
+ public void move(
+ IJavaElement container,
+ IJavaElement sibling,
+ String rename,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this));
+ }
+
+ /**
+ * Opens this element and all parents that are not already open.
+ *
+ * @exception NotPresentException this element is not present or accessable
+ */
+ protected void openHierarchy() throws JavaModelException {
+ Openable openableParent = (Openable) getOpenableParent();
+ if (openableParent != null) {
+ JavaElementInfo openableParentInfo =
+ (JavaElementInfo) fgJavaModelManager.getInfo((IJavaElement) openableParent);
+ if (openableParentInfo == null) {
+ openableParent.openWhenClosed(null);
+ openableParentInfo =
+ (JavaElementInfo) fgJavaModelManager.getInfo((IJavaElement) openableParent);
+ }
+ ClassFileInfo cfi = (ClassFileInfo) openableParentInfo;
+ cfi.getBinaryChildren(); // forces the initialization
+ }
+ }
+
+ /**
+ * @see ISourceManipulation
+ */
+ public void rename(String name, boolean force, IProgressMonitor monitor)
+ throws JavaModelException {
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this));
+ }
+
+ /**
+ * Sets the contents of this element.
+ * Throws an exception as this element is read only.
+ */
+ public void setContents(String contents, IProgressMonitor monitor)
+ throws JavaModelException {
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this));
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMethod.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMethod.java
new file mode 100644
index 0000000000..7b634e949a
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMethod.java
@@ -0,0 +1,188 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.internal.compiler.env.IBinaryMethod;
+import org.eclipse.jdt.core.*;
+
+/**
+ * @see IMethod
+ */
+
+/* package */
+class BinaryMethod extends BinaryMember implements IMethod {
+
+ /**
+ * The parameter type signatures of the method - stored locally
+ * to perform equality test. <code>null</code> indicates no
+ * parameters.
+ */
+ protected String[] fParameterTypes;
+ /**
+ * The parameter names for the method.
+ */
+ protected String[] fParameterNames;
+
+ /**
+ * An empty list of Strings
+ */
+ protected static final String[] fgEmptyList = new String[] {
+ };
+
+ protected String[] fExceptionTypes;
+ protected String fReturnType;
+ protected BinaryMethod(IType parent, String name, String[] parameterTypes) {
+ super(METHOD, parent, name);
+ Assert.isTrue(name.indexOf('.') == -1);
+ if (parameterTypes == null) {
+ fParameterTypes = fgEmptyList;
+ } else {
+ fParameterTypes = parameterTypes;
+ }
+ }
+
+ public boolean equals(Object o) {
+ return super.equals(o)
+ && Util.equalArraysOrNull(fParameterTypes, ((BinaryMethod) o).fParameterTypes);
+ }
+
+ /**
+ * @see IMethod
+ */
+ public String[] getExceptionTypes() throws JavaModelException {
+ if (fExceptionTypes == null) {
+ IBinaryMethod info = (IBinaryMethod) getRawInfo();
+ char[][] eTypeNames = info.getExceptionTypeNames();
+ if (eTypeNames == null || eTypeNames.length == 0) {
+ fExceptionTypes = fgEmptyList;
+ } else {
+ eTypeNames = ClassFile.translatedNames(eTypeNames);
+ fExceptionTypes = new String[eTypeNames.length];
+ for (int j = 0, length = eTypeNames.length; j < length; j++) {
+ // 1G01HRY: ITPJCORE:WINNT - method.getExceptionType not in correct format
+ int nameLength = eTypeNames[j].length;
+ char[] convertedName = new char[nameLength + 2];
+ System.arraycopy(eTypeNames[j], 0, convertedName, 1, nameLength);
+ convertedName[0] = 'L';
+ convertedName[nameLength + 1] = ';';
+ fExceptionTypes[j] = new String(convertedName);
+ }
+ }
+ }
+ return fExceptionTypes;
+ }
+
+ /**
+ * @see IMember
+ */
+ public int getFlags() throws JavaModelException {
+ IBinaryMethod info = (IBinaryMethod) getRawInfo();
+ return info.getModifiers();
+ }
+
+ /**
+ * @see JavaElement#getHandleMemento()
+ */
+ public String getHandleMemento() {
+ StringBuffer buff =
+ new StringBuffer(((JavaElement) getParent()).getHandleMemento());
+ buff.append(getHandleMementoDelimiter());
+ buff.append(getElementName());
+ for (int i = 0; i < fParameterTypes.length; i++) {
+ buff.append(getHandleMementoDelimiter());
+ buff.append(fParameterTypes[i]);
+ }
+ return buff.toString();
+ }
+
+ /**
+ * @see JavaElement#getHandleMemento()
+ */
+ protected char getHandleMementoDelimiter() {
+ return JavaElement.JEM_METHOD;
+ }
+
+ /**
+ * @see IMethod
+ */
+ public int getNumberOfParameters() {
+ return fParameterTypes == null ? 0 : fParameterTypes.length;
+ }
+
+ /**
+ * @see IMethod
+ */
+ public String[] getParameterNames() throws JavaModelException {
+ if (fParameterNames == null) {
+ IBinaryMethod info = (IBinaryMethod) getRawInfo();
+ int paramCount =
+ Signature.getParameterCount(new String(info.getMethodDescriptor()));
+ fParameterNames = new String[paramCount];
+ for (int i = 0; i < paramCount; i++) {
+ fParameterNames[i] = "arg" + i;
+ }
+ }
+ return fParameterNames;
+ }
+
+ /**
+ * @see IMethod
+ */
+ public String[] getParameterTypes() {
+ return fParameterTypes;
+ }
+
+ /**
+ * @see IMethod
+ */
+ public String getReturnType() throws JavaModelException {
+ IBinaryMethod info = (IBinaryMethod) getRawInfo();
+ if (fReturnType == null) {
+ String returnType =
+ Signature.getReturnType(new String(info.getMethodDescriptor()));
+ fReturnType = new String(ClassFile.translatedName(returnType.toCharArray()));
+ }
+ return fReturnType;
+ }
+
+ /**
+ * @see IMethod
+ */
+ public String getSignature() throws JavaModelException {
+ IBinaryMethod info = (IBinaryMethod) getRawInfo();
+ return new String(info.getMethodDescriptor());
+ }
+
+ /**
+ * @see IMethod
+ */
+ public boolean isConstructor() throws JavaModelException {
+ IBinaryMethod info = (IBinaryMethod) getRawInfo();
+ return info.isConstructor();
+ }
+
+ /**
+ */
+ public String readableName() {
+
+ StringBuffer buffer = new StringBuffer(super.readableName());
+ buffer.append("(");
+ String[] parameterTypes = this.getParameterTypes();
+ int length;
+ if (parameterTypes != null && (length = parameterTypes.length) > 0) {
+ for (int i = 0; i < length; i++) {
+ buffer.append(Signature.toString(parameterTypes[i]));
+ if (i < length - 1) {
+ buffer.append(", ");
+ }
+ }
+ }
+ buffer.append(")");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java
new file mode 100644
index 0000000000..83aced1377
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java
@@ -0,0 +1,413 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.core.resources.*;
+import java.util.Vector;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.compiler.env.IBinaryType;
+import org.eclipse.jdt.internal.codeassist.ISelectionRequestor;
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.compiler.ConfigurableOption;
+
+/**
+ * Parent is an IClassFile.
+ *
+ * @see IType
+ */
+
+public class BinaryType extends BinaryMember implements IType {
+ private static final IField[] NO_FIELDS = new IField[0];
+ private static final IMethod[] NO_METHODS = new IMethod[0];
+ private static final IType[] NO_TYPES = new IType[0];
+ private static final IInitializer[] NO_INITIALIZERS = new IInitializer[0];
+ private static final String[] NO_STRINGS = new String[0];
+ protected BinaryType(IJavaElement parent, String name) {
+ super(TYPE, parent, name);
+ Assert.isTrue(name.indexOf('.') == -1);
+ }
+
+ /**
+ * @see IOpenable
+ */
+ public void close() throws JavaModelException {
+ Object info = fgJavaModelManager.peekAtInfo(this);
+ if (info != null) {
+ ClassFileInfo cfi = getClassFileInfo();
+ if (cfi.hasReadBinaryChildren()) {
+ try {
+ IJavaElement[] children = getChildren();
+ for (int i = 0, size = children.length; i < size; ++i) {
+ JavaElement child = (JavaElement) children[i];
+ child.close();
+ }
+ } catch (JavaModelException e) {
+ }
+ }
+ closing(info);
+ fgJavaModelManager.removeInfo(this);
+ }
+ }
+
+ /**
+ * Remove my cached children from the Java Model
+ */
+ protected void closing(Object info) throws JavaModelException {
+ ClassFileInfo cfi = getClassFileInfo();
+ cfi.removeBinaryChildren();
+ }
+
+ /**
+ * @see IType
+ */
+ public IField createField(
+ String contents,
+ IJavaElement sibling,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this));
+ }
+
+ /**
+ * @see IType
+ */
+ public IInitializer createInitializer(
+ String contents,
+ IJavaElement sibling,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this));
+ }
+
+ /**
+ * @see IType
+ */
+ public IMethod createMethod(
+ String contents,
+ IJavaElement sibling,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this));
+ }
+
+ /**
+ * @see IType
+ */
+ public IType createType(
+ String contents,
+ IJavaElement sibling,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this));
+ }
+
+ /**
+ * @see IParent
+ */
+ public IJavaElement[] getChildren() throws JavaModelException {
+ // ensure present
+ // fix for 1FWWVYT
+ if (!exists()) {
+ throw newNotPresentException();
+ }
+ // get children
+ ClassFileInfo cfi = getClassFileInfo();
+ return cfi.getBinaryChildren();
+ }
+
+ protected ClassFileInfo getClassFileInfo() throws JavaModelException {
+ ClassFile cf = (ClassFile) fParent;
+ return (ClassFileInfo) cf.getElementInfo();
+ }
+
+ /**
+ * @see IMember
+ */
+ public IType getDeclaringType() {
+ try {
+ char[] enclosingTypeName = ((IBinaryType) getRawInfo()).getEnclosingTypeName();
+ if (enclosingTypeName == null) {
+ return null;
+ }
+ enclosingTypeName = ClassFile.unqualifiedName(enclosingTypeName);
+ return getPackageFragment()
+ .getClassFile(new String(enclosingTypeName) + ".class")
+ .getType();
+ } catch (JavaModelException npe) {
+ return null;
+ }
+ }
+
+ /**
+ * @see IType#getField
+ */
+ public IField getField(String name) {
+ return new BinaryField(this, name);
+ }
+
+ /**
+ * @see IType
+ */
+ public IField[] getFields() throws JavaModelException {
+ Vector v = getChildrenOfType(FIELD);
+ int size;
+ if ((size = v.size()) == 0) {
+ return NO_FIELDS;
+ } else {
+ IField[] array = new IField[size];
+ v.copyInto(array);
+ return array;
+ }
+ }
+
+ /**
+ * @see IMember
+ */
+ public int getFlags() throws JavaModelException {
+ IBinaryType info = (IBinaryType) getRawInfo();
+ return info.getModifiers();
+ }
+
+ /**
+ * @see IType
+ */
+ public String getFullyQualifiedName() {
+ String packageName = getPackageFragment().getElementName();
+ if (packageName.equals(IPackageFragment.DEFAULT_PACKAGE_NAME)) {
+ return getTypeQualifiedName();
+ }
+ return packageName + '.' + getTypeQualifiedName();
+ }
+
+ /**
+ * @see IType
+ */
+ public IInitializer getInitializer(int occurrenceCount) {
+ return new Initializer(this, occurrenceCount);
+ }
+
+ /**
+ * @see IType
+ */
+ public IInitializer[] getInitializers() {
+ return NO_INITIALIZERS;
+ }
+
+ /**
+ * @see IType#getMethod
+ */
+ public IMethod getMethod(String name, String[] parameterTypeSignatures) {
+ return new BinaryMethod(this, name, parameterTypeSignatures);
+ }
+
+ /**
+ * @see IType
+ */
+ public IMethod[] getMethods() throws JavaModelException {
+ Vector v = getChildrenOfType(METHOD);
+ int size;
+ if ((size = v.size()) == 0) {
+ return NO_METHODS;
+ } else {
+ IMethod[] array = new IMethod[size];
+ v.copyInto(array);
+ return array;
+ }
+ }
+
+ /**
+ * @see IType
+ */
+ public IPackageFragment getPackageFragment() {
+ IJavaElement parent = fParent;
+ while (parent != null) {
+ if (parent.getElementType() == IJavaElement.PACKAGE_FRAGMENT) {
+ return (IPackageFragment) parent;
+ } else {
+ parent = parent.getParent();
+ }
+ }
+ Assert.isTrue(false); // should not happen
+ return null;
+ }
+
+ /**
+ * @see IType#getSuperclassName
+ */
+ public String getSuperclassName() throws JavaModelException {
+ IBinaryType info = (IBinaryType) getRawInfo();
+ char[] superclassName = info.getSuperclassName();
+ if (superclassName == null) {
+ return null;
+ }
+ return new String(ClassFile.translatedName(superclassName));
+ }
+
+ /**
+ * @see IType#getSuperInterfaceNames
+ */
+ public String[] getSuperInterfaceNames() throws JavaModelException {
+ IBinaryType info = (IBinaryType) getRawInfo();
+ char[][] names = info.getInterfaceNames();
+ int length;
+ if (names == null || (length = names.length) == 0) {
+ return NO_STRINGS;
+ }
+ names = ClassFile.translatedNames(names);
+ String[] strings = new String[length];
+ for (int i = 0; i < length; i++) {
+ strings[i] = new String(names[i]);
+ }
+ return strings;
+ }
+
+ /**
+ * @see IType#getType
+ */
+ public IType getType(String name) {
+ IClassFile classFile =
+ getPackageFragment().getClassFile(
+ getTypeQualifiedName() + "$" + name + ".class");
+ return new BinaryType(classFile, name);
+ }
+
+ /**
+ * @see IType#getTypeQualifiedName
+ */
+ public String getTypeQualifiedName() {
+ if (fParent.getElementType() == IJavaElement.CLASS_FILE) {
+ String name = fParent.getElementName();
+ return name.substring(0, name.lastIndexOf('.'));
+ }
+ if (fParent.getElementType() == IJavaElement.TYPE) {
+ return ((IType) fParent).getTypeQualifiedName() + '$' + fName;
+ }
+ Assert.isTrue(false); // should not be reachable
+ return null;
+ }
+
+ /**
+ * @see IType
+ */
+ public IType[] getTypes() throws JavaModelException {
+ Vector v = getChildrenOfType(TYPE);
+ int size;
+ if ((size = v.size()) == 0) {
+ return NO_TYPES;
+ } else {
+ IType[] array = new IType[size];
+ v.copyInto(array);
+ return array;
+ }
+ }
+
+ /**
+ * @see IParent
+ */
+ public boolean hasChildren() throws JavaModelException {
+ return getChildren().length > 0;
+ }
+
+ /**
+ * @see IType
+ */
+ public boolean isClass() throws JavaModelException {
+ return !isInterface();
+ }
+
+ /**
+ * @see IType#isInterface
+ */
+ public boolean isInterface() throws JavaModelException {
+ IBinaryType info = (IBinaryType) getRawInfo();
+ return info.isInterface();
+ }
+
+ /**
+ * @see IType
+ */
+ public ITypeHierarchy newSupertypeHierarchy(IProgressMonitor monitor)
+ throws JavaModelException {
+ CreateTypeHierarchyOperation op =
+ new CreateTypeHierarchyOperation(
+ this,
+ SearchEngine.createWorkspaceScope(),
+ false);
+ runOperation(op, monitor);
+ return op.getResult();
+ }
+
+ /**
+ * @see IType
+ */
+ public ITypeHierarchy newTypeHierarchy(IProgressMonitor monitor)
+ throws JavaModelException {
+ CreateTypeHierarchyOperation op =
+ new CreateTypeHierarchyOperation(
+ this,
+ SearchEngine.createWorkspaceScope(),
+ true);
+ runOperation(op, monitor);
+ return op.getResult();
+ }
+
+ /**
+ * @see IType
+ */
+ public ITypeHierarchy newTypeHierarchy(
+ IJavaProject project,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ if (project == null) {
+ throw new IllegalArgumentException("project argument cannot be null");
+ }
+ CreateTypeHierarchyOperation op =
+ new CreateTypeHierarchyOperation(
+ this,
+ SearchEngine.createJavaSearchScope(new IResource[] { project.getProject()}),
+ true);
+ runOperation(op, monitor);
+ return op.getResult();
+ }
+
+ /**
+ * Removes all cached info from the Java Model, including all children,
+ * but does not close this element.
+ */
+ protected void removeInfo() {
+ Object info = fgJavaModelManager.peekAtInfo(this);
+ if (info != null) {
+ try {
+ IJavaElement[] children = getChildren();
+ for (int i = 0, size = children.length; i < size; ++i) {
+ JavaElement child = (JavaElement) children[i];
+ child.removeInfo();
+ }
+ } catch (JavaModelException e) {
+ }
+ fgJavaModelManager.removeInfo(this);
+ try {
+ ClassFileInfo cfi = getClassFileInfo();
+ cfi.removeBinaryChildren();
+ } catch (JavaModelException npe) {
+ }
+ }
+ }
+
+ public String[][] resolveType(String typeName) throws JavaModelException {
+ // not implemented for binary types
+ return null;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Buffer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Buffer.java
new file mode 100644
index 0000000000..1632edaec1
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Buffer.java
@@ -0,0 +1,720 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * @see IBuffer
+ */
+public class Buffer implements IBuffer {
+ protected BufferManager fManager;
+ protected IFile fFile;
+ protected int fFlags;
+ protected char[] fContents;
+ protected Vector fChangeListeners;
+ protected IOpenable fOwner;
+ protected int fGapStart = -1;
+ protected int fGapEnd = -1;
+
+ protected int fHighWatermark = 300;
+ protected int fLowWatermark = 50;
+ protected Object fLock = new Object();
+
+ String lineSeparator;
+
+ protected static final int F_HAS_UNSAVED_CHANGES = 1;
+ protected static final int F_IS_READ_ONLY = 2;
+ protected static final int F_IS_CLOSED = 4;
+ /**
+ * Creates a new buffer without an underlying resource.
+ */
+ protected Buffer(
+ BufferManager manager,
+ char[] contents,
+ IOpenable owner,
+ boolean readOnly) {
+ fManager = manager;
+ fFile = null;
+ fContents = contents;
+ fOwner = owner;
+ fFlags |= F_HAS_UNSAVED_CHANGES;
+ setReadOnly(readOnly);
+ }
+
+ /**
+ * Creates a new buffer on an underlying resource.
+ */
+ protected Buffer(
+ BufferManager manager,
+ IFile file,
+ char[] contents,
+ IOpenable owner,
+ boolean readOnly) {
+ fManager = manager;
+ fFile = file;
+ fContents = contents;
+ fOwner = owner;
+ setReadOnly(readOnly);
+ }
+
+ /**
+ * @see IBuffer
+ */
+ public void addBufferChangedListener(IBufferChangedListener listener) {
+ if (fChangeListeners == null) {
+ fChangeListeners = new Vector(5);
+ }
+ if (!fChangeListeners.contains(listener)) {
+ fChangeListeners.addElement(listener);
+ }
+ }
+
+ /**
+ * The <code>sizeHint</code> represents the range that will be filled afterwards.
+ * If the gap is already at the right position, it must only be
+ * resized if it will be no longer between low and high watermark.
+ */
+ protected void adjustGap(int position, int sizeHint) {
+ if (position == fGapStart) {
+ int size = (fGapEnd - fGapStart) - sizeHint;
+ if (fLowWatermark <= size && size <= fHighWatermark)
+ return;
+ }
+ moveAndResizeGap(position, sizeHint);
+ }
+
+ /**
+ * Append the <code>text</code> to the actual content, the gap is moved
+ * to the end of the <code>text</code>.
+ */
+ public void append(char[] text) {
+ this.append(text, false);
+ }
+
+ /**
+ * Append the <code>text</code> to the actual content, the gap is moved
+ * to the end of the <code>text</code>.
+ */
+ public void append(char[] text, boolean convert) {
+ if (!isReadOnly()) {
+ if (text == null || text.length == 0) {
+ return;
+ }
+ if (convert)
+ text = this.normalizeCRs(text);
+ int length = getLength();
+ adjustGap(length, text.length);
+ System.arraycopy(text, 0, fContents, length, text.length);
+ fGapStart += text.length;
+ fFlags |= F_HAS_UNSAVED_CHANGES;
+ notifyChanged(new BufferChangedEvent(this, length, 0, new String(text)));
+ }
+ }
+
+ /**
+ * Append the <code>text</code> to the actual content, the gap is moved
+ * to the end of the <code>text</code>.
+ */
+ public void append(String text) {
+ this.append(text, false);
+ }
+
+ /**
+ * Append the <code>text</code> to the actual content, the gap is moved
+ * to the end of the <code>text</code>.
+ */
+ public void append(String text, boolean convert) {
+ if (text == null) {
+ return;
+ }
+ if (!isReadOnly()) {
+ if (convert)
+ text = this.normalizeCRs(text);
+ int textLength = text.length();
+ if (textLength == 0) {
+ return;
+ }
+ int length = getLength();
+ adjustGap(length, textLength);
+ System.arraycopy(text.toCharArray(), 0, fContents, length, textLength);
+ fGapStart += textLength;
+ fFlags |= F_HAS_UNSAVED_CHANGES;
+ notifyChanged(new BufferChangedEvent(this, length, 0, text));
+ }
+ }
+
+ /**
+ * @see IBuffer
+ */
+ public void close() throws IllegalArgumentException {
+ BufferChangedEvent event = null;
+ synchronized (fLock) {
+ if (isClosed())
+ return;
+ event = new BufferChangedEvent(this, 0, 0, null);
+ fContents = null;
+ fFlags |= F_IS_CLOSED;
+ fManager.removeBuffer(this);
+ }
+ notifyChanged(event); // notify outside of synchronized block
+ fChangeListeners = null;
+ }
+
+ /**
+ * Finds the first line separator used by the given text.
+ *
+ * @return </code>"\n"</code> or </code>"\r"</code> or </code>"\r\n"</code>,
+ * or <code>null</code> if none found
+ */
+ private String findLineSeparator(char[] text) {
+ // find the first line separator
+ int length = text.length;
+ if (length > 0) {
+ char nextChar = text[0];
+ for (int i = 0; i < length; i++) {
+ char currentChar = nextChar;
+ nextChar = i < length - 1 ? text[i + 1] : ' ';
+ switch (currentChar) {
+ case '\n' :
+ return "\n";
+ case '\r' :
+ return nextChar == '\n' ? "\r\n" : "\r";
+ }
+ }
+ }
+ // not found
+ return null;
+ }
+
+ /**
+ * @see IBuffer
+ */
+ public char getChar(int position) {
+ synchronized (fLock) {
+ if (position < fGapStart) {
+ return fContents[position];
+ }
+ int gapLength = fGapEnd - fGapStart;
+ return fContents[position + gapLength];
+ }
+ }
+
+ /**
+ * @see IBuffer
+ */
+ public char[] getCharacters() {
+ if (fContents == null)
+ return new char[0];
+ synchronized (fLock) {
+ if (fGapStart < 0) {
+ return fContents;
+ }
+ int length = fContents.length;
+ char[] contents = new char[length - fGapEnd + fGapStart];
+ System.arraycopy(fContents, 0, contents, 0, fGapStart);
+ System.arraycopy(fContents, fGapEnd, contents, fGapStart, length - fGapEnd);
+ return contents;
+ }
+ }
+
+ /**
+ * @see IBuffer
+ */
+ public String getContents() {
+ if (fContents == null)
+ return "";
+ synchronized (fLock) {
+ if (fGapStart < 0) {
+ return new String(fContents);
+ }
+ int length = fContents.length;
+ StringBuffer buffer = new StringBuffer(length - fGapEnd + fGapStart);
+ buffer.append(fContents, 0, fGapStart);
+ buffer.append(fContents, fGapEnd, length - fGapEnd);
+ return buffer.toString();
+ }
+ }
+
+ /**
+ * @see IBuffer
+ */
+ public int getLength() {
+ synchronized (fLock) {
+ int length = fGapEnd - fGapStart;
+ return (fContents.length - length);
+ }
+ }
+
+ /**
+ * Returns the line separator used by this buffer.
+ * Uses the given text if none found.
+ *
+ * @return </code>"\n"</code> or </code>"\r"</code> or </code>"\r\n"</code>
+ */
+ private String getLineSeparator(char[] text) {
+ if (this.lineSeparator == null) {
+ // search in this buffer's contents first
+ this.lineSeparator = this.findLineSeparator(this.getCharacters());
+ if (this.lineSeparator == null) {
+ // search in the given text
+ this.lineSeparator = this.findLineSeparator(text);
+ if (this.lineSeparator == null) {
+ // default to system line separator
+ return JavaModelManager.LINE_SEPARATOR;
+ }
+ }
+ }
+ return this.lineSeparator;
+ }
+
+ /**
+ * @see IBuffer
+ */
+ public IOpenable getOwner() {
+ return fOwner;
+ }
+
+ /**
+ * @see IBuffer
+ */
+ public String getText(int offset, int length) {
+ if (fContents == null)
+ return "";
+ synchronized (fLock) {
+ if (offset + length < fGapStart)
+ return new String(fContents, offset, length);
+ if (fGapStart < offset) {
+ int gapLength = fGapEnd - fGapStart;
+ return new String(fContents, offset + gapLength, length);
+ }
+ StringBuffer buf = new StringBuffer();
+ buf.append(fContents, offset, fGapStart - offset);
+ buf.append(fContents, fGapEnd, offset + length - fGapStart);
+ return buf.toString();
+ }
+ }
+
+ /**
+ * @see IBuffer
+ */
+ public IResource getUnderlyingResource() {
+ return fFile;
+ }
+
+ /**
+ * @see IBuffer
+ */
+ public boolean hasUnsavedChanges() {
+ return (fFlags & F_HAS_UNSAVED_CHANGES) != 0;
+ }
+
+ /**
+ * @see IBuffer
+ */
+ public boolean isClosed() {
+ return (fFlags & F_IS_CLOSED) != 0;
+ }
+
+ /**
+ * @see IBuffer
+ */
+ public boolean isReadOnly() {
+ return (fFlags & F_IS_READ_ONLY) != 0;
+ }
+
+ /**
+ * Moves the gap to location and adjust its size to the
+ * anticipated change size. The size represents the expected
+ * range of the gap that will be filled after the gap has been moved.
+ * Thus the gap is resized to actual size + the specified size and
+ * moved to the given position.
+ */
+ protected void moveAndResizeGap(int position, int size) {
+ char[] content = null;
+ int oldSize = fGapEnd - fGapStart;
+ int newSize = fHighWatermark + size;
+ if (newSize < 0) {
+ if (oldSize > 0) {
+ content = new char[fContents.length - oldSize];
+ System.arraycopy(fContents, 0, content, 0, fGapStart);
+ System.arraycopy(
+ fContents,
+ fGapEnd,
+ content,
+ fGapStart,
+ content.length - fGapStart);
+ fContents = content;
+ }
+ fGapStart = fGapEnd = position;
+ return;
+ }
+ content = new char[fContents.length + (newSize - oldSize)];
+ int newGapStart = position;
+ int newGapEnd = newGapStart + newSize;
+ if (oldSize == 0) {
+ System.arraycopy(fContents, 0, content, 0, newGapStart);
+ System.arraycopy(
+ fContents,
+ newGapStart,
+ content,
+ newGapEnd,
+ content.length - newGapEnd);
+ } else
+ if (newGapStart < fGapStart) {
+ int delta = fGapStart - newGapStart;
+ System.arraycopy(fContents, 0, content, 0, newGapStart);
+ System.arraycopy(fContents, newGapStart, content, newGapEnd, delta);
+ System.arraycopy(
+ fContents,
+ fGapEnd,
+ content,
+ newGapEnd + delta,
+ fContents.length - fGapEnd);
+ } else {
+ int delta = newGapStart - fGapStart;
+ System.arraycopy(fContents, 0, content, 0, fGapStart);
+ System.arraycopy(fContents, fGapEnd, content, fGapStart, delta);
+ System.arraycopy(
+ fContents,
+ fGapEnd + delta,
+ content,
+ newGapEnd,
+ content.length - newGapEnd);
+ }
+ fContents = content;
+ fGapStart = newGapStart;
+ fGapEnd = newGapEnd;
+ }
+
+ /**
+ * Normalizes the cariage returns in the given text.
+ * They are all changed to use this buffer's line sepatator.
+ */
+ private char[] normalizeCRs(char[] text) {
+ CharArrayBuffer buffer = new CharArrayBuffer();
+ int lineStart = 0;
+ int length = text.length;
+ if (length == 0)
+ return text;
+ String lineSeparator = this.getLineSeparator(text);
+ char nextChar = text[0];
+ for (int i = 0; i < length; i++) {
+ char currentChar = nextChar;
+ nextChar = i < length - 1 ? text[i + 1] : ' ';
+ switch (currentChar) {
+ case '\n' :
+ int lineLength = i - lineStart;
+ char[] line = new char[lineLength];
+ System.arraycopy(text, lineStart, line, 0, lineLength);
+ buffer.append(line);
+ buffer.append(lineSeparator);
+ lineStart = i + 1;
+ break;
+ case '\r' :
+ lineLength = i - lineStart;
+ line = new char[lineLength];
+ System.arraycopy(text, lineStart, line, 0, lineLength);
+ buffer.append(line);
+ buffer.append(lineSeparator);
+ if (nextChar == '\n') {
+ nextChar = ' ';
+ i++;
+ }
+ lineStart = i + 1;
+ break;
+ }
+ }
+ char[] lastLine;
+ if (lineStart > 0) {
+ int lastLineLength = length - lineStart;
+ if (lastLineLength > 0) {
+ lastLine = new char[lastLineLength];
+ System.arraycopy(text, lineStart, lastLine, 0, lastLineLength);
+ buffer.append(lastLine);
+ }
+ return buffer.getContents();
+ } else {
+ return text;
+ }
+ }
+
+ /**
+ * Normalizes the cariage returns in the given text.
+ * They are all changed to use this buffer's line sepatator.
+ */
+ private String normalizeCRs(String text) {
+ return new String(this.normalizeCRs(text.toCharArray()));
+ }
+
+ /**
+ * Notify the listeners that this buffer has changed.
+ * To avoid deadlock, this should not be called in a synchronized block.
+ */
+ protected void notifyChanged(BufferChangedEvent event) {
+ if (fChangeListeners != null) {
+ for (int i = 0, size = fChangeListeners.size(); i < size; ++i) {
+ IBufferChangedListener listener =
+ (IBufferChangedListener) fChangeListeners.elementAt(i);
+ listener.bufferChanged(event);
+ }
+ }
+ }
+
+ /**
+ * @see IBuffer
+ */
+ public void removeBufferChangedListener(IBufferChangedListener listener) {
+ if (fChangeListeners != null) {
+ fChangeListeners.removeElement(listener);
+ if (fChangeListeners.size() == 0) {
+ fChangeListeners = null;
+ }
+ }
+ }
+
+ /**
+ * Replaces <code>length</code> characters starting from <code>position</code> with <code>text<code>.
+ * After that operation, the gap is placed at the end of the
+ * inserted <code>text</code>.
+ */
+ public void replace(int position, int length, char[] text) {
+ this.replace(position, length, text, false);
+ }
+
+ /**
+ * Replaces <code>length</code> characters starting from <code>position</code> with <code>text<code>.
+ * After that operation, the gap is placed at the end of the
+ * inserted <code>text</code>.
+ */
+ public void replace(int position, int length, char[] text, boolean convert) {
+ if (!isReadOnly()) {
+ if (text == null) {
+ text = new char[0];
+ } else {
+ if (convert)
+ text = this.normalizeCRs(text);
+ }
+ synchronized (fLock) {
+ // move gap
+ adjustGap(position + length, text.length - length);
+
+ // overwrite
+ int min = Math.min(text.length, length);
+ for (int i = position, j = 0; i < position + min; i++, j++)
+ fContents[i] = text[j];
+ if (length > text.length) {
+ // enlarge the gap
+ fGapStart -= (length - text.length);
+ } else
+ if (text.length > length) {
+ // shrink gap
+ fGapStart += (text.length - length);
+ for (int i = length; i < text.length; i++)
+ fContents[position + i] = text[i];
+ }
+ }
+ fFlags |= F_HAS_UNSAVED_CHANGES;
+ String string = null;
+ if (text.length > 0) {
+ string = new String(text);
+ }
+ notifyChanged(new BufferChangedEvent(this, position, length, string));
+ }
+ }
+
+ /**
+ * Replaces <code>length</code> characters starting from <code>position</code> with <code>text<code>.
+ * After that operation, the gap is placed at the end of the
+ * inserted <code>text</code>.
+ */
+ public void replace(int position, int length, String text) {
+ this.replace(position, length, text, false);
+ }
+
+ /**
+ * Replaces <code>length</code> characters starting from <code>position</code> with <code>text<code>.
+ * After that operation, the gap is placed at the end of the
+ * inserted <code>text</code>.
+ */
+ public void replace(int position, int length, String text, boolean convert) {
+ if (!isReadOnly()) {
+ int textLength = 0;
+ if (text != null) {
+ if (convert)
+ text = this.normalizeCRs(text);
+ textLength = text.length();
+ }
+
+ synchronized (fLock) {
+ // move gap
+ adjustGap(position + length, textLength - length);
+
+ // overwrite
+ int min = Math.min(textLength, length);
+ for (int i = position, j = 0; i < position + min; i++, j++)
+ fContents[i] = text.charAt(j);
+ if (length > textLength) {
+ // enlarge the gap
+ fGapStart -= (length - textLength);
+ } else
+ if (textLength > length) {
+ // shrink gap
+ fGapStart += (textLength - length);
+ for (int i = length; i < textLength; i++)
+ fContents[position + i] = text.charAt(i);
+ }
+ }
+ fFlags |= F_HAS_UNSAVED_CHANGES;
+
+ notifyChanged(new BufferChangedEvent(this, position, length, text));
+ }
+ }
+
+ /**
+ * @see IBuffer
+ */
+ public void save(IProgressMonitor progress, boolean force)
+ throws JavaModelException {
+
+ // determine if saving is required
+ if (isReadOnly() || fFile == null) {
+ return;
+ }
+ synchronized (fLock) {
+ if (!hasUnsavedChanges())
+ return;
+ byte[] bytes = getContents().getBytes();
+ ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
+
+ // use a platform operation to update the resource contents
+ try {
+ fFile.setContents(stream, force, true, null); // record history
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ }
+
+ // the resource no longer has unsaved changes
+ fFlags &= ~(F_HAS_UNSAVED_CHANGES);
+ }
+ }
+
+ /**
+ * @see IBuffer
+ */
+ public void setContents(char[] contents) {
+ this.setContents(contents, false);
+ }
+
+ /**
+ * @see IBuffer
+ */
+ public void setContents(char[] contents, boolean convert) {
+ if (!isReadOnly()) {
+ String string = null;
+ if (contents != null) {
+ if (convert)
+ contents = this.normalizeCRs(contents);
+ string = new String(contents);
+ }
+ BufferChangedEvent event =
+ new BufferChangedEvent(this, 0, this.getLength(), string);
+ synchronized (fLock) {
+ fContents = contents;
+ fFlags |= F_HAS_UNSAVED_CHANGES;
+ fGapStart = -1;
+ fGapEnd = -1;
+ }
+ notifyChanged(event);
+ }
+ }
+
+ /**
+ * @see IBuffer
+ */
+ public void setContents(String contents) {
+ this.setContents(contents, false);
+ }
+
+ /**
+ * @see IBuffer
+ */
+ public void setContents(String contents, boolean convert) {
+ if (!isReadOnly()) {
+ char[] charContents = null;
+ if (contents != null) {
+ charContents = contents.toCharArray();
+ if (convert) {
+ charContents = this.normalizeCRs(charContents);
+ contents = new String(charContents);
+ }
+ }
+ BufferChangedEvent event =
+ new BufferChangedEvent(this, 0, this.getLength(), contents);
+ synchronized (fLock) {
+ fContents = charContents;
+ fFlags |= F_HAS_UNSAVED_CHANGES;
+ fGapStart = -1;
+ fGapEnd = -1;
+ }
+ notifyChanged(event);
+ }
+ }
+
+ /**
+ * Sets this <code>Buffer</code> to be read only.
+ */
+ protected void setReadOnly(boolean readOnly) {
+ if (readOnly) {
+ fFlags |= F_IS_READ_ONLY;
+ } else {
+ fFlags &= ~(F_IS_READ_ONLY);
+ }
+ }
+
+ /**
+ * Adjusts low and high water mark to the specified values.
+ */
+ public void setWaterMarks(int low, int high) {
+ fLowWatermark = low;
+ fHighWatermark = high;
+ }
+
+ public String toString() {
+ char[] contents = this.getCharacters();
+ int length = contents.length;
+ StringBuffer buffer = new StringBuffer(length);
+ buffer.append("Buffer:\n");
+ for (int i = 0; i < length; i++) {
+ char car = contents[i];
+ switch (car) {
+ case '\n' :
+ buffer.append("\\n\n");
+ break;
+ case '\r' :
+ if (i < length - 1 && contents[i + 1] == '\n') {
+ buffer.append("\\r\\n\n");
+ i++;
+ } else {
+ buffer.append("\\r\n");
+ }
+ break;
+ default :
+ buffer.append(car);
+ break;
+ }
+ }
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BufferCache.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BufferCache.java
new file mode 100644
index 0000000000..a47fe4a2fb
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BufferCache.java
@@ -0,0 +1,55 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.core.IBuffer;
+import org.eclipse.jdt.core.IOpenable;
+import org.eclipse.jdt.internal.core.util.LRUCache;
+
+/**
+ * An LRU cache of <code>IBuffers</code>.
+ */
+public class BufferCache extends OverflowingLRUCache {
+ /**
+ * Constructs a new buffer cache of the given size.
+ */
+ public BufferCache(int size) {
+ super(size);
+ }
+
+ /**
+ * Constructs a new buffer cache of the given size.
+ */
+ public BufferCache(int size, int overflow) {
+ super(size, overflow);
+ }
+
+ /**
+ * Returns true if the buffer is successfully closed and
+ * removed from the cache, otherwise false.
+ *
+ * <p>NOTE: this triggers an external removal of this buffer
+ * by closing the buffer.
+ */
+ protected boolean close(LRUCacheEntry entry) {
+ IBuffer buffer = (IBuffer) entry._fValue;
+ synchronized (buffer) {
+ if (buffer.hasUnsavedChanges()) {
+ return false;
+ } else {
+ buffer.close();
+ return true;
+ }
+ }
+ }
+
+ /**
+ * Returns a new instance of the reciever.
+ */
+ protected LRUCache newInstance(int size, int overflow) {
+ return new BufferCache(size, overflow);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BufferManager.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BufferManager.java
new file mode 100644
index 0000000000..7659f4d04f
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BufferManager.java
@@ -0,0 +1,221 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.jdt.core.*;
+
+import java.io.*;
+import java.util.Enumeration;
+
+/**
+ * The BufferManager implements an LRU cache of buffers.
+ *
+ * @see IBufferManager
+ */
+public class BufferManager implements IBufferManager {
+
+ /**
+ * LRU cache of buffers. The key and value for an entry
+ * in the table is the identical buffer.
+ */
+ protected OverflowingLRUCache fOpenBuffers = new BufferCache(20);
+ protected static BufferManager fgDefaultBufferManager;
+ /**
+ * Creates a new buffer manager.
+ */
+ public BufferManager() {
+ }
+
+ /**
+ * Adds a buffer to the table of open buffers.
+ */
+ protected void addBuffer(IBuffer buffer) {
+ fOpenBuffers.put(buffer.getOwner(), buffer);
+ }
+
+ /**
+ * Returns the given bytes as a char array.
+ */
+ public static char[] bytesToChar(byte[] bytes) throws JavaModelException {
+
+ return getInputStreamAsCharArray(new ByteArrayInputStream(bytes));
+
+ }
+
+ /**
+ * @see IBufferManager
+ */
+ public IBuffer getBuffer(IOpenable owner) {
+ return (IBuffer) fOpenBuffers.get(owner);
+ }
+
+ /**
+ * Returns the default buffer manager.
+ * TBD: There shouldn't be a global buffer manager.
+ * It should be a registered manager with the workspace.
+ */
+ public synchronized static IBufferManager getDefaultBufferManager() {
+ if (fgDefaultBufferManager == null) {
+ fgDefaultBufferManager = new BufferManager();
+ }
+ return fgDefaultBufferManager;
+ }
+
+ /**
+ * Returns the given input stream's contents as a character array.
+ */
+ protected static char[] getInputStreamAsCharArray(InputStream stream)
+ throws JavaModelException {
+ InputStreamReader reader = null;
+ reader = new InputStreamReader(stream);
+ char[] contents = new char[0];
+ char[] grow;
+ try {
+ int available = stream.available();
+ int charsRead = 0;
+ int pos = 0;
+ while (available > 0) {
+ grow = new char[contents.length + available];
+ System.arraycopy(contents, 0, grow, 0, contents.length);
+ contents = grow;
+ charsRead = reader.read(contents, pos, available);
+ available = stream.available();
+ }
+ if (charsRead < available && charsRead > 0) {
+ grow = new char[contents.length - (available - charsRead)];
+ System.arraycopy(contents, 0, grow, 0, grow.length);
+ contents = grow;
+ }
+ } catch (IOException e) {
+ throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
+ } finally {
+ try {
+ reader.close();
+ } catch (IOException ioe) {
+ throw new JavaModelException(ioe, IJavaModelStatusConstants.IO_EXCEPTION);
+ }
+ }
+ return contents;
+ }
+
+ /**
+ * The <code>Enumeration</code> answered is thread safe.
+ *
+ * @see OverflowLRUCache
+ * @see IBufferManager
+ */
+ public Enumeration getOpenBuffers() {
+ synchronized (fOpenBuffers) {
+ fOpenBuffers.shrink();
+ return fOpenBuffers.elements();
+ }
+ }
+
+ /**
+ * Returns the given file's contents as a byte array.
+ */
+ public static byte[] getResourceContentsAsBytes(IFile file)
+ throws JavaModelException {
+ InputStream stream = null;
+ try {
+ stream = file.getContents(true);
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ }
+ byte[] contents = new byte[0];
+ byte[] grow;
+ try {
+ int available = stream.available();
+ int pos = 0;
+ while (available > 0) {
+ grow = new byte[contents.length + available];
+ System.arraycopy(contents, 0, grow, 0, contents.length);
+ contents = grow;
+ stream.read(contents, pos, available);
+ available = stream.available();
+ }
+ } catch (IOException e) {
+ throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
+ } finally {
+ try {
+ stream.close();
+ } catch (IOException ioe) {
+ throw new JavaModelException(ioe, IJavaModelStatusConstants.IO_EXCEPTION);
+ }
+ }
+ return contents;
+ }
+
+ /**
+ * Returns the given file's contents as a character array.
+ */
+ public static char[] getResourceContentsAsCharArray(IFile file)
+ throws JavaModelException {
+ InputStream stream = null;
+ try {
+ stream = file.getContents(true);
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ }
+ return getInputStreamAsCharArray(stream);
+ }
+
+ /**
+ * @see IBufferManager
+ */
+ public IBuffer openBuffer(
+ char[] contents,
+ IProgressMonitor progress,
+ IOpenable owner,
+ boolean readOnly)
+ throws IllegalArgumentException {
+ if (contents == null || owner == null) {
+ throw new IllegalArgumentException();
+ }
+ Buffer buffer = new Buffer(this, contents, owner, readOnly);
+ addBuffer(buffer);
+ return buffer;
+ }
+
+ /**
+ * @see IBufferManager
+ */
+ public IBuffer openBuffer(
+ IFile file,
+ IProgressMonitor progress,
+ IOpenable owner,
+ boolean readOnly)
+ throws JavaModelException {
+ if (file == null || owner == null) {
+ throw new IllegalArgumentException();
+ }
+ char[] contents = getResourceContentsAsCharArray(file);
+ Buffer buffer = new Buffer(this, file, contents, owner, readOnly);
+ addBuffer(buffer);
+ return buffer;
+ }
+
+ /**
+ * Removes a buffer from the table of open buffers.
+ */
+ protected void removeBuffer(IBuffer buffer) {
+ fOpenBuffers.remove(buffer.getOwner());
+ }
+
+ /**
+ * Returns the given String as a byte array. This is centralized here in case
+ * we need to do special conversion.
+ */
+ public static byte[] stringToBytes(String s) {
+
+ return s.getBytes();
+
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
new file mode 100644
index 0000000000..3a7ca5702f
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
@@ -0,0 +1,485 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.compiler.env.IBinaryType;
+import org.eclipse.jdt.internal.compiler.ConfigurableOption;
+import org.eclipse.jdt.internal.compiler.classfmt.*;
+
+import java.io.*;
+import java.util.*;
+import java.util.zip.ZipFile;
+import java.lang.reflect.Modifier;
+
+/**
+ * @see IClassFile
+ */
+
+public class ClassFile extends Openable implements IClassFile {
+ protected BinaryType fBinaryType = null;
+ /*
+ * Creates a handle to a class file.
+ *
+ * @exception IllegalArgumentExcpetion if the name does not end with ".class"
+ */
+ protected ClassFile(IPackageFragment parent, String name) {
+ super(CLASS_FILE, parent, name);
+ if (!name.toUpperCase().endsWith(".CLASS")) {
+ throw new IllegalArgumentException("class file name must end with .class");
+ }
+ }
+
+ /**
+ * @see ICodeAssist
+ */
+ public void codeComplete(int offset, ICodeCompletionRequestor requestor)
+ throws JavaModelException {
+ String source = getSource();
+ if (source != null) {
+ BasicCompilationUnit cu =
+ new BasicCompilationUnit(getSource().toCharArray(), getElementName() + ".java");
+ codeComplete(cu, cu, offset, requestor);
+ }
+ }
+
+ /**
+ * @see ICodeResolve
+ */
+ public IJavaElement[] codeSelect(int offset, int length)
+ throws JavaModelException {
+ IBuffer buffer = getBuffer();
+ if (buffer != null) {
+ char[] contents = null;
+ contents = buffer.getCharacters();
+ String name = getElementName();
+ name = name.substring(0, name.length() - 6); // remove ".class"
+ name = name + ".java";
+ BasicCompilationUnit cu = new BasicCompilationUnit(contents, name);
+ return super.codeSelect(cu, offset, length);
+ } else {
+ //has no associated souce
+ return new IJavaElement[] {
+ };
+ }
+ }
+
+ /**
+ * Returns a new element info for this element.
+ */
+ protected OpenableElementInfo createElementInfo() {
+ return new ClassFileInfo(this);
+ }
+
+ /**
+ * Finds the deepest <code>IJavaElement</code> in the hierarchy of
+ * <code>elt</elt>'s children (including <code>elt</code> itself)
+ * which has a source range that encloses <code>position</code>
+ * according to <code>mapper</code>.
+ */
+ protected IJavaElement findElement(
+ IJavaElement elt,
+ int position,
+ SourceMapper mapper) {
+ SourceRange range = mapper.getSourceRange(elt);
+ if (range == null
+ || position < range.getOffset()
+ || range.getOffset() + range.getLength() - 1 < position) {
+ return null;
+ }
+ if (elt instanceof IParent) {
+ try {
+ IJavaElement[] children = ((IParent) elt).getChildren();
+ for (int i = 0; i < children.length; i++) {
+ IJavaElement match = findElement(children[i], position, mapper);
+ if (match != null) {
+ return match;
+ }
+ }
+ } catch (JavaModelException npe) {
+ }
+ }
+ return elt;
+ }
+
+ /**
+ * Creates the children elements for this class file adding the resulting
+ * new handles and info objects to the newElements table. Returns true
+ * if successful, or false if an error is encountered parsing the class file.
+ *
+ * @see Openable
+ * @see Signature
+ */
+ protected boolean generateInfos(
+ OpenableElementInfo info,
+ IProgressMonitor pm,
+ Hashtable newElements,
+ IResource underlyingResource)
+ throws JavaModelException {
+ IBinaryType typeInfo = getBinaryTypeInfo((IFile) underlyingResource);
+ if (typeInfo == null) {
+ // The structure of a class file is unknown if a class file format errors occurred
+ //during the creation of the diet class file representative of this ClassFile.
+ info.setChildren(new IJavaElement[] {
+ });
+ return false;
+ }
+
+ // Make the type
+ IType type = new BinaryType(this, new String(simpleName(typeInfo.getName())));
+ info.addChild(type);
+ newElements.put(type, typeInfo);
+ return true;
+ }
+
+ /**
+ * Returns the <code>ClassFileReader</code>specific for this IClassFile, based
+ * on its underlying resource, or <code>null</code> if unable to create
+ * the diet class file.
+ * There are two cases to consider:<ul>
+ * <li>a class file corresponding to an IFile resource</li>
+ * <li>a class file corresponding to a zip entry in a JAR</li>
+ * </ul>
+ *
+ * @exception JavaModelException when the IFile resource or JAR is not available
+ * or when this class file is not present in the JAR
+ */
+ private IBinaryType getBinaryTypeInfo(IFile file) throws JavaModelException {
+ JavaElement le = (JavaElement) getParent();
+ if (le instanceof JarPackageFragment) {
+ try {
+ JarPackageFragmentRoot root = (JarPackageFragmentRoot) le.getParent();
+ IBinaryType info = null;
+ ZipFile zip = null;
+ try {
+ zip = root.getJar();
+ String entryName = getParent().getElementName();
+ entryName = entryName.replace('.', '/');
+ if (entryName.equals("")) {
+ entryName += getElementName();
+ } else {
+ entryName += '/' + getElementName();
+ }
+ info = ClassFileReader.read(zip, entryName);
+ } finally {
+ if (zip != null) {
+ try {
+ zip.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+ if (info == null) {
+ throw newNotPresentException();
+ }
+ return info;
+ } catch (ClassFormatException cfe) {
+ //the structure remains unknown
+ return null;
+ } catch (IOException ioe) {
+ throw new JavaModelException(ioe, IJavaModelStatusConstants.IO_EXCEPTION);
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ }
+ } else {
+ byte[] contents = null;
+ contents = BufferManager.getResourceContentsAsBytes(file);
+ try {
+ return new ClassFileReader(contents, getElementName().toCharArray());
+ } catch (ClassFormatException cfe) {
+ //the structure remains unknown
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Note: a buffer with no unsaved changes can be closed by the Java Model
+ * since it has a finite number of buffers allowed open at one time. If this
+ * is the first time a request is being made for the buffer, an attempt is
+ * made to create and fill this element's buffer. If the buffer has been
+ * closed since it was first opened, the buffer is re-created.
+ *
+ * @see IOpenable
+ */
+ public IBuffer getBuffer() throws JavaModelException {
+ IBuffer buffer = getBufferManager().getBuffer(this);
+ if (buffer == null) {
+ // try to (re)open a buffer
+ return openBuffer(null);
+ }
+ return buffer;
+ }
+
+ /**
+ * @see IMember
+ */
+ public IClassFile getClassFile() {
+ return this;
+ }
+
+ /**
+ * A class file has a corresponding resource unless it is contained
+ * in a jar.
+ *
+ * @see IJavaElement
+ */
+ public IResource getCorrespondingResource() throws JavaModelException {
+ IPackageFragmentRoot root = (IPackageFragmentRoot) getParent().getParent();
+ if (root.isArchive()) {
+ return null;
+ } else {
+ return getUnderlyingResource();
+ }
+ }
+
+ /**
+ * @see IClassFile
+ */
+ public IJavaElement getElementAt(int position) throws JavaModelException {
+ IJavaElement parent = getParent();
+ while (parent.getElementType() != IJavaElement.PACKAGE_FRAGMENT_ROOT) {
+ parent = parent.getParent();
+ }
+ PackageFragmentRoot root = (PackageFragmentRoot) parent;
+ SourceMapper mapper = root.getSourceMapper();
+ if (mapper == null) {
+ return null;
+ } else {
+ IType type = getType();
+ return findElement(type, position, mapper);
+ }
+ }
+
+ /**
+ * @see JavaElement#getHandleMemento()
+ */
+ protected char getHandleMementoDelimiter() {
+ return JavaElement.JEM_CLASSFILE;
+ }
+
+ /**
+ * @see ISourceReference
+ */
+ public String getSource() throws JavaModelException {
+ IBuffer buffer = getBuffer();
+ if (buffer == null) {
+ return null;
+ }
+ return buffer.getContents();
+ }
+
+ /**
+ * @see ISourceReference
+ */
+ public ISourceRange getSourceRange() throws JavaModelException {
+ return new SourceRange(0, getBuffer().getContents().toString().length());
+ }
+
+ /**
+ * @see IClassFile
+ */
+ public IType getType() throws JavaModelException {
+ if (fBinaryType == null) {
+ // Remove the ".class" from the name of the ClassFile - always works
+ // since constructor fails if name does not end with ".class"
+ String name = fName.substring(0, fName.lastIndexOf('.'));
+ name = name.substring(name.lastIndexOf('.') + 1);
+ int index = name.lastIndexOf('$');
+ if (index > -1) {
+ name = name.substring(index + 1);
+ }
+ fBinaryType = new BinaryType(this, name);
+ }
+ return fBinaryType;
+ }
+
+ /**
+ *
+ */
+ public WorkingCopy getWorkingCopy() {
+ String name = getElementName();
+ name = name.substring(0, name.length() - 6); // remove ".class"
+ name = name + ".java";
+ return new WorkingCopy((IPackageFragment) getParent(), name);
+ }
+
+ /**
+ * @see Openable
+ */
+ protected boolean hasBuffer() {
+ return true;
+ }
+
+ /**
+ * If I am not open, return true to avoid parsing.
+ *
+ * @see IParent
+ */
+ public boolean hasChildren() throws JavaModelException {
+ if (isOpen()) {
+ return getChildren().length > 0;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * @see IClassFile
+ */
+ public boolean isClass() throws JavaModelException {
+ return getType().isClass();
+ }
+
+ /**
+ * @see IClassFile
+ */
+ public boolean isInterface() throws JavaModelException {
+ return getType().isInterface();
+ }
+
+ /**
+ * Returns true - class files are always read only.
+ */
+ public boolean isReadOnly() {
+ return true;
+ }
+
+ /**
+ * Opens and returns buffer on the source code associated with this class file.
+ * Maps the source code to the children elements of this class file.
+ * If no source code is associated with this class file,
+ * <code>null</code> is returned.
+ *
+ * @see Openable
+ */
+ protected IBuffer openBuffer(IProgressMonitor pm) throws JavaModelException {
+ SourceMapper mapper = getSourceMapper();
+ if (mapper != null) {
+ char[] contents = mapper.findSource(getType());
+ if (contents != null) {
+ IBufferManager bufManager = getBufferManager();
+ IBuffer buf = bufManager.openBuffer(contents, pm, this, isReadOnly());
+ // do the source mapping
+ mapper.mapSource(getType(), contents);
+ return buf;
+ }
+ } else {
+ // Attempts to find the corresponding java file
+ String qualifiedName = getType().getFullyQualifiedName();
+ INameLookup lookup = ((JavaProject) getJavaProject()).getNameLookup();
+ ICompilationUnit cu = lookup.findCompilationUnit(qualifiedName);
+ if (cu != null) {
+ return cu.getBuffer();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the Java Model format of the simple class name for the
+ * given className which is provided in diet class file format,
+ * or <code>null</code> if the given className is <code>null</code>.
+ * (This removes package name and enclosing type names).
+ *
+ * <p><code>ClassFileReader</code> format is similar to "java/lang/Object",
+ * and corresponding Java Model simple name format is "Object".
+ */
+
+ /* package */
+ static char[] simpleName(char[] className) {
+ if (className == null)
+ return null;
+ className = unqualifiedName(className);
+ int count = 0;
+ for (int i = className.length - 1; i > -1; i--) {
+ if (className[i] == '$') {
+ char[] name = new char[count];
+ System.arraycopy(className, i + 1, name, 0, count);
+ return name;
+ }
+ count++;
+ }
+ return className;
+ }
+
+ /**
+ * Returns the Java Model representation of the given name
+ * which is provided in diet class file format, or <code>null</code>
+ * if the given name is <code>null</code>.
+ *
+ * <p><code>ClassFileReader</code> format is similar to "java/lang/Object",
+ * and corresponding Java Model format is "java.lang.Object".
+ */
+
+ public static char[] translatedName(char[] name) {
+ if (name == null)
+ return null;
+ int nameLength = name.length;
+ char[] newName = new char[nameLength];
+ for (int i = 0; i < nameLength; i++) {
+ if (name[i] == '/') {
+ newName[i] = '.';
+ } else {
+ newName[i] = name[i];
+ }
+ }
+ return newName;
+ }
+
+ /**
+ * Returns the Java Model representation of the given names
+ * which are provided in diet class file format, or <code>null</code>
+ * if the given names are <code>null</code>.
+ *
+ * <p><code>ClassFileReader</code> format is similar to "java/lang/Object",
+ * and corresponding Java Model format is "java.lang.Object".
+ */
+
+ /* package */
+ static char[][] translatedNames(char[][] names) {
+ if (names == null)
+ return null;
+ int length = names.length;
+ char[][] newNames = new char[length][];
+ for (int i = 0; i < length; i++) {
+ newNames[i] = translatedName(names[i]);
+ }
+ return newNames;
+ }
+
+ /**
+ * Returns the Java Model format of the unqualified class name for the
+ * given className which is provided in diet class file format,
+ * or <code>null</code> if the given className is <code>null</code>.
+ * (This removes the package name, but not enclosing type names).
+ *
+ * <p><code>ClassFileReader</code> format is similar to "java/lang/Object",
+ * and corresponding Java Model simple name format is "Object".
+ */
+
+ /* package */
+ static char[] unqualifiedName(char[] className) {
+ if (className == null)
+ return null;
+ int count = 0;
+ for (int i = className.length - 1; i > -1; i--) {
+ if (className[i] == '/') {
+ char[] name = new char[count];
+ System.arraycopy(className, i + 1, name, 0, count);
+ return name;
+ }
+ count++;
+ }
+ return className;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFileInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFileInfo.java
new file mode 100644
index 0000000000..b2f0473997
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFileInfo.java
@@ -0,0 +1,200 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.internal.compiler.env.IBinaryField;
+import org.eclipse.jdt.internal.compiler.env.IBinaryMethod;
+import org.eclipse.jdt.internal.compiler.env.IBinaryNestedType;
+import org.eclipse.jdt.internal.compiler.env.IBinaryType;
+import org.eclipse.jdt.core.*;
+
+import java.util.Vector;
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+/**
+ * Element info for <code>ClassFile</code> handles.
+ */
+
+/* package */
+class ClassFileInfo extends OpenableElementInfo {
+ /**
+ * The children of the <code>BinaryType</code> corresponding to our
+ * <code>ClassFile</code>. These are kept here because we don't have
+ * access to the <code>BinaryType</code> info (<code>ClassFileReader</code>).
+ * <p>
+ * The children are lazily initialized, on the first call to
+ * <code>getBinaryChildren()</code>, which in turn is called by
+ * <code>BinaryType.getChildren()</code>.
+ */
+ protected IJavaElement[] fBinaryChildren = null;
+ /**
+ * Back-pointer to the IClassFile to allow lazy initialization.
+ */
+ protected IClassFile fClassFile = null;
+ /**
+ * Creates a new <code>ClassFileInfo</code> for <code>classFile</code>.
+ */
+ ClassFileInfo(IClassFile classFile) {
+ fClassFile = classFile;
+ }
+
+ /**
+ * Creates the handles and infos for the fields of the given binary type.
+ * Adds new handles to the given vector.
+ */
+ private void generateFieldInfos(
+ IType type,
+ IBinaryType typeInfo,
+ Hashtable newElements,
+ Vector children) {
+ // Make the fields
+ IBinaryField[] fields = typeInfo.getFields();
+ if (fields == null) {
+ return;
+ }
+ for (int i = 0, fieldCount = fields.length; i < fieldCount; i++) {
+ IBinaryField fieldInfo = fields[i];
+ IField field = new BinaryField(type, new String(fieldInfo.getName()));
+ newElements.put(field, fieldInfo);
+ children.addElement(field);
+ }
+ }
+
+ /**
+ * Creates the handles and infos for the inner types of the given binary type.
+ * Adds new handles to the given vector.
+ */
+ private void generateInnerClassInfos(
+ IType type,
+ IBinaryType typeInfo,
+ Hashtable newElements,
+ Vector children) {
+ // Add inner types
+ // If the current type is an inner type, innerClasses returns
+ // an extra entry for the current type. This entry must be removed.
+ // Can also return an entry for the enclosing type of an inner type.
+ IBinaryNestedType[] innerTypes = typeInfo.getMemberTypes();
+ if (innerTypes != null) {
+ for (int i = 0, typeCount = innerTypes.length; i < typeCount; i++) {
+ IBinaryNestedType binaryType = innerTypes[i];
+ String innerQualifiedName = new String(binaryType.getName());
+ IClassFile classFile =
+ ((IPackageFragment) fClassFile.getParent()).getClassFile(
+ new String(ClassFile.unqualifiedName(binaryType.getName())) + ".class");
+ IType innerType =
+ new BinaryType(
+ classFile,
+ new String(ClassFile.simpleName(binaryType.getName())));
+ children.addElement(innerType);
+ }
+ }
+ }
+
+ /**
+ * Creates the handles and infos for the methods of the given binary type.
+ * Adds new handles to the given vector.
+ */
+ private void generateMethodInfos(
+ IType type,
+ IBinaryType typeInfo,
+ Hashtable newElements,
+ Vector children) {
+ IBinaryMethod[] methods = typeInfo.getMethods();
+ if (methods == null) {
+ return;
+ }
+ for (int i = 0, methodCount = methods.length; i < methodCount; i++) {
+ IBinaryMethod methodInfo = methods[i];
+ String[] pNames =
+ Signature.getParameterTypes(new String(methodInfo.getMethodDescriptor()));
+ char[][] paramNames = new char[pNames.length][];
+ for (int j = 0; j < pNames.length; j++) {
+ paramNames[j] = pNames[j].toCharArray();
+ }
+ char[][] parameterTypes = ClassFile.translatedNames(paramNames);
+ String selector = new String(methodInfo.getSelector());
+ if (methodInfo.isConstructor()) {
+ selector = type.getElementName();
+ }
+ for (int j = 0; j < pNames.length; j++) {
+ pNames[j] = new String(parameterTypes[j]);
+ }
+ IMethod method = new BinaryMethod(type, selector, pNames);
+ children.addElement(method);
+ newElements.put(method, methodInfo);
+ }
+ }
+
+ /**
+ * Returns the list of children (<code>BinaryMember</code>s) of the
+ * <code>BinaryType</code> of our <code>ClassFile</code>.
+ */
+ IJavaElement[] getBinaryChildren() throws JavaModelException {
+ if (fBinaryChildren == null) {
+ readBinaryChildren();
+ }
+ return fBinaryChildren;
+ }
+
+ /**
+ * Returns true iff the <code>readBinaryChildren</code> has already
+ * been called.
+ */
+ boolean hasReadBinaryChildren() {
+ return fBinaryChildren != null;
+ }
+
+ /**
+ * Creates the handles for <code>BinaryMember</code>s defined in this
+ * <code>ClassFile</code> and adds them to the
+ * <code>JavaModelManager</code>'s cache.
+ */
+ private void readBinaryChildren() {
+ Vector children = new Vector();
+ Hashtable newElements = new Hashtable();
+ BinaryType type = null;
+ IBinaryType typeInfo = null;
+ JavaModelManager manager =
+ (JavaModelManager) JavaModelManager.getJavaModelManager();
+ try {
+ type = (BinaryType) fClassFile.getType();
+ typeInfo = (IBinaryType) manager.getInfo(type);
+ } catch (JavaModelException npe) {
+ return;
+ }
+ if (typeInfo != null) { //may not be a valid class file
+ generateFieldInfos(type, typeInfo, newElements, children);
+ generateMethodInfos(type, typeInfo, newElements, children);
+ generateInnerClassInfos(type, typeInfo, newElements, children);
+ }
+ for (Enumeration e = newElements.keys(); e.hasMoreElements();) {
+ IJavaElement key = (IJavaElement) e.nextElement();
+ Object value = newElements.get(key);
+ manager.putInfo(key, value);
+ }
+ fBinaryChildren = new IJavaElement[children.size()];
+ children.copyInto(fBinaryChildren);
+ }
+
+ /**
+ * Removes the binary children handles and remove their infos from
+ * the <code>JavaModelManager</code>'s cache.
+ */
+ void removeBinaryChildren() {
+ if (fBinaryChildren != null) {
+ JavaModelManager manager =
+ (JavaModelManager) JavaModelManager.getJavaModelManager();
+ for (int i = 0; i < fBinaryChildren.length; i++) {
+ manager.removeInfo(fBinaryChildren[i]);
+ }
+ fBinaryChildren = fgEmptyChildren;
+ }
+ }
+
+}
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
new file mode 100644
index 0000000000..7da08eaea4
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java
@@ -0,0 +1,233 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.IPath;
+
+import org.eclipse.jdt.core.*;
+
+import java.io.File;
+
+/**
+ * @see IClasspathEntry
+ */
+public class ClasspathEntry implements IClasspathEntry {
+
+ /**
+ * Describes the kind of classpath entry - one of
+ * CPE_PROJECT, CPE_LIBRARY or CPE_SOURCE.
+ */
+ protected int entryKind;
+
+ /**
+ * Describes the kind of package fragment roots found on
+ * this classpath entry - either K_BINARY or K_SOURCE or
+ * K_OUTPUT.
+ */
+ protected int contentKind;
+
+ /**
+ * The meaning of the path of a classpath entry depends on its entry kind:<ul>
+ * <li>Source code in the current project (<code>CPE_SOURCE</code>) -
+ * The path associated with this entry is the absolute path to the root folder. </li>
+ * <li>A binary library in the current project (<code>CPE_LIBRARY</code>) - the path
+ * associated with this entry is the absolute path to the JAR (or root folder), and
+ * in case it refers to an external JAR, then there is no associated resource in
+ * the workbench.
+ * <li>A required project (<code>CPE_PROJECT</code>) - the path of the entry denotes the
+ * path to the corresponding project resource.</li>
+ * <li>A variable entry (<code>CPE_VARIABLE</code>) - the first segment of the path
+ * is the name of a classpath variable. If this classpath variable
+ * is bound to the path <it>P</it>, the path of the corresponding classpath entry
+ * is computed by appending to <it>P</it> the segments of the returned
+ * path without the variable.</li>
+ */
+ protected IPath path;
+
+ /**
+ * Describes the path to the source archive associated with this
+ * classpath entry, or <code>null</code> if this classpath entry has no
+ * source attachment.
+ * <p>
+ * Only library and variable classpath entries may have source attachments.
+ * For library classpath entries, the result path (if present) locates a source
+ * archive. For variable classpath entries, the result path (if present) has
+ * an analogous form and meaning as the variable path, namely the first segment
+ * is the name of a classpath variable.
+ */
+ protected IPath sourceAttachmentPath;
+
+ /**
+ * Describes the path within the source archive where package fragments
+ * are located. An empty path indicates that packages are located at
+ * the root of the source archive. Returns a non-<code>null</code> value
+ * if and only if <code>getSourceAttachmentPath</code> returns
+ * a non-<code>null</code> value.
+ */
+ protected IPath sourceAttachmentRootPath;
+
+ /**
+ * A constant indicating an output location.
+ */
+ protected static final int K_OUTPUT = 10;
+ /**
+ * Creates a class path entry of the specified kind with the given path.
+ */
+ public ClasspathEntry(
+ int contentKind,
+ int entryKind,
+ IPath path,
+ IPath sourceAttachmentPath,
+ IPath sourceAttachmentRootPath) {
+ this.contentKind = contentKind;
+ this.entryKind = entryKind;
+ this.path = path;
+ this.sourceAttachmentPath = sourceAttachmentPath;
+ this.sourceAttachmentRootPath = sourceAttachmentRootPath;
+ }
+
+ /**
+ * Returns true if the given object is a classpath entry
+ * with equivalent attributes.
+ */
+ public boolean equals(Object object) {
+ if (this == object)
+ return true;
+ if (object instanceof IClasspathEntry) {
+ IClasspathEntry otherEntry = (IClasspathEntry) object;
+
+ if (this.contentKind != otherEntry.getContentKind())
+ return false;
+
+ if (this.entryKind != otherEntry.getEntryKind())
+ return false;
+
+ if (!this.path.equals(otherEntry.getPath()))
+ return false;
+
+ IPath otherPath = otherEntry.getSourceAttachmentPath();
+ if (this.sourceAttachmentPath == null) {
+ if (otherPath != null)
+ return false;
+ } else {
+ if (!this.sourceAttachmentPath.equals(otherPath))
+ return false;
+ }
+
+ otherPath = otherEntry.getSourceAttachmentRootPath();
+ if (this.sourceAttachmentRootPath == null) {
+ if (otherPath != null)
+ return false;
+ } else {
+ if (!this.sourceAttachmentRootPath.equals(otherPath))
+ return false;
+ }
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @see IClasspathEntry
+ */
+ public int getContentKind() {
+ return this.contentKind;
+ }
+
+ /**
+ * @see IClasspathEntry
+ */
+ public int getEntryKind() {
+ return this.entryKind;
+ }
+
+ /**
+ * @see IClasspathEntry
+ */
+ public IPath getPath() {
+ return this.path;
+ }
+
+ /**
+ * @see IClasspathEntry
+ * @deprecated
+ */
+ public IClasspathEntry getResolvedEntry() {
+
+ return JavaCore.getResolvedClasspathEntry(this);
+ }
+
+ /**
+ * @see IClasspathEntry
+ */
+ public IPath getSourceAttachmentPath() {
+ return this.sourceAttachmentPath;
+ }
+
+ /**
+ * @see IClasspathEntry
+ */
+ public IPath getSourceAttachmentRootPath() {
+ return this.sourceAttachmentRootPath;
+ }
+
+ /**
+ * Returns the hash code for this classpath entry
+ */
+ public int hashCode() {
+ return this.path.hashCode();
+ }
+
+ /**
+ * Returns a printable representation of this classpath entry.
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(getPath().toString());
+ buffer.append('[');
+ switch (getEntryKind()) {
+ case IClasspathEntry.CPE_LIBRARY :
+ buffer.append("CPE_LIBRARY");
+ break;
+ case IClasspathEntry.CPE_PROJECT :
+ buffer.append("CPE_PROJECT");
+ break;
+ case IClasspathEntry.CPE_SOURCE :
+ buffer.append("CPE_SOURCE");
+ break;
+ case IClasspathEntry.CPE_VARIABLE :
+ buffer.append("CPE_VARIABLE");
+ break;
+ }
+ buffer.append("][");
+ switch (getContentKind()) {
+ case IPackageFragmentRoot.K_BINARY :
+ buffer.append("K_BINARY");
+ break;
+ case IPackageFragmentRoot.K_SOURCE :
+ buffer.append("K_SOURCE");
+ break;
+ case ClasspathEntry.K_OUTPUT :
+ buffer.append("K_OUTPUT");
+ break;
+ }
+ buffer.append(']');
+ if (getSourceAttachmentPath() != null) {
+ buffer.append("[sourcePath:");
+ buffer.append(getSourceAttachmentPath());
+ buffer.append(']');
+ }
+ if (getSourceAttachmentRootPath() != null) {
+ buffer.append("[rootPath:");
+ buffer.append(getSourceAttachmentRootPath());
+ buffer.append(']');
+ }
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CommitWorkingCopyOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CommitWorkingCopyOperation.java
new file mode 100644
index 0000000000..335c5ce992
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CommitWorkingCopyOperation.java
@@ -0,0 +1,156 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.IJavaModelStatusConstants;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IPackageDeclaration;
+import org.eclipse.jdt.core.IJavaModelStatus;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IPackageFragment;
+
+/**
+ * Commits the contents of a working copy compilation
+ * unit to its original element and resource, bringing
+ * the Java Model up-to-date with the current contents of the working
+ * copy.
+ *
+ * <p>It is possible that the contents of the
+ * original resource have changed since the working copy was created,
+ * in which case there is an update conflict. This operation allows
+ * for two settings to resolve conflict set by the <code>fForce</code> flag:<ul>
+ * <li>force flag is <code>false</code> - in this case an <code>JavaModelException</code>
+ * is thrown</li>
+ * <li>force flag is <code>true</code> - in this case the contents of
+ * the working copy are applied to the underlying resource even though
+ * the working copy was created before a subsequent change in the
+ * resource</li>
+ * </ul>
+ *
+ * <p>The default conflict resolution setting is the force flag is <code>false</code>
+ *
+ * @exception JavaModelOperation An exception is thrown either if the commit could not
+ * be performed or if the new content of the compilation unit violates some Java Model
+ * constraint (e.g. if the new package declaration doesn't match the name of the folder
+ * containing the compilation unit).
+ */
+public class CommitWorkingCopyOperation extends JavaModelOperation {
+ /**
+ * Constructs an operation to commit the contents of a working copy
+ * to its original compilation unit.
+ */
+ public CommitWorkingCopyOperation(ICompilationUnit element, boolean force) {
+ super(new IJavaElement[] { element }, force);
+ }
+
+ /**
+ * Checks that the package declaration in the compilation unit matches the actual
+ * package fragment the CU is defined in.
+ *
+ * @exception JavaModelException with an <code>INVALID_PACKAGE</code> JavaModelStatus if the
+ * package declaration is invalid.
+ * @see IJavaModelStatusConstants.INVALID_PACKAGE
+ */
+ private void checkPackageDeclaration(ICompilationUnit cu)
+ throws JavaModelException {
+ IPackageFragment frag = (IPackageFragment) cu.getParent();
+ IPackageDeclaration[] decls = cu.getPackageDeclarations();
+ String pkgName = frag.getElementName();
+ if (pkgName.equals(IPackageFragment.DEFAULT_PACKAGE_NAME)) {
+ if (decls != null && decls.length > 0) {
+ throw new JavaModelException(
+ new JavaModelStatus(
+ IJavaModelStatusConstants.INVALID_PACKAGE,
+ cu,
+ decls[0].getElementName()));
+ }
+ } else {
+ if (decls == null
+ || decls.length != 1
+ || !pkgName.equals(decls[0].getElementName())) {
+ throw new JavaModelException(
+ new JavaModelStatus(
+ IJavaModelStatusConstants.INVALID_PACKAGE,
+ cu,
+ (decls == null || decls.length == 0)
+ ? IPackageFragment.DEFAULT_PACKAGE_NAME
+ : decls[0].getElementName()));
+ }
+ }
+ }
+
+ /**
+ * @exception JavaModelException if setting the source
+ * of the original compilation unit fails
+ */
+ protected void executeOperation() throws JavaModelException {
+ beginTask("Committing working copy...", 2);
+ ICompilationUnit copy = getCompilationUnit();
+ ICompilationUnit original = (ICompilationUnit) copy.getOriginalElement();
+
+ // creates the delta builder (this remembers the content of the cu)
+ JavaElementDeltaBuilder deltaBuilder = new JavaElementDeltaBuilder(original);
+
+ // save the cu
+ original.getBuffer().setContents(copy.getBuffer().getCharacters());
+ original.save(fMonitor, fForce);
+
+ // make sure working copy is in sync
+ copy.restore();
+ worked(1);
+
+ // build the deltas
+ deltaBuilder.buildDeltas();
+
+ // add the deltas to the list of deltas created during this operation
+ if (deltaBuilder.delta != null) {
+ addDelta(deltaBuilder.delta);
+ }
+ worked(1);
+
+ done();
+ // checkPackageDeclaration(original);
+ }
+
+ /**
+ * Returns the compilation unit this operation is working on.
+ */
+ protected ICompilationUnit getCompilationUnit() {
+ return (ICompilationUnit) getElementToProcess();
+ }
+
+ /**
+ * Possible failures: <ul>
+ * <li>INVALID_ELEMENT_TYPES - the compilation unit supplied to this
+ * operation is not a working copy
+ * <li>ELEMENT_NOT_PRESENT - the compilation unit the working copy is
+ * based on no longer exists.
+ * <li>UPDATE_CONFLICT - the original compilation unit has changed since
+ * the working copy was created and the operation specifies no force
+ * </ul>
+ */
+ public IJavaModelStatus verify() {
+ ICompilationUnit cu = getCompilationUnit();
+ if (!cu.isWorkingCopy()) {
+ return new JavaModelStatus(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, cu);
+ }
+ ICompilationUnit original = (ICompilationUnit) cu.getOriginalElement();
+ IResource resource = null;
+ try {
+ resource = original.getUnderlyingResource();
+ } catch (JavaModelException e) {
+ return e.getJavaModelStatus();
+ }
+ if (!cu.isBasedOn(resource) && !fForce) {
+ return new JavaModelStatus(IJavaModelStatusConstants.UPDATE_CONFLICT);
+ }
+ return JavaModelStatus.VERIFIED_OK;
+ }
+
+}
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
new file mode 100644
index 0000000000..412db8b1ea
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnit.java
@@ -0,0 +1,687 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.internal.codeassist.*;
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.internal.core.lookup.*;
+
+import java.util.*;
+
+/**
+ * @see ICompilationUnit
+ */
+
+public class CompilationUnit
+ extends Openable
+ implements ICompilationUnit, org.eclipse.jdt.internal.compiler.env.ICompilationUnit {
+
+ /**
+ * Constructs a handle to a compilation unit with the given name in the
+ * specified package.
+ *
+ * @exception IllegalArgumentException if the name of the compilation unit
+ * does not end with ".java"
+ */
+ protected CompilationUnit(IPackageFragment parent, String name) {
+ super(COMPILATION_UNIT, parent, name);
+ if (!name.toUpperCase().endsWith(".JAVA")) {
+ throw new IllegalArgumentException("compilation unit name must end with .java");
+ }
+ }
+
+ /**
+ * Accepts the given visitor onto the parsed tree of this compilation unit, after
+ * having runned the name resolution.
+ * The visitor's corresponding <code>visit</code> method is called with the
+ * corresponding parse tree. If the visitor returns <code>true</code>, this method
+ * visits this parse node's members.
+ *
+ * @param visitor the visitor
+ * @exception JavaModelException if this method fails. Reasons include:
+ * <ul>
+ * <li> This element does not exist.</li>
+ * <li> The visitor failed with this exception.</li>
+ * </ul>
+ */
+ public void accept(IAbstractSyntaxTreeVisitor visitor)
+ throws JavaModelException {
+ CompilationUnitVisitor.visit(this, visitor);
+ }
+
+ /**
+ * @see ICodeAssist
+ */
+ public void codeComplete(int offset, ICodeCompletionRequestor requestor)
+ throws JavaModelException {
+ codeComplete(
+ this,
+ isWorkingCopy()
+ ? (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) getOriginalElement()
+ : this,
+ offset,
+ requestor);
+ }
+
+ /**
+ * @see ICodeResolve
+ */
+ public IJavaElement[] codeSelect(int offset, int length)
+ throws JavaModelException {
+ return super.codeSelect(this, offset, length);
+ }
+
+ /**
+ * @see IWorkingCopy
+ */
+ public void commit(boolean force, IProgressMonitor monitor)
+ throws JavaModelException {
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, this));
+ }
+
+ /**
+ * @see ISourceManipulation
+ */
+ public void copy(
+ IJavaElement container,
+ IJavaElement sibling,
+ String rename,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ if (container == null) {
+ throw new IllegalArgumentException("container cannot be null");
+ }
+ IJavaElement[] elements = new IJavaElement[] { this };
+ IJavaElement[] containers = new IJavaElement[] { container };
+ String[] renamings = null;
+ if (rename != null) {
+ renamings = new String[] { rename };
+ }
+ getJavaModel().copy(elements, containers, null, renamings, force, monitor);
+ }
+
+ /**
+ * Returns a new element info for this element.
+ */
+ protected OpenableElementInfo createElementInfo() {
+ return new CompilationUnitElementInfo();
+ }
+
+ /**
+ * @see ICompilationUnit
+ */
+ public IImportDeclaration createImport(
+ String name,
+ IJavaElement sibling,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ CreateImportOperation op = new CreateImportOperation(name, this);
+ if (sibling != null) {
+ op.createBefore(sibling);
+ }
+ runOperation(op, monitor);
+ return getImport(name);
+ }
+
+ /**
+ * @see ICompilationUnit
+ */
+ public IPackageDeclaration createPackageDeclaration(
+ String name,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+
+ CreatePackageDeclarationOperation op =
+ new CreatePackageDeclarationOperation(name, this);
+ runOperation(op, monitor);
+ return getPackageDeclaration(name);
+ }
+
+ /**
+ * @see ICompilationUnit
+ */
+ public IType createType(
+ String content,
+ IJavaElement sibling,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ if (!exists()) {
+ //autogenerate this compilation unit
+ IPackageFragment pkg = (IPackageFragment) getParent();
+ String source = "";
+ if (pkg.getElementName().length() > 0) {
+ //not the default package...add the package declaration
+ source =
+ "package " + pkg.getElementName() + ";" + JavaModelManager.LINE_SEPARATOR;
+ }
+ CreateCompilationUnitOperation op =
+ new CreateCompilationUnitOperation(pkg, fName, source, force);
+ runOperation(op, monitor);
+ }
+ CreateTypeOperation op = new CreateTypeOperation(this, content, force);
+ if (sibling != null) {
+ op.createBefore(sibling);
+ }
+ runOperation(op, monitor);
+ return (IType) op.getResultElements()[0];
+ }
+
+ /**
+ * @see ISourceManipulation
+ */
+ public void delete(boolean force, IProgressMonitor monitor)
+ throws JavaModelException {
+ IJavaElement[] elements = new IJavaElement[] { this };
+ getJavaModel().delete(elements, force, monitor);
+ }
+
+ /**
+ * This is not a working copy, do nothing.
+ *
+ * @see IWorkingCopy
+ */
+ public void destroy() {
+ }
+
+ /**
+ * Returns true if this handle represents the same Java element
+ * as the given handle.
+ *
+ * <p>Compilation units must also check working copy state;
+ *
+ * @see Object#equals
+ */
+ public boolean equals(Object o) {
+ return super.equals(o) && !((ICompilationUnit) o).isWorkingCopy();
+ }
+
+ /**
+ * @see JavaElement#equalsDOMNode
+ */
+ protected boolean equalsDOMNode(IDOMNode node) throws JavaModelException {
+ String name = getElementName();
+ if (node.getNodeType() == IDOMNode.COMPILATION_UNIT && name != null) {
+ String nodeName = node.getName();
+ if (nodeName == null)
+ return false;
+ if (name.equals(nodeName)) {
+ return true;
+ } else {
+ // iterate through all the types inside the receiver and see if one of them can fit
+ IType[] types = getTypes();
+ String typeNodeName = nodeName.substring(0, nodeName.indexOf(".java"));
+ for (int i = 0, max = types.length; i < max; i++) {
+ if (types[i].getElementName().equals(typeNodeName)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @see Openable
+ */
+ protected boolean generateInfos(
+ OpenableElementInfo info,
+ IProgressMonitor pm,
+ Hashtable newElements,
+ IResource underlyingResource)
+ throws JavaModelException {
+
+ if (getParent() instanceof JarPackageFragment) {
+ // ignore .java files in jar
+ throw newNotPresentException();
+ } else {
+ // put the info now, because getting the contents requires it
+ fgJavaModelManager.putInfo(this, info);
+ CompilationUnitElementInfo unitInfo = (CompilationUnitElementInfo) info;
+
+ // generate structure
+ CompilationUnitStructureRequestor requestor =
+ new CompilationUnitStructureRequestor(this, unitInfo, newElements);
+ IProblemFactory factory = new ProblemFactory();
+ SourceElementParser parser = new SourceElementParser(requestor, factory);
+ parser.parseCompilationUnit(this, !isWorkingCopy());
+ if (isWorkingCopy()) {
+ // remember problems
+ Vector problems = requestor.fProblems;
+ if (problems != null) {
+ problems.copyInto(
+ ((WorkingCopyElementInfo) unitInfo).problems = new IProblem[problems.size()]);
+ }
+
+ CompilationUnit original = (CompilationUnit) getOriginalElement();
+ unitInfo.fTimestamp =
+ ((IFile) original.getUnderlyingResource()).getModificationStamp();
+ if (unitInfo.fTimestamp == IResource.NULL_STAMP) {
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.INVALID_RESOURCE));
+ }
+ }
+ return unitInfo.isStructureKnown();
+ }
+ }
+
+ /**
+ * @see ICompilationUnit
+ */
+ public IType[] getAllTypes() throws JavaModelException {
+ IJavaElement[] types = getTypes();
+ int i;
+ Vector allTypes = new Vector(types.length);
+ Vector typesToTraverse = new Vector(types.length);
+ for (i = 0; i < types.length; i++) {
+ typesToTraverse.addElement(types[i]);
+ }
+ while (!typesToTraverse.isEmpty()) {
+ IType type = (IType) typesToTraverse.elementAt(0);
+ typesToTraverse.removeElement(type);
+ allTypes.addElement(type);
+ types = type.getTypes();
+ for (i = 0; i < types.length; i++) {
+ typesToTraverse.addElement(types[i]);
+ }
+ }
+ allTypes.trimToSize();
+ IType[] arrayOfAllTypes = new IType[allTypes.size()];
+ allTypes.copyInto(arrayOfAllTypes);
+ return arrayOfAllTypes;
+ }
+
+ /**
+ * @see IMember
+ */
+ public ICompilationUnit getCompilationUnit() {
+ return this;
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.compiler.env.api.ICompilationUnit
+ */
+ public char[] getContents() {
+ try {
+ return getBuffer().getCharacters();
+ } catch (NullPointerException e) { // buffer could be null
+ return new char[0];
+ } catch (JavaModelException e) {
+ return new char[0];
+ }
+ }
+
+ /**
+ * A compilation unit has a corresponding resource unless it is contained
+ * in a jar.
+ *
+ * @see IJavaElement
+ */
+ public IResource getCorrespondingResource() throws JavaModelException {
+ IPackageFragmentRoot root = (IPackageFragmentRoot) getParent().getParent();
+ if (root.isArchive()) {
+ return null;
+ } else {
+ return getUnderlyingResource();
+ }
+ }
+
+ /**
+ * @see ICompilationUnit
+ */
+ public IJavaElement getElementAt(int position) throws JavaModelException {
+
+ IJavaElement e = getSourceElementAt(position);
+ if (e == this) {
+ return null;
+ } else {
+ return e;
+ }
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.compiler.env.api.ICompilationUnit
+ */
+ public char[] getFileName() {
+ return getElementName().toCharArray();
+ }
+
+ /**
+ * @see JavaElement#getHandleMemento()
+ */
+ protected char getHandleMementoDelimiter() {
+ return JavaElement.JEM_COMPILATIONUNIT;
+ }
+
+ /**
+ * @see ICompilationUnit#getImport
+ */
+ public IImportDeclaration getImport(String name) {
+ return new ImportDeclaration(getImportContainer(), name);
+ }
+
+ /**
+ * @see ICompilationUnit
+ */
+ public IImportContainer getImportContainer() {
+ return new ImportContainer(this);
+ }
+
+ /**
+ * @see ICompilationUnit
+ */
+ public IImportDeclaration[] getImports() throws JavaModelException {
+ IImportContainer container = getImportContainer();
+ if (container.exists()) {
+ IJavaElement[] elements = container.getChildren();
+ IImportDeclaration[] imprts = new IImportDeclaration[elements.length];
+ System.arraycopy(elements, 0, imprts, 0, elements.length);
+ return imprts;
+ } else
+ if (!exists()) {
+ throw newNotPresentException();
+ } else {
+ return new IImportDeclaration[0];
+ }
+
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.compiler.env.api.ICompilationUnit
+ */
+ public char[] getMainTypeName() {
+ String name = getElementName();
+ //remove the .java
+ name = name.substring(0, name.length() - 5);
+ return name.toCharArray();
+ }
+
+ /**
+ * Returns <code>null</code>, this is not a working copy.
+ *
+ * @see IWorkingCopy
+ */
+ public IJavaElement getOriginal(IJavaElement workingCopyElement) {
+ return null;
+ }
+
+ /**
+ * Returns <code>null</code>, this is not a working copy.
+ *
+ * @see IWorkingCopy
+ */
+ public IJavaElement getOriginalElement() {
+ return null;
+ }
+
+ /**
+ * @see ICompilationUnit#getPackageDeclaration(String)
+ */
+ public IPackageDeclaration getPackageDeclaration(String name) {
+ return new PackageDeclaration(this, name);
+ }
+
+ /**
+ * @see ICompilationUnit
+ */
+ public IPackageDeclaration[] getPackageDeclarations()
+ throws JavaModelException {
+ Vector v = getChildrenOfType(PACKAGE_DECLARATION);
+ IPackageDeclaration[] array = new IPackageDeclaration[v.size()];
+ v.copyInto(array);
+ return array;
+ }
+
+ /**
+ * Returns the reference information for this compilation unit
+ */
+ public ReferenceInfo getReferenceInfo() throws JavaModelException {
+ return ((CompilationUnitElementInfo) getElementInfo()).getReferenceInfo();
+ }
+
+ /**
+ * @see ISourceReference
+ */
+ public String getSource() throws JavaModelException {
+ IBuffer buffer = getBuffer();
+ if (buffer == null)
+ return "";
+ return buffer.getContents();
+ }
+
+ /**
+ * @see ISourceReference
+ */
+ public ISourceRange getSourceRange() throws JavaModelException {
+ return ((CompilationUnitElementInfo) getElementInfo()).getSourceRange();
+ }
+
+ /**
+ * @see ICompilationUnit
+ */
+ public IType getType(String name) {
+ return new SourceType(this, name);
+ }
+
+ /**
+ * @see ICompilationUnit
+ */
+ public IType[] getTypes() throws JavaModelException {
+ Vector v = getChildrenOfType(TYPE);
+ IType[] array = new IType[v.size()];
+ v.copyInto(array);
+ return array;
+ }
+
+ /**
+ * @see IWorkingCopy
+ */
+ public IJavaElement getWorkingCopy() throws JavaModelException {
+ WorkingCopy workingCopy =
+ new WorkingCopy((IPackageFragment) getParent(), getElementName());
+ // open the working copy now to ensure contents are that of the current state of this element
+ workingCopy.open(null);
+ return workingCopy;
+ }
+
+ /**
+ * @see Openable
+ */
+ protected boolean hasBuffer() {
+ return true;
+ }
+
+ /**
+ * If I am not open, return true to avoid parsing.
+ *
+ * @see IParent
+ */
+ public boolean hasChildren() throws JavaModelException {
+ if (isOpen()) {
+ return getChildren().length > 0;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Returns false, this is not a working copy.
+ *
+ * @see IWorkingCopy
+ */
+ public boolean isBasedOn(IResource resource) {
+ return false;
+ }
+
+ /**
+ * @see IOpenable
+ */
+ public boolean isConsistent() throws JavaModelException {
+ return fgJavaModelManager.getElementsOutOfSynchWithBuffers().get(this) == null;
+ }
+
+ /**
+ * @see Openable
+ */
+ protected boolean isSourceElement() {
+ return true;
+ }
+
+ /**
+ * @see IWorkingCopy
+ */
+ public boolean isWorkingCopy() {
+ return false;
+ }
+
+ /**
+ * @see IOpenable
+ */
+ public void makeConsistent(IProgressMonitor pm) throws JavaModelException {
+ if (!isConsistent()) {
+ // create a new info and make it the current info
+ OpenableElementInfo info = createElementInfo();
+ buildStructure(info, pm);
+ }
+ }
+
+ /**
+ * @see ISourceManipulation
+ */
+ public void move(
+ IJavaElement container,
+ IJavaElement sibling,
+ String rename,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ if (container == null) {
+ throw new IllegalArgumentException("container cannot be null");
+ }
+ IJavaElement[] elements = new IJavaElement[] { this };
+ IJavaElement[] containers = new IJavaElement[] { container };
+
+ String[] renamings = null;
+ if (rename != null) {
+ renamings = new String[] { rename };
+ }
+ getJavaModel().move(elements, containers, null, renamings, force, monitor);
+ }
+
+ /**
+ * Changes the source end index of this element and all children (following
+ * <code>child</code>).
+ */
+ public void offsetSourceEndAndChildren(int amount, IJavaElement child) {
+ try {
+ CompilationUnitElementInfo cuInfo =
+ (CompilationUnitElementInfo) getElementInfo();
+ cuInfo.setSourceLength(cuInfo.getSourceLength() + amount);
+ IJavaElement[] children = getChildren();
+ boolean afterChild = false;
+ for (int i = 0; i < children.length; i++) {
+ IJavaElement aChild = children[i];
+ if (child == null || aChild.equals(child)) {
+ afterChild = true;
+ } else
+ if (afterChild) {
+ ((JavaElement) aChild).offsetSourceRange(amount);
+ }
+ }
+ } catch (JavaModelException npe) {
+ return;
+ }
+ }
+
+ /**
+ * Changes the source indexes of this element and all children elements.
+ */
+ public void offsetSourceRange(int amount) {
+ try {
+ CompilationUnitElementInfo cuInfo =
+ (CompilationUnitElementInfo) getElementInfo();
+ cuInfo.setSourceLength(cuInfo.getSourceLength() + amount);
+ IJavaElement[] children = getChildren();
+ for (int i = 0; i < children.length; i++) {
+ IJavaElement aChild = children[i];
+ ((JavaElement) aChild).offsetSourceRange(amount);
+ }
+ } catch (JavaModelException npe) {
+ return;
+ }
+ }
+
+ /**
+ * @see Openable
+ */
+ protected IBuffer openBuffer(IProgressMonitor pm) throws JavaModelException {
+ IBuffer buf =
+ getBufferManager().openBuffer(
+ (IFile) getUnderlyingResource(),
+ pm,
+ this,
+ isReadOnly());
+ buf.addBufferChangedListener(this);
+ return buf;
+ }
+
+ /**
+ * @see IWorkingCopy
+ */
+ public IMarker[] reconcile() throws JavaModelException {
+ // Reconciling is not supported on non working copies
+ return null;
+ }
+
+ /**
+ * @see ISourceManipulation
+ */
+ public void rename(String name, boolean force, IProgressMonitor monitor)
+ throws JavaModelException {
+ if (name == null) {
+ throw new IllegalArgumentException("name cannot be null");
+ }
+ IJavaElement[] elements = new IJavaElement[] { this };
+ IJavaElement[] dests = new IJavaElement[] { this.getParent()};
+ String[] renamings = new String[] { name };
+ getJavaModel().rename(elements, dests, renamings, force, monitor);
+ }
+
+ /**
+ * Does nothing - this is not a working copy.
+ *
+ * @see IWorkingCopy
+ */
+ public void restore() throws JavaModelException {
+ }
+
+ /**
+ * Updates the source end index for this element.
+ */
+ public void triggerSourceEndOffset(int amount, int nameStart, int nameEnd) {
+ try {
+ CompilationUnitElementInfo cuInfo = (CompilationUnitElementInfo) getRawInfo();
+ cuInfo.setSourceLength(cuInfo.getSourceLength() + amount);
+ } catch (JavaModelException npe) {
+ return;
+ }
+ }
+
+ /**
+ * Updates the source indexes for this element.
+ */
+ public void triggerSourceRangeOffset(int amount, int nameStart, int nameEnd) {
+ triggerSourceEndOffset(amount, nameStart, nameEnd);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitElementInfo.java
new file mode 100644
index 0000000000..0806d983aa
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitElementInfo.java
@@ -0,0 +1,61 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.ISourceRange;
+import org.eclipse.jdt.internal.core.lookup.ReferenceInfo;
+
+/* package */
+class CompilationUnitElementInfo extends OpenableElementInfo {
+
+ /**
+ * The length of this compilation unit's source code <code>String</code>
+ */
+ protected int fSourceLength;
+
+ /**
+ * The reference information for this compilation unit
+ */
+ protected ReferenceInfo fRefInfo;
+ /**
+ * Timestamp of original resource at the time this element
+ * was opened or last updated.
+ */
+ protected long fTimestamp;
+ /**
+ * Returns the reference information for this compilation unit
+ */
+ public ReferenceInfo getReferenceInfo() {
+ return fRefInfo;
+ }
+
+ /**
+ * Returns the length of the source string.
+ */
+ public int getSourceLength() {
+ return fSourceLength;
+ }
+
+ protected ISourceRange getSourceRange() {
+ return new SourceRange(0, fSourceLength);
+ }
+
+ /**
+ * Sets the reference information for this compilation unit
+ */
+ public void setReferenceInfo(ReferenceInfo info) {
+ fRefInfo = info;
+ }
+
+ /**
+ * Sets the length of the source string.
+ */
+ public void setSourceLength(int newSourceLength) {
+ fSourceLength = newSourceLength;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitStructureRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitStructureRequestor.java
new file mode 100644
index 0000000000..b583ad616b
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitStructureRequestor.java
@@ -0,0 +1,779 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.internal.compiler.IProblem;
+import org.eclipse.jdt.internal.compiler.ISourceElementRequestor;
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+import org.eclipse.jdt.internal.core.lookup.ReferenceInfo;
+
+import java.util.*;
+
+/**
+ * A requestor for the fuzzy parser, used to compute the children of an ICompilationUnit.
+ */
+public class CompilationUnitStructureRequestor
+ implements ISourceElementRequestor {
+
+ /**
+ * The handle to the compilation unit being parsed
+ */
+ protected ICompilationUnit fUnit;
+
+ /**
+ * The info object for the compilation unit being parsed
+ */
+ protected CompilationUnitElementInfo fUnitInfo;
+
+ /**
+ * The import container info - null until created
+ */
+ protected JavaElementInfo fImportContainerInfo = null;
+
+ /**
+ * Hashtable of children elements of the compilation unit.
+ * Children are added to the table as they are found by
+ * the parser. Keys are handles, values are corresponding
+ * info objects.
+ */
+ protected Hashtable fNewElements;
+
+ /**
+ * Stack of parent scope info objects - i.e. the info on the
+ * top of the stack is the parent of the next element found.
+ * For example, when we locate a method, the parent info object
+ * will be the type the method is contained in.
+ */
+ protected Stack fInfoStack;
+
+ /**
+ * Stack of parent handles, corresponding to the info stack. We
+ * keep both, since info objects do not have back pointers to
+ * handles.
+ */
+ protected Stack fHandleStack;
+
+ /**
+ * The name of the source file being parsed.
+ */
+ protected char[] fSourceFileName = null;
+
+ /**
+ * The dot-separated name of the package the compilation unit
+ * is contained in - based on the package statement in the
+ * compilation unit, and initialized by #acceptPackage.
+ * Initialized to <code>null</code> for the default package.
+ */
+ protected char[] fPackageName = null;
+
+ /**
+ * Array of bytes describing reference info found during the
+ * parse. Entires are constants defined by ReferenceInfo,
+ * and the corresponding names are in fReferenceNames.
+ *
+ * @see ReferenceInfo
+ */
+ protected byte[] fReferenceKinds = fgEmptyByte;
+
+ /**
+ * Array of referenced names found during the
+ * parse. Entires are char arrays, and the corresponding
+ * reference kinds are in fReferenceKinds.
+ */
+ protected char[][] fReferenceNames = fgEmptyCharChar;
+
+ /**
+ * The number of references reported thus far. Used to
+ * expand the arrays of reference kinds and names.
+ */
+ protected int fRefCount = 0;
+
+ /**
+ * The initial size of the reference kind and name
+ * arrays. If the arrays fill, they are doubled in
+ * size
+ */
+ protected static int fgReferenceAllocation = 50;
+
+ /**
+ * Collection of problems reported during the parse.
+ * If any errors appear (i.e. not warnings), the structure
+ * of the compilation unit is considered unknown.
+ */
+ protected Vector fProblems;
+
+ /**
+ * Empty collections used for efficient initialization
+ */
+ protected static String[] fgEmptyStringArray = new String[0];
+ protected static byte[] fgEmptyByte = new byte[] {
+ };
+
+ protected static char[][] fgEmptyCharChar = new char[][] {
+ };
+
+ protected static char[] fgEmptyChar = new char[] {
+ };
+
+ protected HashtableOfObject fieldRefCache;
+ protected HashtableOfObject messageRefCache;
+ protected HashtableOfObject typeRefCache;
+ protected HashtableOfObject unknownRefCache;
+ protected CompilationUnitStructureRequestor(
+ ICompilationUnit unit,
+ CompilationUnitElementInfo unitInfo,
+ Hashtable newElements)
+ throws JavaModelException {
+ fUnit = unit;
+ fUnitInfo = unitInfo;
+ fNewElements = newElements;
+ fSourceFileName = unit.getElementName().toCharArray();
+ }
+
+ public void acceptConstructorReference(
+ char[] typeName,
+ int argCount,
+ int sourcePosition) {
+
+ // type name could be qualified
+ if (CharOperation.indexOf('.', typeName) < 0) {
+ acceptTypeReference(typeName, sourcePosition);
+ } else {
+ acceptTypeReference(CharOperation.splitOn('.', typeName), -1, -1);
+ // source positions are not used
+ // use simple name afterwards
+ typeName = CharOperation.lastSegment(typeName, '.');
+ }
+ if (argCount < 10) {
+ // common case (i.e. small arg count)
+ int len = typeName.length;
+ char[] name = new char[len + 4];
+ name[0] = '<';
+ System.arraycopy(typeName, 0, name, 1, len);
+ // fix for 1FWAKJJ
+ name[len + 1] = '>';
+ name[len + 2] = '/';
+ name[len + 3] = (char) ('0' + argCount);
+ addReference(ReferenceInfo.REFTYPE_call, name);
+ } else {
+ String name = "<" + new String(typeName) + ">/" + argCount;
+ addReference(ReferenceInfo.REFTYPE_call, name.toCharArray());
+ }
+ }
+
+ public void acceptFieldReference(char[] fieldName, int sourcePosition) {
+ addReference(ReferenceInfo.REFTYPE_var, fieldName);
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void acceptImport(
+ int declarationStart,
+ int declarationEnd,
+ char[] name,
+ boolean onDemand) {
+ JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
+ JavaElement parentHandle = (JavaElement) fHandleStack.peek();
+ if (!(parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT)) {
+ Assert.isTrue(false); // Should not happen
+ }
+
+ ICompilationUnit parentCU = (ICompilationUnit) parentHandle;
+ //create the import container and its info
+ IImportContainer importContainer = parentCU.getImportContainer();
+ if (fImportContainerInfo == null) {
+ fImportContainerInfo = new JavaElementInfo();
+ fImportContainerInfo.setIsStructureKnown(true);
+ parentInfo.addChild(importContainer);
+ fNewElements.put(importContainer, fImportContainerInfo);
+ }
+
+ // tack on the '.*' if it is onDemand
+ String importName;
+ if (onDemand) {
+ importName = new String(name) + ".*";
+ } else {
+ importName = new String(name);
+ }
+
+ ImportDeclaration handle = new ImportDeclaration(importContainer, importName);
+ resolveDuplicates(handle);
+
+ SourceRefElementInfo info = new SourceRefElementInfo();
+ info.setSourceRangeStart(declarationStart);
+ info.setSourceRangeEnd(declarationEnd);
+
+ fImportContainerInfo.addChild(handle);
+ fNewElements.put(handle, info);
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void acceptInitializer(
+ int modifiers,
+ int declarationSourceStart,
+ int declarationSourceEnd) {
+ JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
+ JavaElement parentHandle = (JavaElement) fHandleStack.peek();
+ IInitializer handle = null;
+
+ if (parentHandle.getElementType() == IJavaElement.TYPE) {
+ handle = ((IType) parentHandle).getInitializer(1);
+ } else {
+ Assert.isTrue(false); // Should not happen
+ }
+ resolveDuplicates(handle);
+
+ InitializerElementInfo info = new InitializerElementInfo();
+ info.setSourceRangeStart(declarationSourceStart);
+ info.setSourceRangeEnd(declarationSourceEnd);
+ info.setFlags(modifiers);
+
+ parentInfo.addChild(handle);
+ fNewElements.put(handle, info);
+ }
+
+ /*
+ * Table of line separator position. This table is passed once at the end
+ * of the parse action, so as to allow computation of normalized ranges.
+ *
+ * A line separator might corresponds to several characters in the source,
+ *
+ */
+ public void acceptLineSeparatorPositions(int[] positions) {
+ }
+
+ public void acceptMethodReference(
+ char[] methodName,
+ int argCount,
+ int sourcePosition) {
+ if (argCount < 10) {
+ // common case (i.e. small arg count)
+ int len = methodName.length;
+ char[] name = new char[len + 2];
+ System.arraycopy(methodName, 0, name, 0, len);
+ name[len] = '/';
+ name[len + 1] = (char) ('0' + argCount);
+ addReference(ReferenceInfo.REFTYPE_call, name);
+ } else {
+ String name = new String(methodName) + "/" + argCount;
+ addReference(ReferenceInfo.REFTYPE_call, name.toCharArray());
+ }
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void acceptPackage(
+ int declarationStart,
+ int declarationEnd,
+ char[] name) {
+
+ JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
+ JavaElement parentHandle = (JavaElement) fHandleStack.peek();
+ IPackageDeclaration handle = null;
+ fPackageName = name;
+
+ if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
+ handle =
+ new PackageDeclaration((ICompilationUnit) parentHandle, new String(name));
+ } else {
+ Assert.isTrue(false); // Should not happen
+ }
+ resolveDuplicates(handle);
+
+ SourceRefElementInfo info = new SourceRefElementInfo();
+ info.setSourceRangeStart(declarationStart);
+ info.setSourceRangeEnd(declarationEnd);
+
+ parentInfo.addChild(handle);
+ fNewElements.put(handle, info);
+
+ }
+
+ public void acceptProblem(IProblem problem) {
+ if (fProblems == null) {
+ fProblems = new Vector();
+ }
+ fProblems.addElement(problem);
+ }
+
+ public void acceptTypeReference(
+ char[][] typeName,
+ int sourceStart,
+ int sourceEnd) {
+ int last = typeName.length - 1;
+ for (int i = 0; i < last; ++i) {
+ addReference(ReferenceInfo.REFTYPE_unknown, typeName[i]);
+ }
+ addReference(ReferenceInfo.REFTYPE_type, typeName[last]);
+ }
+
+ public void acceptTypeReference(char[] typeName, int sourcePosition) {
+ addReference(ReferenceInfo.REFTYPE_type, typeName);
+ }
+
+ public void acceptUnknownReference(
+ char[][] name,
+ int sourceStart,
+ int sourceEnd) {
+ for (int i = 0; i < name.length; ++i) {
+ addReference(ReferenceInfo.REFTYPE_unknown, name[i]);
+ }
+ }
+
+ public void acceptUnknownReference(char[] name, int sourcePosition) {
+ addReference(ReferenceInfo.REFTYPE_unknown, name);
+ }
+
+ /**
+ * Adds the given reference to the reference info for this CU.
+ */
+ protected void addReference(byte kind, char[] name) {
+
+ HashtableOfObject refCache = null;
+ switch (kind) {
+ case ReferenceInfo.REFTYPE_unknown :
+ if ((refCache = this.unknownRefCache) == null) {
+ refCache = this.unknownRefCache = new HashtableOfObject(5);
+ }
+ break;
+ case ReferenceInfo.REFTYPE_call :
+ if ((refCache = this.messageRefCache) == null) {
+ refCache = this.messageRefCache = new HashtableOfObject(5);
+ }
+ break;
+ case ReferenceInfo.REFTYPE_type :
+ if ((refCache = this.typeRefCache) == null) {
+ refCache = this.typeRefCache = new HashtableOfObject(5);
+ }
+ break;
+ case ReferenceInfo.REFTYPE_var :
+ if ((refCache = this.fieldRefCache) == null) {
+ refCache = this.fieldRefCache = new HashtableOfObject(5);
+ }
+ break;
+ case ReferenceInfo.REFTYPE_import :
+ case ReferenceInfo.REFTYPE_derive :
+ case ReferenceInfo.REFTYPE_class :
+ case ReferenceInfo.REFTYPE_constant :
+ }
+ if (refCache == null)
+ addReference0(kind, name); // backward compatible
+ if (refCache.containsKey(name))
+ return;
+ refCache.put(name, name);
+ addReference0(kind, name);
+ }
+
+ /**
+ * Adds the given reference to the reference info for this CU.
+ */
+ private void addReference0(byte kind, char[] name) {
+
+ int count = fRefCount++;
+ if (count >= fReferenceKinds.length) {
+ int size = fgReferenceAllocation;
+ if (fReferenceKinds.length > 0) {
+ size = fReferenceKinds.length * 2;
+ }
+ byte[] kinds = new byte[size];
+ System.arraycopy(fReferenceKinds, 0, kinds, 0, fReferenceKinds.length);
+ fReferenceKinds = kinds;
+ char[][] names = new char[size][];
+ System.arraycopy(fReferenceNames, 0, names, 0, fReferenceNames.length);
+ fReferenceNames = names;
+ }
+ fReferenceKinds[count] = kind;
+ fReferenceNames[count] = name;
+ }
+
+ /**
+ * Convert these type names to signatures.
+ * @see Signature.
+ */
+ /* default */
+ static String[] convertTypeNamesToSigs(char[][] typeNames) {
+ if (typeNames == null)
+ return fgEmptyStringArray;
+ int n = typeNames.length;
+ if (n == 0)
+ return fgEmptyStringArray;
+ String[] typeSigs = new String[n];
+ for (int i = 0; i < n; ++i) {
+ typeSigs[i] = Signature.createTypeSignature(typeNames[i], false);
+ }
+ return typeSigs;
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterClass(
+ int declarationStart,
+ int modifiers,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[] superclass,
+ char[][] superinterfaces) {
+
+ enterType(
+ declarationStart,
+ modifiers,
+ name,
+ nameSourceStart,
+ nameSourceEnd,
+ superclass,
+ superinterfaces);
+
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterCompilationUnit() {
+ fInfoStack = new Stack();
+ fHandleStack = new Stack();
+ fInfoStack.push(fUnitInfo);
+ fHandleStack.push(fUnit);
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterConstructor(
+ int declarationStart,
+ int modifiers,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[][] parameterTypes,
+ char[][] parameterNames,
+ char[][] exceptionTypes) {
+
+ enterMethod(
+ declarationStart,
+ modifiers,
+ null,
+ name,
+ nameSourceStart,
+ nameSourceEnd,
+ parameterTypes,
+ parameterNames,
+ exceptionTypes,
+ true);
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterField(
+ int declarationStart,
+ int modifiers,
+ char[] type,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd) {
+
+ SourceTypeElementInfo parentInfo = (SourceTypeElementInfo) fInfoStack.peek();
+ JavaElement parentHandle = (JavaElement) fHandleStack.peek();
+ IField handle = null;
+
+ if (parentHandle.getElementType() == IJavaElement.TYPE) {
+ handle = new SourceField((IType) parentHandle, new String(name));
+ } else {
+ Assert.isTrue(false); // Should not happen
+ }
+ resolveDuplicates(handle);
+
+ SourceFieldElementInfo info = new SourceFieldElementInfo();
+ info.setName(name);
+ info.setNameSourceStart(nameSourceStart);
+ info.setNameSourceEnd(nameSourceEnd);
+ info.setSourceRangeStart(declarationStart);
+ info.setFlags(modifiers);
+ info.setTypeName(type);
+
+ parentInfo.addChild(handle);
+ parentInfo.addField(info);
+ fNewElements.put(handle, info);
+
+ fInfoStack.push(info);
+ fHandleStack.push(handle);
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterInterface(
+ int declarationStart,
+ int modifiers,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[][] superinterfaces) {
+
+ enterType(
+ declarationStart,
+ modifiers,
+ name,
+ nameSourceStart,
+ nameSourceEnd,
+ null,
+ superinterfaces);
+
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterMethod(
+ int declarationStart,
+ int modifiers,
+ char[] returnType,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[][] parameterTypes,
+ char[][] parameterNames,
+ char[][] exceptionTypes) {
+
+ enterMethod(
+ declarationStart,
+ modifiers,
+ returnType,
+ name,
+ nameSourceStart,
+ nameSourceEnd,
+ parameterTypes,
+ parameterNames,
+ exceptionTypes,
+ false);
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ protected void enterMethod(
+ int declarationStart,
+ int modifiers,
+ char[] returnType,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[][] parameterTypes,
+ char[][] parameterNames,
+ char[][] exceptionTypes,
+ boolean isConstructor) {
+
+ SourceTypeElementInfo parentInfo = (SourceTypeElementInfo) fInfoStack.peek();
+ JavaElement parentHandle = (JavaElement) fHandleStack.peek();
+ IMethod handle = null;
+
+ // translate nulls to empty arrays
+ if (parameterTypes == null) {
+ parameterTypes = fgEmptyCharChar;
+ }
+ if (parameterNames == null) {
+ parameterNames = fgEmptyCharChar;
+ }
+ if (exceptionTypes == null) {
+ exceptionTypes = fgEmptyCharChar;
+ }
+
+ String[] parameterTypeSigs = convertTypeNamesToSigs(parameterTypes);
+ if (parentHandle.getElementType() == IJavaElement.TYPE) {
+ handle =
+ new SourceMethod((IType) parentHandle, new String(name), parameterTypeSigs);
+ } else {
+ Assert.isTrue(false); // Should not happen
+ }
+ resolveDuplicates(handle);
+
+ SourceMethodElementInfo info = new SourceMethodElementInfo();
+ info.setSourceRangeStart(declarationStart);
+ int flags = modifiers;
+ info.setName(name);
+ info.setNameSourceStart(nameSourceStart);
+ info.setNameSourceEnd(nameSourceEnd);
+ info.setConstructor(isConstructor);
+ info.setFlags(flags);
+ info.setArgumentNames(parameterNames);
+ info.setArgumentTypeNames(parameterTypes);
+ info.setReturnType(returnType == null ? new char[] { 'v', 'o', 'i', 'd' }
+ : returnType);
+ info.setExceptionTypeNames(exceptionTypes);
+
+ parentInfo.addChild(handle);
+ parentInfo.addMethod(info);
+ fNewElements.put(handle, info);
+ fInfoStack.push(info);
+ fHandleStack.push(handle);
+ }
+
+ /**
+ * Common processing for classes and interfaces.
+ */
+ protected void enterType(
+ int declarationStart,
+ int modifiers,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[] superclass,
+ char[][] superinterfaces) {
+
+ char[] enclosingTypeName = null;
+ char[] qualifiedName = null;
+
+ JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
+ JavaElement parentHandle = (JavaElement) fHandleStack.peek();
+ IType handle = null;
+ String nameString = new String(name);
+
+ if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
+ handle = ((ICompilationUnit) parentHandle).getType(nameString);
+ if (fPackageName == null) {
+ qualifiedName = nameString.toCharArray();
+ } else {
+ qualifiedName = (new String(fPackageName) + "." + nameString).toCharArray();
+ }
+ } else
+ if (parentHandle.getElementType() == IJavaElement.TYPE) {
+ handle = ((IType) parentHandle).getType(nameString);
+ enclosingTypeName = ((SourceTypeElementInfo) parentInfo).getName();
+ qualifiedName =
+ (new String(((SourceTypeElementInfo) parentInfo).getQualifiedName())
+ + "."
+ + nameString)
+ .toCharArray();
+ } else {
+ Assert.isTrue(false); // Should not happen
+ }
+ resolveDuplicates(handle);
+
+ SourceTypeElementInfo info = new SourceTypeElementInfo();
+ info.setHandle(handle);
+ info.setSourceRangeStart(declarationStart);
+ info.setFlags(modifiers);
+ info.setName(name);
+ info.setNameSourceStart(nameSourceStart);
+ info.setNameSourceEnd(nameSourceEnd);
+ info.setSuperclassName(superclass);
+ info.setSuperInterfaceNames(superinterfaces);
+ info.setEnclosingTypeName(enclosingTypeName);
+ info.setSourceFileName(fSourceFileName);
+ info.setPackageName(fPackageName);
+ info.setQualifiedName(qualifiedName);
+ Enumeration e = fNewElements.keys();
+ while (e.hasMoreElements()) {
+ Object object = e.nextElement();
+ if (object instanceof IImportDeclaration)
+ info.addImport(((IImportDeclaration) object).getElementName().toCharArray());
+ }
+
+ parentInfo.addChild(handle);
+ if (parentInfo instanceof SourceTypeElementInfo) {
+ ((SourceTypeElementInfo) parentInfo).addMemberType(info);
+ }
+ fNewElements.put(handle, info);
+
+ fInfoStack.push(info);
+ fHandleStack.push(handle);
+
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitClass(int declarationEnd) {
+ exitMember(declarationEnd);
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitCompilationUnit(int declarationEnd) {
+ fUnitInfo.setSourceLength(declarationEnd + 1);
+
+ // make the reference arrays the correct size
+ if (fRefCount != fReferenceKinds.length) {
+ byte[] kinds = new byte[fRefCount];
+ System.arraycopy(fReferenceKinds, 0, kinds, 0, fRefCount);
+ fReferenceKinds = kinds;
+ char[][] names = new char[fRefCount][];
+ System.arraycopy(fReferenceNames, 0, names, 0, fRefCount);
+ fReferenceNames = names;
+ }
+ fUnitInfo.setReferenceInfo(new ReferenceInfo(fReferenceNames, fReferenceKinds));
+
+ // determine if there were any parsing errors
+ fUnitInfo.setIsStructureKnown(true);
+ if (fProblems != null) {
+ for (int i = 0; i < fProblems.size(); i++) {
+ IProblem problem = (IProblem) fProblems.elementAt(i);
+ if (!problem.isWarning()) {
+ fUnitInfo.setIsStructureKnown(false);
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitConstructor(int declarationEnd) {
+ exitMember(declarationEnd);
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitField(int declarationEnd) {
+ exitMember(declarationEnd);
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitInterface(int declarationEnd) {
+ exitMember(declarationEnd);
+ }
+
+ /**
+ * common processing for classes and interfaces
+ */
+ protected void exitMember(int declarationEnd) {
+ SourceRefElementInfo info = (SourceRefElementInfo) fInfoStack.pop();
+ info.setSourceRangeEnd(declarationEnd);
+ fHandleStack.pop();
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitMethod(int declarationEnd) {
+ exitMember(declarationEnd);
+ }
+
+ /**
+ * Resolves duplicate handles by incrementing the occurrence count
+ * of the handle being created until there is no conflict.
+ */
+ protected void resolveDuplicates(IJavaElement handle) {
+ while (fNewElements.containsKey(handle)) {
+ JavaElement h = (JavaElement) handle;
+ h.setOccurrenceCount(h.getOccurrenceCount() + 1);
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitVisitor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitVisitor.java
new file mode 100644
index 0000000000..2c68bb7195
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitVisitor.java
@@ -0,0 +1,155 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
+import org.eclipse.jdt.internal.compiler.parser.SourceTypeConverter;
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+import java.io.*;
+import java.util.*;
+
+public class CompilationUnitVisitor extends Compiler {
+/**
+ * Answer a new CompilationUnitVisitor using the given name environment and compiler options.
+ * The environment and options will be in effect for the lifetime of the compiler.
+ * When the compiler is run, compilation results are sent to the given requestor.
+ *
+ * @param environment org.eclipse.jdt.internal.compiler.api.env.INameEnvironment
+ * Environment used by the compiler in order to resolve type and package
+ * names. The name environment implements the actual connection of the compiler
+ * to the outside world (e.g. in batch mode the name environment is performing
+ * pure file accesses, reuse previous build state or connection to repositories).
+ * Note: the name environment is responsible for implementing the actual classpath
+ * rules.
+ *
+ * @param policy org.eclipse.jdt.internal.compiler.api.problem.IErrorHandlingPolicy
+ * Configurable part for problem handling, allowing the compiler client to
+ * specify the rules for handling problems (stop on first error or accumulate
+ * them all) and at the same time perform some actions such as opening a dialog
+ * in UI when compiling interactively.
+ * @see org.eclipse.jdt.internal.compiler.api.problem.DefaultErrorHandlingPolicies
+ *
+ * @param requestor org.eclipse.jdt.internal.compiler.api.ICompilerRequestor
+ * Component which will receive and persist all compilation results and is intended
+ * to consume them as they are produced. Typically, in a batch compiler, it is
+ * responsible for writing out the actual .class files to the file system.
+ * @see org.eclipse.jdt.internal.compiler.api.CompilationResult
+ *
+ * @param problemFactory org.eclipse.jdt.internal.compiler.api.problem.IProblemFactory
+ * Factory used inside the compiler to create problem descriptors. It allows the
+ * compiler client to supply its own representation of compilation problems in
+ * order to avoid object conversions. Note that the factory is not supposed
+ * to accumulate the created problems, the compiler will gather them all and hand
+ * them back as part of the compilation unit result.
+ */
+public CompilationUnitVisitor(
+ INameEnvironment environment,
+ IErrorHandlingPolicy policy,
+ ConfigurableOption[] settings,
+ ICompilerRequestor requestor,
+ IProblemFactory problemFactory) {
+
+ super(environment, policy, settings, requestor, problemFactory);
+}
+/**
+ * Add an additional source type
+ */
+public void accept(ISourceType sourceType, PackageBinding packageBinding) {
+ CompilationResult result = new CompilationResult(sourceType.getFileName(), 1, 1); // need to hold onto this
+ CompilationUnitDeclaration unit =
+ SourceTypeConverter.buildCompilationUnit(sourceType, true, true, lookupEnvironment.problemReporter, result);
+
+ if (unit != null) {
+ this.lookupEnvironment.buildTypeBindings(unit);
+ this.lookupEnvironment.completeTypeBindings(unit, true);
+ }
+}
+/*
+ * Low-level API performing the actual compilation
+ */
+protected static IErrorHandlingPolicy getHandlingPolicy() {
+
+ // passes the initial set of files to the batch oracle (to avoid finding more than once the same units when case insensitive match)
+ return new IErrorHandlingPolicy() {
+ public boolean stopOnFirstError() {
+ return true;
+ }
+ public boolean proceedOnErrors() {
+ return false; // stop if there are some errors
+ }
+ };
+}
+protected static INameEnvironment getNameEnvironment(ICompilationUnit sourceUnit) throws JavaModelException {
+ return (SearchableEnvironment) ((JavaProject) sourceUnit.getJavaProject())
+ .getSearchableNameEnvironment();
+}
+/*
+ * Low-level API performing the actual compilation
+ */
+protected static ConfigurableOption[] getOptions() {
+ CompilerOptions options = new CompilerOptions();
+ return options.getConfigurableOptions(Locale.getDefault());
+}
+protected static IProblemFactory getProblemFactory(final IAbstractSyntaxTreeVisitor visitor) {
+
+ return new DefaultProblemFactory(Locale.getDefault()){
+ public IProblem createProblem(char[] originatingFileName, int problemId, String[] arguments, int severity, int startPosition, int endPosition, int lineNumber) {
+
+ IProblem problem = super.createProblem(
+ originatingFileName,
+ problemId,
+ arguments,
+ severity,
+ startPosition,
+ endPosition,
+ lineNumber);
+ visitor.acceptProblem(problem);
+ return problem;
+ }
+ };
+}
+/*
+ * Answer the component to which will be handed back compilation results from the compiler
+ */
+protected static ICompilerRequestor getRequestor() {
+ return new ICompilerRequestor() {
+ public void acceptResult(CompilationResult compilationResult) {
+ }
+ };
+}
+public static void visit(ICompilationUnit unitElement, IAbstractSyntaxTreeVisitor visitor) throws JavaModelException {
+
+ CompilationUnitVisitor compilationUnitVisitor = new CompilationUnitVisitor(
+ getNameEnvironment(unitElement),
+ getHandlingPolicy(),
+ getOptions(),
+ getRequestor(),
+ getProblemFactory(visitor));
+
+
+ CompilationUnitDeclaration unit = null;
+ try {
+ unit = compilationUnitVisitor.resolve(
+ new BasicCompilationUnit(
+ unitElement.getSource().toCharArray(),
+ unitElement.getElementName()));
+ if (unit != null) {
+ unit.traverse(visitor, unit.scope);
+ }
+ } finally {
+ if (unit != null) {
+ unit.cleanUp();
+ }
+ }
+}
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompletionRequestorWrapper.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompletionRequestorWrapper.java
new file mode 100644
index 0000000000..11d6ee7f35
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompletionRequestorWrapper.java
@@ -0,0 +1,222 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+import org.eclipse.jdt.internal.codeassist.ICompletionRequestor;
+import org.eclipse.jdt.internal.compiler.IProblem;
+import org.eclipse.jdt.core.*;
+
+public class CompletionRequestorWrapper implements ICompletionRequestor {
+ ICodeCompletionRequestor clientRequestor;
+ public CompletionRequestorWrapper(ICodeCompletionRequestor clientRequestor) {
+ this.clientRequestor = clientRequestor;
+ }
+
+ /**
+ * See ICompletionRequestor
+ */
+ public void acceptClass(
+ char[] packageName,
+ char[] className,
+ char[] completionName,
+ int modifiers,
+ int completionStart,
+ int completionEnd) {
+
+ this.clientRequestor.acceptClass(
+ packageName,
+ className,
+ completionName,
+ modifiers,
+ completionStart,
+ completionEnd);
+ }
+
+ /**
+ * See ICompletionRequestor
+ */
+ public void acceptError(IProblem error) {
+
+ if (true)
+ return; // work-around PR 1GD9RLP: ITPJCORE:WIN2000 - Code assist is slow
+ try {
+ IMarker marker =
+ ResourcesPlugin.getWorkspace().getRoot().createMarker(
+ IJavaModelMarker.TRANSIENT_PROBLEM);
+ marker.setAttribute(IJavaModelMarker.ID, error.getID());
+ marker.setAttribute(IMarker.CHAR_START, error.getSourceStart());
+ marker.setAttribute(IMarker.CHAR_END, error.getSourceEnd() + 1);
+ marker.setAttribute(IMarker.LINE_NUMBER, error.getSourceLineNumber());
+ //marker.setAttribute(IMarker.LOCATION, "#" + error.getSourceLineNumber());
+ marker.setAttribute(IMarker.MESSAGE, error.getMessage());
+ marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
+
+ this.clientRequestor.acceptError(marker);
+
+ } catch (CoreException e) {
+ }
+ }
+
+ /**
+ * See ICompletionRequestor
+ */
+ public void acceptField(
+ char[] declaringTypePackageName,
+ char[] declaringTypeName,
+ char[] name,
+ char[] typePackageName,
+ char[] typeName,
+ char[] completionName,
+ int modifiers,
+ int completionStart,
+ int completionEnd) {
+ this.clientRequestor.acceptField(
+ declaringTypePackageName,
+ declaringTypeName,
+ name,
+ typePackageName,
+ typeName,
+ completionName,
+ modifiers,
+ completionStart,
+ completionEnd);
+ }
+
+ /**
+ * See ICompletionRequestor
+ */
+ public void acceptInterface(
+ char[] packageName,
+ char[] interfaceName,
+ char[] completionName,
+ int modifiers,
+ int completionStart,
+ int completionEnd) {
+ this.clientRequestor.acceptInterface(
+ packageName,
+ interfaceName,
+ completionName,
+ modifiers,
+ completionStart,
+ completionEnd);
+ }
+
+ /**
+ * See ICompletionRequestor
+ */
+ public void acceptKeyword(
+ char[] keywordName,
+ int completionStart,
+ int completionEnd) {
+ this.clientRequestor.acceptKeyword(keywordName, completionStart, completionEnd);
+ }
+
+ /**
+ * See ICompletionRequestor
+ */
+ public void acceptLabel(
+ char[] labelName,
+ int completionStart,
+ int completionEnd) {
+ this.clientRequestor.acceptLabel(labelName, completionStart, completionEnd);
+ }
+
+ /**
+ * See ICompletionRequestor
+ */
+ public void acceptLocalVariable(
+ char[] name,
+ char[] typePackageName,
+ char[] typeName,
+ int modifiers,
+ int completionStart,
+ int completionEnd) {
+ this.clientRequestor.acceptLocalVariable(
+ name,
+ typePackageName,
+ typeName,
+ modifiers,
+ completionStart,
+ completionEnd);
+ }
+
+ /**
+ * See ICompletionRequestor
+ */
+ public void acceptMethod(
+ char[] declaringTypePackageName,
+ char[] declaringTypeName,
+ char[] selector,
+ char[][] parameterPackageNames,
+ char[][] parameterTypeNames,
+ char[] returnTypePackageName,
+ char[] returnTypeName,
+ char[] completionName,
+ int modifiers,
+ int completionStart,
+ int completionEnd) {
+ this.clientRequestor.acceptMethod(
+ declaringTypePackageName,
+ declaringTypeName,
+ selector,
+ parameterPackageNames,
+ parameterTypeNames,
+ returnTypePackageName,
+ returnTypeName,
+ completionName,
+ modifiers,
+ completionStart,
+ completionEnd);
+ }
+
+ /**
+ * See ICompletionRequestor
+ */
+ public void acceptModifier(
+ char[] modifierName,
+ int completionStart,
+ int completionEnd) {
+ this.clientRequestor.acceptModifier(
+ modifierName,
+ completionStart,
+ completionEnd);
+ }
+
+ /**
+ * See ICompletionRequestor
+ */
+ public void acceptPackage(
+ char[] packageName,
+ char[] completionName,
+ int completionStart,
+ int completionEnd) {
+ this.clientRequestor.acceptPackage(
+ packageName,
+ completionName,
+ completionStart,
+ completionEnd);
+ }
+
+ /**
+ * See ICompletionRequestor
+ */
+ public void acceptType(
+ char[] packageName,
+ char[] typeName,
+ char[] completionName,
+ int completionStart,
+ int completionEnd) {
+ this.clientRequestor.acceptType(
+ packageName,
+ typeName,
+ completionName,
+ completionStart,
+ completionEnd);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyElementsOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyElementsOperation.java
new file mode 100644
index 0000000000..ffd41512cf
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyElementsOperation.java
@@ -0,0 +1,290 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.jdom.*;
+import org.eclipse.jdt.internal.core.jdom.*;
+import java.util.Hashtable;
+
+/**
+ * This operation copies/moves a collection of elements from their current
+ * container to a new container, optionally renaming the
+ * elements.
+ * <p>Notes:<ul>
+ * <li>If there is already an element with the same name in
+ * the new container, the operation either overwrites or aborts,
+ * depending on the collision policy setting. The default setting is
+ * abort.
+ *
+ * <li>When constructors are copied to a type, the constructors
+ * are automatically renamed to the name of the destination
+ * type.
+ *
+ * <li>When main types are renamed (move within the same parent),
+ * the compilation unit and constructors are automatically renamed
+ *
+ * <li>The collection of elements being copied must all share the
+ * same type of container (for example, must all be type members).
+ *
+ * <li>The elements are inserted in the new container in the order given.
+ *
+ * <li>The elements can be positioned in the new container - see #setInsertBefore.
+ * By default, the elements are inserted based on the default positions as specified in
+ * the creation operation for that element type.
+ *
+ * <li>This operation can be used to copy and rename elements within
+ * the same container.
+ *
+ * <li>This operation only copies elements contained within compilation units.
+ * </ul>
+ *
+ */
+public class CopyElementsOperation extends MultiOperation {
+
+ private Hashtable fSources = new Hashtable();
+ /**
+ * When executed, this operation will copy the given elements to the
+ * given containers. The elements and destination containers must be in
+ * the correct order. If there is > 1 destination, the number of destinations
+ * must be the same as the number of elements being copied/moved/renamed.
+ */
+ public CopyElementsOperation(
+ IJavaElement[] elementsToCopy,
+ IJavaElement[] destContainers,
+ boolean force) {
+ super(elementsToCopy, destContainers, force);
+ }
+
+ /**
+ * When executed, this operation will copy the given elements to the
+ * given container.
+ */
+ public CopyElementsOperation(
+ IJavaElement[] elementsToCopy,
+ IJavaElement destContainer,
+ boolean force) {
+ this(elementsToCopy, new IJavaElement[] { destContainer }, force);
+ }
+
+ /**
+ * Returns the <code>String</code> to use as the main task name
+ * for progress monitoring.
+ */
+ protected String getMainTaskName() {
+ return "Copying elements...";
+ }
+
+ /**
+ * Returns the nested operation to use for processing this element
+ */
+ protected JavaModelOperation getNestedOperation(IJavaElement element) {
+ try {
+ IJavaElement dest = getDestinationParent(element);
+ switch (element.getElementType()) {
+ case IJavaElement.PACKAGE_DECLARATION :
+ return new CreatePackageDeclarationOperation(
+ element.getElementName(),
+ (ICompilationUnit) dest);
+ case IJavaElement.IMPORT_DECLARATION :
+ return new CreateImportOperation(
+ element.getElementName(),
+ (ICompilationUnit) dest);
+ case IJavaElement.TYPE :
+ if (isRenamingMainType(element, dest)) {
+ return new RenameResourceElementsOperation(
+ new IJavaElement[] { dest },
+ new IJavaElement[] { dest.getParent()},
+ new String[] { getNewNameFor(element) + ".java" },
+ fForce);
+ } else {
+ return new CreateTypeOperation(
+ dest,
+ getSourceFor(element) + JavaModelManager.LINE_SEPARATOR,
+ fForce);
+ }
+ case IJavaElement.METHOD :
+ return new CreateMethodOperation(
+ (IType) dest,
+ getSourceFor(element) + JavaModelManager.LINE_SEPARATOR,
+ fForce);
+ case IJavaElement.FIELD :
+ return new CreateFieldOperation(
+ (IType) dest,
+ getSourceFor(element) + JavaModelManager.LINE_SEPARATOR,
+ fForce);
+ case IJavaElement.INITIALIZER :
+ return new CreateInitializerOperation(
+ (IType) dest,
+ getSourceFor(element) + JavaModelManager.LINE_SEPARATOR);
+ default :
+ return null;
+ }
+ } catch (JavaModelException npe) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the cached source for this element or compute it if not already cached.
+ */
+ private String getSourceFor(IJavaElement element) throws JavaModelException {
+ String source = (String) fSources.get(element);
+ if (source == null && element instanceof IMember) {
+ IMember member = (IMember) element;
+ ICompilationUnit cu = member.getCompilationUnit();
+ String cuSource = cu.getSource();
+ IDOMCompilationUnit domCU =
+ new DOMFactory().createCompilationUnit(cuSource, cu.getElementName());
+ IDOMNode node = ((JavaElement) element).findNode(domCU);
+ source = new String(node.getCharacters());
+ fSources.put(element, source);
+ }
+ return source;
+ }
+
+ /**
+ * Returns <code>true</code> if this element is the main type of its compilation unit.
+ */
+ protected boolean isRenamingMainType(IJavaElement element, IJavaElement dest) {
+ if ((isRename() || getNewNameFor(element) != null)
+ && dest.getElementType() == IJavaElement.COMPILATION_UNIT) {
+ String typeName = dest.getElementName();
+ typeName = typeName.substring(0, typeName.length() - 5);
+ return element.getElementName().equals(typeName)
+ && element.getParent().equals(dest);
+ }
+ return false;
+ }
+
+ /**
+ * Copy/move the element from the source to destination, renaming
+ * the elements as specified, honoring the collision policy.
+ *
+ * @exception JavaModelException if the operation is unable to
+ * be completed
+ */
+ protected void processElement(IJavaElement element) throws JavaModelException {
+ JavaModelOperation op = getNestedOperation(element);
+ boolean createElementInCUOperation = op instanceof CreateElementInCUOperation;
+ if (op == null) {
+ return;
+ }
+ if (createElementInCUOperation) {
+ IJavaElement sibling = (IJavaElement) fInsertBeforeElements.get(element);
+ if (sibling != null) {
+ ((CreateElementInCUOperation) op).setRelativePosition(
+ sibling,
+ CreateElementInCUOperation.INSERT_BEFORE);
+ } else
+ if (isRename()) {
+ IJavaElement anchor = resolveRenameAnchor(element);
+ if (anchor != null) {
+ ((CreateElementInCUOperation) op).setRelativePosition(
+ anchor,
+ CreateElementInCUOperation.INSERT_AFTER);
+ // insert after so that the anchor is found before when deleted below
+ }
+ }
+ String newName = getNewNameFor(element);
+ if (newName != null) {
+ ((CreateElementInCUOperation) op).setAlteredName(newName);
+ }
+ }
+ executeNestedOperation(op, 1);
+
+ JavaElement destination = (JavaElement) getDestinationParent(element);
+ destination.getCompilationUnit().close();
+
+ if (createElementInCUOperation
+ && isMove()
+ && !isRenamingMainType(element, destination)) {
+ DeleteElementsOperation deleteOp =
+ new DeleteElementsOperation(new IJavaElement[] { element }, fForce);
+ executeNestedOperation(deleteOp, 1);
+ }
+ }
+
+ /**
+ * Returns the anchor used for positioning in the destination for
+ * the element being renamed. For renaming, if no anchor has
+ * explicitly been provided, the element is anchored in the same position.
+ */
+ private IJavaElement resolveRenameAnchor(IJavaElement element)
+ throws JavaModelException {
+ IParent parent = (IParent) element.getParent();
+ IJavaElement[] children = parent.getChildren();
+ for (int i = 0; i < children.length; i++) {
+ IJavaElement child = children[i];
+ if (child.equals(element)) {
+ return child;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Possible failures:
+ * <ul>
+ * <li>NO_ELEMENTS_TO_PROCESS - no elements supplied to the operation
+ * <li>INDEX_OUT_OF_BOUNDS - the number of renamings supplied to the operation
+ * does not match the number of elements that were supplied.
+ * </ul>
+ */
+ protected IJavaModelStatus verify() {
+ IJavaModelStatus status = super.verify();
+ if (!status.isOK()) {
+ return status;
+ }
+ if (fRenamingsList != null
+ && fRenamingsList.length != fElementsToProcess.length) {
+ return new JavaModelStatus(IJavaModelStatusConstants.INDEX_OUT_OF_BOUNDS);
+ }
+ return JavaModelStatus.VERIFIED_OK;
+ }
+
+ /**
+ * @see MultiOperation
+ *
+ * Possible failure codes:
+ * <ul>
+ *
+ * <li>ELEMENT_DOES_NOT_EXIST - <code>element</code> or its specified destination is
+ * is <code>null</code> or does not exist. If a <code>null</code> element is
+ * supplied, no element is provided in the status, otherwise, the non-existant element
+ * is supplied in the status.
+ * <li>INVALID_ELEMENT_TYPES - <code>element</code> is not contained within a compilation unit.
+ * This operation only operates on elements contained within compilation units.
+ * <li>READ_ONLY - <code>element</code> is read only.
+ * <li>INVALID_DESTINATION - The destination parent specified for <code>element</code>
+ * is of an incompatible type. The destination for a package declaration or import declaration must
+ * be a compilation unit; the destination for a type must be a type or compilation
+ * unit; the destinaion for any type member (other than a type) must be a type. When
+ * this error occurs, the element provided in the operation status is the <code>element</code>.
+ * <li>INVALID_NAME - the new name for <code>element</code> does not have valid syntax.
+ * In this case the element and name are provided in the status.
+
+ * </ul>
+ */
+ protected void verify(IJavaElement element) throws JavaModelException {
+ if (element == null || !element.exists())
+ error(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, element);
+
+ if (element.getElementType() < IJavaElement.TYPE)
+ error(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element);
+
+ if (element.isReadOnly())
+ error(IJavaModelStatusConstants.READ_ONLY, element);
+
+ IJavaElement dest = getDestinationParent(element);
+ verifyDestination(element, dest);
+ verifySibling(element, dest);
+ if (fRenamingsList != null) {
+ verifyRenaming(element);
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyResourceElementsOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyResourceElementsOperation.java
new file mode 100644
index 0000000000..56c57b657e
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyResourceElementsOperation.java
@@ -0,0 +1,581 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.*;
+import org.eclipse.core.resources.*;
+import org.eclipse.core.resources.*;
+import java.io.ByteArrayInputStream;
+import java.util.*;
+
+import org.eclipse.jdt.core.jdom.*;
+import org.eclipse.jdt.core.*;
+
+/**
+ * This operation copies/moves/renames a collection of resources from their current
+ * container to a new container, optionally renaming the
+ * elements.
+ * <p>Notes:<ul>
+ * <li>If there is already an resource with the same name in
+ * the new container, the operation either overwrites or aborts,
+ * depending on the collision policy setting. The default setting is
+ * abort.
+ *
+ * <li>When a compilation unit is copied to a new package, the
+ * package declaration in the compilation unit is automatically updated.
+ *
+ * <li>The collection of elements being copied must all share the
+ * same type of container.
+ *
+ * <li>This operation can be used to copy and rename elements within
+ * the same container.
+ *
+ * <li>This operation only copies compilation units and package fragments.
+ * It does not copy package fragment roots - a platform operation must be used for that.
+ * </ul>
+ *
+ */
+public class CopyResourceElementsOperation extends MultiOperation {
+ /**
+ * A collection of renamed compilation units. These cus do
+ * not need to be saved as they no longer exist.
+ */
+ protected Vector fRenamedCompilationUnits = null;
+ /**
+ * Table specifying deltas for elements being
+ * copied/moved/renamed. Keyed by elements' project(s), and
+ * values are the corresponding deltas.
+ */
+ protected Hashtable fDeltasPerProject = new Hashtable(1);
+ /**
+ * The <code>DOMFactory</code> used to manipulate the source code of
+ * <code>ICompilationUnit</code>.
+ */
+ protected DOMFactory fFactory;
+ /**
+ * The list of new resources created during this operation.
+ */
+ protected Vector fCreatedElements;
+ /**
+ * When executed, this operation will copy the given resources to the
+ * given containers. The resources and destination containers must be in
+ * the correct order. If there is > 1 destination, the number of destinations
+ * must be the same as the number of resources being copied/moved.
+ */
+ public CopyResourceElementsOperation(
+ IJavaElement[] resourcesToCopy,
+ IJavaElement[] destContainers,
+ boolean force) {
+ super(resourcesToCopy, destContainers, force);
+ fFactory = new DOMFactory();
+ }
+
+ /**
+ * When executed, this operation will copy the given resources to the
+ * given container.
+ */
+ public CopyResourceElementsOperation(
+ IJavaElement[] resourcesToCopy,
+ IJavaElement destContainer,
+ boolean force) {
+ this(resourcesToCopy, new IJavaElement[] { destContainer }, force);
+ }
+
+ /**
+ * Returns the children of <code>source</code> which are affected by this operation.
+ * If <code>source</code> is a <code>K_SOURCE</code>, these are the <code>.java</code>
+ * files, if it is a <code>K_BINARY</code>, they are the <code>.class</code> files.
+ */
+ private IResource[] collectResourcesOfInterest(IPackageFragment source)
+ throws JavaModelException {
+ IJavaElement[] children = source.getChildren();
+ int childOfInterest = IJavaElement.COMPILATION_UNIT;
+ if (source.getKind() == IPackageFragmentRoot.K_BINARY) {
+ childOfInterest = IJavaElement.CLASS_FILE;
+ }
+ Vector correctKindChildren = new Vector(children.length);
+ for (int i = 0; i < children.length; i++) {
+ IJavaElement child = children[i];
+ if (child.getElementType() == childOfInterest) {
+ correctKindChildren.addElement(child.getUnderlyingResource());
+ }
+ }
+ // Gather non-java resources
+ Object[] nonJavaResources = source.getNonJavaResources();
+ int actualNonJavaResourceCount = 0;
+ for (int i = 0, max = nonJavaResources.length; i < max; i++) {
+ if (nonJavaResources[i] instanceof IResource)
+ actualNonJavaResourceCount++;
+ }
+ IResource[] actualNonJavaResources = new IResource[actualNonJavaResourceCount];
+ for (int i = 0, max = nonJavaResources.length, index = 0; i < max; i++) {
+ if (nonJavaResources[i] instanceof IResource)
+ actualNonJavaResources[index++] = (IResource) nonJavaResources[i];
+ }
+
+ if (actualNonJavaResourceCount != 0) {
+ int correctKindChildrenSize = correctKindChildren.size();
+ IResource[] result =
+ new IResource[correctKindChildrenSize + actualNonJavaResourceCount];
+ correctKindChildren.copyInto(result);
+ System.arraycopy(
+ actualNonJavaResources,
+ 0,
+ result,
+ correctKindChildrenSize,
+ actualNonJavaResourceCount);
+ return result;
+ } else {
+ IResource[] result = new IResource[correctKindChildren.size()];
+ correctKindChildren.copyInto(result);
+ return result;
+ }
+ }
+
+ /**
+ * Creates any destination package fragment(s) which do not exists yet.
+ */
+ private void createNeededPackageFragments(
+ IPackageFragmentRoot root,
+ String newFragName)
+ throws JavaModelException {
+ IContainer parentFolder = (IContainer) root.getUnderlyingResource();
+ JavaElementDelta projectDelta = getDeltaFor(root.getJavaProject());
+ String[] names = Signature.getSimpleNames(newFragName);
+ StringBuffer sideEffectPackageName = new StringBuffer();
+ for (int i = 0; i < names.length; i++) {
+ String subFolderName = names[i];
+ sideEffectPackageName.append(subFolderName);
+ IResource subFolder = parentFolder.findMember(subFolderName);
+ if (subFolder == null) {
+ createFolder(parentFolder, subFolderName, fForce);
+ parentFolder = parentFolder.getFolder(new Path(subFolderName));
+ IPackageFragment sideEffectPackage =
+ root.getPackageFragment(sideEffectPackageName.toString());
+ if (i < names.length - 1) { // all but the last one are side effect packages
+ projectDelta.added(sideEffectPackage);
+ }
+ fCreatedElements.addElement(sideEffectPackage);
+ } else {
+ parentFolder = (IContainer) subFolder;
+ }
+ sideEffectPackageName.append('.');
+ }
+ }
+
+ /**
+ * Returns the <code>JavaElementDelta</code> for <code>javaProject</code>,
+ * creating it and putting it in <code>fDeltasPerProject</code> if
+ * it does not exist yet.
+ */
+ private JavaElementDelta getDeltaFor(IJavaProject javaProject) {
+ JavaElementDelta delta = (JavaElementDelta) fDeltasPerProject.get(javaProject);
+ if (delta == null) {
+ delta = new JavaElementDelta(javaProject);
+ fDeltasPerProject.put(javaProject, delta);
+ }
+ return delta;
+ }
+
+ /**
+ * @see MultiOperation
+ */
+ protected String getMainTaskName() {
+ return "Copying resources...";
+ }
+
+ /**
+ * Sets the deltas to register the changes resulting from this operation
+ * for this source element and its destination.
+ * If the operation is a cross project operation<ul>
+ * <li>On a copy, the delta should be rooted in the dest project
+ * <li>On a move, two deltas are generated<ul>
+ * <li>one rooted in the source project
+ * <li>one rooted in the destination project</ul></ul>
+ * If the operation is rooted in a single project, the delta is rooted in that project
+ *
+ */
+ protected void prepareDeltas(
+ IJavaElement sourceElement,
+ IJavaElement destinationElement) {
+ IJavaProject destProject = destinationElement.getJavaProject();
+ if (isMove()) {
+ IJavaProject sourceProject = sourceElement.getJavaProject();
+ getDeltaFor(sourceProject).movedFrom(sourceElement, destinationElement);
+ getDeltaFor(destProject).movedTo(destinationElement, sourceElement);
+ } else {
+ getDeltaFor(destProject).added(destinationElement);
+ }
+ }
+
+ /**
+ * Copies/moves a compilation unit with the name <code>newCUName</code>
+ * to the destination package.<br>
+ * The package statement in the compilation unit is updated if necessary.
+ * The main type of the compilation unit is renamed if necessary.
+ *
+ * @exception JavaModelException if the operation is unable to
+ * complete
+ */
+ private void processCompilationUnitResource(
+ ICompilationUnit source,
+ IPackageFragment dest)
+ throws JavaModelException {
+ String newCUName = getNewNameFor(source);
+ String destName = (newCUName != null) ? newCUName : source.getElementName();
+ String newContent = updatedContent(source, dest, newCUName);
+
+ // copy resource
+ IFile sourceResource =
+ (IFile) (source.isWorkingCopy() ? source.getOriginalElement() : source)
+ .getCorrespondingResource();
+ IContainer destFolder = (IContainer) dest.getCorrespondingResource();
+ // can be an IFolder or an IProject
+ IFile destFile = destFolder.getFile(new Path(destName));
+ try {
+ if (destFile.exists()) {
+ if (fForce) {
+ // we can remove it
+ deleteResource(destFile, false);
+ } else {
+ // abort
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION));
+ }
+ }
+ if (this.isMove()) {
+ sourceResource.move(
+ destFile.getFullPath(),
+ fForce,
+ true,
+ getSubProgressMonitor(1));
+ } else {
+ sourceResource.copy(destFile.getFullPath(), fForce, getSubProgressMonitor(1));
+ }
+ } catch (JavaModelException e) {
+ throw e;
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ }
+
+ // update new resource content
+ try {
+ destFile.setContents(
+ new ByteArrayInputStream(newContent.getBytes()),
+ fForce,
+ true,
+ getSubProgressMonitor(1));
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ }
+
+ // register the correct change deltas
+ ICompilationUnit destCU = dest.getCompilationUnit(destName);
+ prepareDeltas(source, destCU);
+ if (newCUName != null) {
+ //the main type has been renamed
+ String oldName = source.getElementName();
+ oldName = oldName.substring(0, oldName.length() - 5);
+ String newName = newCUName;
+ newName = newName.substring(0, newName.length() - 5);
+ prepareDeltas(source.getType(oldName), destCU.getType(newName));
+ }
+ }
+
+ /**
+ * Process all of the changed deltas generated by this operation.
+ */
+ protected void processDeltas() {
+ Enumeration deltas = fDeltasPerProject.elements();
+ while (deltas.hasMoreElements()) {
+ addDelta((IJavaElementDelta) deltas.nextElement());
+ }
+ }
+
+ /**
+ * @see MultiOperation
+ * This method delegates to <code>processCompilationUnitResource</code> or
+ * <code>processPackageFragmentResource</code>, depending on the type of
+ * <code>element</code>.
+ */
+ protected void processElement(IJavaElement element) throws JavaModelException {
+ IJavaElement dest = getDestinationParent(element);
+ switch (element.getElementType()) {
+ case IJavaElement.COMPILATION_UNIT :
+ processCompilationUnitResource(
+ (ICompilationUnit) element,
+ (IPackageFragment) dest);
+ fCreatedElements.addElement(
+ ((IPackageFragment) dest).getCompilationUnit(element.getElementName()));
+ break;
+ case IJavaElement.PACKAGE_FRAGMENT :
+ processPackageFragmentResource(
+ (IPackageFragment) element,
+ (IPackageFragmentRoot) dest,
+ getNewNameFor(element));
+ break;
+ default :
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element));
+ }
+ }
+
+ /**
+ * @see MultiOperation
+ * Overridden to allow special processing of <code>JavaElementDelta</code>s
+ * and <code>fResultElements</code>.
+ */
+ protected void processElements() throws JavaModelException {
+ fCreatedElements = new Vector(fElementsToProcess.length);
+ try {
+ super.processElements();
+ } catch (JavaModelException jme) {
+ throw jme;
+ } finally {
+ fResultElements = new IJavaElement[fCreatedElements.size()];
+ fCreatedElements.copyInto(fResultElements);
+ processDeltas();
+ }
+ }
+
+ /**
+ * Copies/moves a package fragment with the name <code>newName</code>
+ * to the destination package.<br>
+ *
+ * @exception JavaModelException if the operation is unable to
+ * complete
+ */
+ private void processPackageFragmentResource(
+ IPackageFragment source,
+ IPackageFragmentRoot root,
+ String newName)
+ throws JavaModelException {
+ try {
+ // grab the members before applying the rename (covers nested cases: p --> p.p.p
+ IResource[] members = ((IContainer) source.getUnderlyingResource()).members();
+
+ String newFragName = (newName == null) ? source.getElementName() : newName;
+ createNeededPackageFragments(root, newFragName);
+ IPackageFragment newFrag = root.getPackageFragment(newFragName);
+
+ // process the leaf resources
+ IResource[] resources = collectResourcesOfInterest(source);
+ if (resources.length > 0) {
+ IPath destPath = newFrag.getUnderlyingResource().getFullPath();
+ if (isRename()) {
+ if (!destPath.equals(source.getUnderlyingResource().getFullPath())) {
+ moveResources(resources, destPath);
+ }
+ } else
+ if (isMove()) {
+ // we need to delete this resource if this operation wants to override existing resources
+ for (int i = 0, max = resources.length; i < max; i++) {
+ IResource destinationResource =
+ getWorkspace().getRoot().findMember(destPath.append(resources[i].getName()));
+ if (destinationResource != null) {
+ if (fForce) {
+ deleteResource(destinationResource, false);
+ } else {
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION));
+ }
+ }
+ }
+ moveResources(resources, destPath);
+ } else {
+ // we need to delete this resource if this operation wants to override existing resources
+ for (int i = 0, max = resources.length; i < max; i++) {
+ IResource destinationResource =
+ getWorkspace().getRoot().findMember(destPath.append(resources[i].getName()));
+ if (destinationResource != null) {
+ if (fForce) {
+ // we need to delete this resource if this operation wants to override existing resources
+ deleteResource(destinationResource, false);
+ } else {
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION));
+ }
+ }
+ }
+ copyResources(resources, destPath);
+ }
+ if (!newFrag.getElementName().equals(source.getElementName())) {
+ // if package has been renamed, update the compilation units
+ for (int i = 0; i < resources.length; i++) {
+ if (resources[i].getName().endsWith(".java")) {
+ // we only consider potential compilation units
+ ICompilationUnit cu = newFrag.getCompilationUnit(resources[i].getName());
+ IDOMCompilationUnit domCU =
+ fFactory.createCompilationUnit(cu.getSource(), cu.getElementName());
+ if (domCU != null) {
+ updatePackageStatement(domCU, newFragName);
+ ((Buffer) cu.getBuffer()).setContents(domCU.getContents(), true);
+ cu.save(null, false);
+ }
+ }
+ }
+ }
+ }
+
+ // discard empty old package (if still empty after the rename)
+ if (isMove()
+ && ((IContainer) source.getUnderlyingResource()).members().length == 0) {
+ deleteEmptyPackageFragment(source, false);
+ }
+
+ //register the correct change deltas
+ prepareDeltas(source, newFrag);
+ } catch (DOMException dom) {
+ throw new JavaModelException(dom, IJavaModelStatusConstants.DOM_EXCEPTION);
+ } catch (JavaModelException e) {
+ throw e;
+ } catch (CoreException ce) {
+ throw new JavaModelException(ce);
+ }
+ }
+
+ /**
+ * Updates the content of <code>cu</code>, modifying the type name and/or package
+ * declaration as necessary.
+ *
+ * @return the new source
+ */
+ private String updatedContent(
+ ICompilationUnit cu,
+ IPackageFragment dest,
+ String newName)
+ throws JavaModelException {
+ String currPackageName = cu.getParent().getElementName();
+ String destPackageName = dest.getElementName();
+ if (currPackageName.equals(destPackageName) && newName == null) {
+ return cu.getSource();
+ } else {
+ String typeName = cu.getElementName();
+ typeName = typeName.substring(0, typeName.length() - 5);
+ IDOMCompilationUnit cuDOM = null;
+ cuDOM =
+ fFactory.createCompilationUnit(cu.getBuffer().getCharacters(), typeName);
+ updateTypeName(cu, cuDOM, cu.getElementName(), newName);
+ updatePackageStatement(cuDOM, destPackageName);
+ return cuDOM.getContents();
+ }
+ }
+
+ /**
+ * Makes sure that <code>cu</code> declares to be in the <code>pkgName</code> package.
+ */
+ private void updatePackageStatement(IDOMCompilationUnit domCU, String pkgName)
+ throws JavaModelException {
+ boolean defaultPackage = pkgName.equals(IPackageFragment.DEFAULT_PACKAGE_NAME);
+ boolean seenPackageNode = false;
+ Enumeration enum = domCU.getChildren();
+ while (enum.hasMoreElements()) {
+ IDOMNode node = (IDOMNode) enum.nextElement();
+ if (node.getNodeType() == IDOMNode.PACKAGE) {
+ if (!defaultPackage) {
+ node.setName(pkgName);
+ } else {
+ node.remove();
+ }
+ seenPackageNode = true;
+ break;
+ }
+ }
+ if (!seenPackageNode && !defaultPackage) {
+ //the cu was in a default package...no package declaration
+ //create the new package declaration as the first child of the cu
+ IDOMPackage pkg =
+ fFactory.createPackage(
+ "package " + pkgName + ";" + JavaModelManager.LINE_SEPARATOR);
+ domCU.getFirstChild().insertSibling(pkg);
+ }
+ }
+
+ /**
+ * Renames the main type in <code>cu</code>.
+ */
+ private void updateTypeName(
+ ICompilationUnit cu,
+ IDOMCompilationUnit domCU,
+ String oldName,
+ String newName)
+ throws JavaModelException {
+ if (newName != null) {
+ if (fRenamedCompilationUnits == null) {
+ fRenamedCompilationUnits = new Vector(1);
+ }
+ fRenamedCompilationUnits.addElement(cu);
+ String oldTypeName = oldName.substring(0, oldName.length() - 5);
+ String newTypeName = newName.substring(0, newName.length() - 5);
+ // update main type name
+ IType[] types = cu.getTypes();
+ for (int i = 0, max = types.length; i < max; i++) {
+ IType currentType = types[i];
+ if (currentType.getElementName().equals(oldTypeName)) {
+ IDOMNode typeNode = ((JavaElement) currentType).findNode(domCU);
+ if (typeNode != null) {
+ typeNode.setName(newTypeName);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Possible failures:
+ * <ul>
+ * <li>NO_ELEMENTS_TO_PROCESS - no elements supplied to the operation
+ * <li>INDEX_OUT_OF_BOUNDS - the number of renamings supplied to the operation
+ * does not match the number of elements that were supplied.
+ * </ul>
+ */
+ protected IJavaModelStatus verify() {
+ IJavaModelStatus status = super.verify();
+ if (!status.isOK()) {
+ return status;
+ }
+
+ if (fRenamingsList != null
+ && fRenamingsList.length != fElementsToProcess.length) {
+ return new JavaModelStatus(IJavaModelStatusConstants.INDEX_OUT_OF_BOUNDS);
+ }
+ return JavaModelStatus.VERIFIED_OK;
+ }
+
+ /**
+ * @see MultiOperation
+ */
+ protected void verify(IJavaElement element) throws JavaModelException {
+ if (element == null || !element.exists())
+ error(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, element);
+
+ if (element.isReadOnly() && (isRename() || isMove()))
+ error(IJavaModelStatusConstants.READ_ONLY, element);
+
+ int elementType = element.getElementType();
+
+ if (elementType == IJavaElement.COMPILATION_UNIT) {
+ if (isMove() && ((ICompilationUnit) element).isWorkingCopy())
+ error(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element);
+ } else
+ if (elementType != IJavaElement.PACKAGE_FRAGMENT) {
+ error(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element);
+ }
+
+ JavaElement dest = (JavaElement) getDestinationParent(element);
+ verifyDestination(element, dest);
+ if (fRenamings != null) {
+ verifyRenaming(element);
+ }
+
+ IContainer folder = (IContainer) dest.getUnderlyingResource();
+ String name = element.getElementName();
+ String rename = getNewNameFor(element);
+ if (rename != null) {
+ name = rename;
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateCompilationUnitOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateCompilationUnitOperation.java
new file mode 100644
index 0000000000..25e5fa19a8
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateCompilationUnitOperation.java
@@ -0,0 +1,109 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.jdom.DOMFactory;
+import org.eclipse.jdt.core.jdom.IDOMCompilationUnit;
+
+import java.io.*;
+
+/**
+ * <p>This operation creates a compilation unit (CU).
+ * The operation will fail if the CU already exists.
+ *
+ * <p>Note: It is possible to create a CU automatically when creating a
+ * class or interface. Thus, the preferred method of creating a CU is
+ * to perform a create type operation rather than
+ * first creating a CU and secondly creating a type inside the CU.
+ *
+ * <p>Required Attributes:<ul>
+ * <li>The package fragment in which to create the compilation unit.
+ * <li>The name of the compilation unit.
+ * Do not include the <code>".java"</code> suffix (ex. <code>"Object"</code> -
+ * the <code>".java"</code> will be added for the name of the compilation unit.)
+ * <li>
+ * </ul>
+ */
+public class CreateCompilationUnitOperation extends JavaModelOperation {
+
+ /**
+ * The name of the compilation unit being created.
+ */
+ protected String fName;
+ /**
+ * The source code to use when creating the element.
+ */
+ protected String fSource = null;
+ /**
+ * When executed, this operation will create a compilation unit with the given name.
+ * The name should have the ".java" suffix.
+ */
+ public CreateCompilationUnitOperation(
+ IPackageFragment parentElement,
+ String name,
+ String source,
+ boolean force) {
+ super(null, new IJavaElement[] { parentElement }, force);
+ fName = name;
+ fSource = source;
+ }
+
+ /**
+ * Creates a compilation unit.
+ *
+ * @exception JavaModelException if unable to create the compilation unit.
+ */
+ protected void executeOperation() throws JavaModelException {
+ beginTask("Creating a compilation unit...", 2);
+ JavaElementDelta delta = newJavaElementDelta();
+ ICompilationUnit unit = getCompilationUnit();
+ IPackageFragment pkg = (IPackageFragment) getParentElement();
+ IContainer folder = (IContainer) pkg.getUnderlyingResource();
+ InputStream stream =
+ new ByteArrayInputStream(BufferManager.stringToBytes(fSource));
+ worked(1);
+ createFile(folder, unit.getElementName(), stream, fForce);
+ worked(1);
+ fResultElements = new IJavaElement[] { getCompilationUnit()};
+ for (int i = 0; i < fResultElements.length; i++) {
+ delta.added(fResultElements[i]);
+ }
+ addDelta(delta);
+ done();
+ }
+
+ /**
+ * @see CreateElementInCUOperation#getCompilationUnit()
+ */
+ protected ICompilationUnit getCompilationUnit() {
+ return ((IPackageFragment) getParentElement()).getCompilationUnit(fName);
+ }
+
+ /**
+ * Possible failures: <ul>
+ * <li>NO_ELEMENTS_TO_PROCESS - the package fragment supplied to the operation is
+ * <code>null</code>.
+ * <li>INVALID_NAME - the compilation unit name provided to the operation
+ * is <code>null</code> or has an invalid syntax
+ * <li>INVALID_CONTENTS - the source specified for the compiliation unit is null
+ * </ul>
+ */
+ public IJavaModelStatus verify() {
+ if (getParentElement() == null) {
+ return new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
+ }
+ if (!JavaConventions.validateCompilationUnitName(fName).isOK()) {
+ return new JavaModelStatus(IJavaModelStatusConstants.INVALID_NAME, fName);
+ }
+ if (fSource == null) {
+ return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CONTENTS);
+ }
+ return JavaModelStatus.VERIFIED_OK;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateElementInCUOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateElementInCUOperation.java
new file mode 100644
index 0000000000..5df9ecbde5
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateElementInCUOperation.java
@@ -0,0 +1,315 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.jdom.*;
+import org.eclipse.jdt.internal.core.jdom.DOMNode;
+
+/**
+ * <p>This abstract class implements behavior common to <code>CreateElementInCUOperations</code>.
+ * To create a compilation unit, or an element contained in a compilation unit, the
+ * source code for the entire compilation unit is updated and saved.
+ *
+ * <p>The element being created can be positioned relative to an existing
+ * element in the compilation unit via the methods <code>#createAfter</code>
+ * and <code>#createBefore</code>. By default, the new element is positioned
+ * as the last child of its parent element.
+ *
+ */
+public abstract class CreateElementInCUOperation extends JavaModelOperation {
+ /**
+ * The compilation unit DOM used for this operation
+ */
+ protected IDOMCompilationUnit fCUDOM;
+ /**
+ * A constant meaning to position the new element
+ * as the last child of its parent element.
+ */
+ protected static final int INSERT_LAST = 1;
+ /**
+ * A constant meaning to position the new element
+ * after the element defined by <code>fAnchorElement</code>.
+ */
+ protected static final int INSERT_AFTER = 2;
+
+ /**
+ * A constant meaning to position the new element
+ * before the element defined by <code>fAnchorElement</code>.
+ */
+ protected static final int INSERT_BEFORE = 3;
+ /**
+ * One of the position constants, describing where
+ * to position the newly created element.
+ */
+ protected int fInsertionPolicy = INSERT_LAST;
+ /**
+ * The element that the newly created element is
+ * positioned relative to, as described by
+ * <code>fInsertPosition</code>, or <code>null</code>
+ * if the newly created element will be positioned
+ * last.
+ */
+ protected IJavaElement fAnchorElement = null;
+ /**
+ * A flag indicating whether creation of a new element occurred.
+ * A request for creating a duplicate element would request in this
+ * flag being set to <code>false</code>. Ensures that no deltas are generated
+ * when creation does not occur.
+ */
+ protected boolean fCreationOccurred = true;
+ /**
+ * The element that is being created.
+ */
+ protected DOMNode fCreatedElement;
+ /**
+ * The position of the element that is being created.
+ */
+ protected int fInsertionPosition = -1;
+ /**
+ * The number of characters the new element replaces,
+ * or 0 if the new element is inserted,
+ * or -1 if the new element is append to the end of the CU.
+ */
+ protected int fReplacementLength = -1;
+ /**
+ * Constructs an operation that creates a Java Language Element with
+ * the specified parent, contained within a compilation unit.
+ */
+ public CreateElementInCUOperation(IJavaElement parentElement) {
+ super(null, new IJavaElement[] { parentElement });
+ initializeDefaultPosition();
+ }
+
+ /**
+ * Only allow cancelling if this operation is not nested.
+ */
+ protected void checkCanceled() {
+ if (!fNested) {
+ super.checkCanceled();
+ }
+ }
+
+ /**
+ * Instructs this operation to position the new element after
+ * the given sibling, or to add the new element as the last child
+ * of its parent if <code>null</code>.
+ */
+ public void createAfter(IJavaElement sibling) {
+ setRelativePosition(sibling, INSERT_AFTER);
+ }
+
+ /**
+ * Instructs this operation to position the new element before
+ * the given sibling, or to add the new element as the last child
+ * of its parent if <code>null</code>.
+ */
+ public void createBefore(IJavaElement sibling) {
+ setRelativePosition(sibling, INSERT_BEFORE);
+ }
+
+ /**
+ * Execute the operation - generate new source for the compilation unit
+ * and save the results.
+ *
+ * @exception JavaModelException if the operation is unable to complete
+ */
+ protected void executeOperation() throws JavaModelException {
+ beginTask(getMainTaskName(), getMainAmountOfWork());
+ JavaElementDelta delta = newJavaElementDelta();
+ ICompilationUnit unit = getCompilationUnit();
+ generateNewCompilationUnitDOM(unit);
+ if (fCreationOccurred) {
+ //a change has really occurred
+ Buffer buffer = (Buffer) unit.getBuffer();
+ switch (fReplacementLength) {
+ case -1 :
+ // element is append at the end
+ buffer.append(fCreatedElement.getCharacters(), true);
+ break;
+ case 0 :
+ // element is inserted
+ buffer.replace(fInsertionPosition, 0, fCreatedElement.getCharacters(), true);
+ break;
+ default :
+ // element is replacing the previous one
+ buffer.replace(
+ fInsertionPosition,
+ fReplacementLength,
+ fCreatedElement.getCharacters(),
+ true);
+ }
+ unit.save(null, false);
+ worked(1);
+ fResultElements = generateResultHandles();
+ for (int i = 0; i < fResultElements.length; i++) {
+ delta.added(fResultElements[i]);
+ }
+ addDelta(delta);
+ }
+ done();
+ }
+
+ /**
+ * Returns a JDOM document fragment for the element being created.
+ */
+ protected abstract IDOMNode generateElementDOM() throws JavaModelException;
+ /**
+ * Returns the DOM with the new source to use for the given compilation unit.
+ */
+ protected void generateNewCompilationUnitDOM(ICompilationUnit cu)
+ throws JavaModelException {
+ char[] prevSource = cu.getBuffer().getCharacters();
+
+ // create a JDOM for the compilation unit
+ fCUDOM =
+ (new DOMFactory()).createCompilationUnit(prevSource, cu.getElementName());
+ IDOMNode child = generateElementDOM();
+ if (child != null) {
+ insertDOMNode(fCUDOM, child);
+ }
+ worked(1);
+ }
+
+ /**
+ * Creates and returns the handle for the element this operation created.
+ */
+ protected abstract IJavaElement generateResultHandle();
+ /**
+ * Creates and returns the handles for the elements this operation created.
+ */
+ protected IJavaElement[] generateResultHandles() throws JavaModelException {
+ return new IJavaElement[] { generateResultHandle()};
+ }
+
+ /**
+ * Returns the compilation unit in which the new element is being created.
+ */
+ protected ICompilationUnit getCompilationUnit() {
+ return getCompilationUnitFor(getParentElement());
+ }
+
+ /**
+ * Returns the amount of work for the main task of this operation for
+ * progress reporting.
+ * @see executeOperation()
+ */
+ protected int getMainAmountOfWork() {
+ return 2;
+ }
+
+ /**
+ * Returns the name of the main task of this operation for
+ * progress reporting.
+ * @see executeOperation()
+ */
+ protected abstract String getMainTaskName();
+ /**
+ * Returns the elements created by this operation.
+ */
+ public IJavaElement[] getResultElements() {
+ return fResultElements;
+ }
+
+ /**
+ * Sets the default position in which to create the new type
+ * member. By default, the new element is positioned as the
+ * last child of the parent element in which it is created.
+ * Operations that require a different default position must
+ * override this method.
+ */
+ protected void initializeDefaultPosition() {
+
+ }
+
+ /**
+ * Inserts the given child into the given JDOM,
+ * based on the position settings of this operation.
+ *
+ * @see createAfter(IJavaElement)
+ * @see createBefore(IJavaElement);
+ */
+ protected void insertDOMNode(IDOMNode parent, IDOMNode child) {
+ if (fInsertionPolicy != INSERT_LAST) {
+ IDOMNode sibling = ((JavaElement) fAnchorElement).findNode(fCUDOM);
+ if (sibling != null && fInsertionPolicy == INSERT_AFTER) {
+ sibling = sibling.getNextNode();
+ }
+ if (sibling != null) {
+ sibling.insertSibling(child);
+ fCreatedElement = (DOMNode) child;
+ fInsertionPosition = ((DOMNode) sibling).getStartPosition();
+ fReplacementLength = 0;
+ return;
+ }
+ }
+ //add as the last element of the parent
+ parent.addChild(child);
+ fCreatedElement = (DOMNode) child;
+ DOMNode lastChild = (DOMNode) fCreatedElement.getPreviousNode();
+ fInsertionPosition =
+ lastChild == null
+ ? ((DOMNode) parent).getInsertionPosition()
+ : lastChild.getEndPosition() + 1;
+ fReplacementLength = parent.getParent() == null ? -1 : 0;
+ }
+
+ /**
+ * Sets the name of the <code>DOMNode</code> that will be used to
+ * create this new element.
+ * Used by the <code>CopyElementsOperation</code> for renaming.
+ * Only used for <code>CreateTypeMemberOperation</code>
+ */
+ protected void setAlteredName(String newName) {
+ }
+
+ /**
+ * Instructs this operation to position the new element relative
+ * to the given sibling, or to add the new element as the last child
+ * of its parent if <code>null</code>. The <code>position</code>
+ * must be one of the position constants.
+ */
+ protected void setRelativePosition(IJavaElement sibling, int policy)
+ throws IllegalArgumentException {
+ if (sibling == null) {
+ fAnchorElement = null;
+ fInsertionPolicy = INSERT_LAST;
+ } else {
+ fAnchorElement = sibling;
+ fInsertionPolicy = policy;
+ }
+ }
+
+ /**
+ * Possible failures: <ul>
+ * <li>NO_ELEMENTS_TO_PROCESS - the compilation unit supplied to the operation is
+ * <code>null</code>.
+ * <li>INVALID_NAME - no name, a name was null or not a valid
+ * import declaration name.
+ * <li>INVALID_SIBLING - the sibling provided for positioning is not valid.
+ * </ul>
+ * @see IJavaModelStatus
+ * @see JavaNamingConventions
+ */
+ public IJavaModelStatus verify() {
+ if (getParentElement() == null) {
+ return new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
+ }
+ if (fAnchorElement != null) {
+ IJavaElement domPresentParent = fAnchorElement.getParent();
+ if (domPresentParent.getElementType() == IJavaElement.IMPORT_CONTAINER) {
+ domPresentParent = domPresentParent.getParent();
+ }
+ if (!domPresentParent.equals(getParentElement())) {
+ return new JavaModelStatus(
+ IJavaModelStatusConstants.INVALID_SIBLING,
+ fAnchorElement);
+ }
+ }
+ return JavaModelStatus.VERIFIED_OK;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateFieldOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateFieldOperation.java
new file mode 100644
index 0000000000..a8699361b8
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateFieldOperation.java
@@ -0,0 +1,99 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.jdom.*;
+
+/**
+ * <p>This operation creates a field declaration in a type.
+ *
+ * <p>Required Attributes:<ul>
+ * <li>Containing Type
+ * <li>The source code for the declaration. No verification of the source is
+ * performed.
+ * </ul>
+ */
+public class CreateFieldOperation extends CreateTypeMemberOperation {
+ /**
+ * When executed, this operation will create a field with the given name
+ * in the given type with the specified source.
+ *
+ * <p>By default the new field is positioned after the last existing field
+ * declaration, or as the first member in the type if there are no
+ * field declarations.
+ */
+ public CreateFieldOperation(
+ IType parentElement,
+ String source,
+ boolean force) {
+ super(parentElement, source, force);
+ }
+
+ /**
+ * @see CreateTypeMemberOperation#generateElementDOM
+ */
+ protected IDOMNode generateElementDOM() throws JavaModelException {
+ if (fDOMNode == null) {
+ fDOMNode = (new DOMFactory()).createField(fSource);
+ if (fDOMNode == null) {
+ fDOMNode = generateSyntaxIncorrectDOM();
+ }
+ if (fAlteredName != null && fDOMNode != null) {
+ fDOMNode.setName(fAlteredName);
+ }
+ }
+ return fDOMNode;
+ }
+
+ /**
+ * @see CreateElementInCUOperation#generateResultHandle
+ */
+ protected IJavaElement generateResultHandle() {
+ return getType().getField(fDOMNode.getName());
+ }
+
+ /**
+ * @see CreateElementInCUOperation#getMainTaskName
+ */
+ public String getMainTaskName() {
+ return "Creating a field...";
+ }
+
+ /**
+ * By default the new field is positioned after the last existing field
+ * declaration, or as the first member in the type if there are no
+ * field declarations.
+ */
+ protected void initializeDefaultPosition() {
+ IType parentElement = getType();
+ try {
+ IJavaElement[] elements = parentElement.getFields();
+ if (elements != null && elements.length > 0) {
+ createAfter(elements[elements.length - 1]);
+ } else {
+ elements = parentElement.getChildren();
+ if (elements != null && elements.length > 0) {
+ createBefore(elements[0]);
+ }
+ }
+ } catch (JavaModelException e) {
+ }
+ }
+
+ /**
+ * @see CreateTypeMemberOperation#verifyNameCollision
+ */
+ protected IJavaModelStatus verifyNameCollision() {
+ IType type = getType();
+ if (type.getField(fDOMNode.getName()).exists()) {
+ return new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION);
+ }
+ return JavaModelStatus.VERIFIED_OK;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateImportOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateImportOperation.java
new file mode 100644
index 0000000000..3387473c98
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateImportOperation.java
@@ -0,0 +1,135 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.jdom.IDOMCompilationUnit;
+import org.eclipse.jdt.core.jdom.DOMFactory;
+import org.eclipse.jdt.core.jdom.IDOMImport;
+import org.eclipse.jdt.core.jdom.IDOMNode;
+
+import java.util.Vector;
+
+/**
+ * <p>This operation adds an import declaration to an existing compilation unit.
+ * If the compilation unit already includes the specified import declaration,
+ * the import is not generated (it does not generate duplicates).
+ * Note that it is valid to specify both a single-type import and an on-demand import
+ * for the same package, for example <code>"java.io.File"</code> and
+ * <code>"java.io.*"</code>, in which case both are preserved since the semantics
+ * of this are not the same as just importing <code>"java.io.*"</code>.
+ * Importing <code>"java.lang.*"</code>, or the package in which the compilation unit
+ * is defined, are not treated as special cases. If they are specified, they are
+ * included in the result.
+ *
+ * <p>Required Attributes:<ul>
+ * <li>Compilation unit
+ * <li>Import name - the name of the import to add to the
+ * compilation unit. For example: <code>"java.io.File"</code> or <code>"java.awt.*"</code>
+ * </ul>
+ */
+public class CreateImportOperation extends CreateElementInCUOperation {
+
+ /**
+ * The name of the import to be created.
+ */
+ protected String fImportName;
+ /**
+ * When executed, this operation will add an import to the given compilation unit.
+ */
+ public CreateImportOperation(
+ String importName,
+ ICompilationUnit parentElement) {
+ super(parentElement);
+ fImportName = importName;
+ }
+
+ /**
+ * @see CreateTypeMemberOperation#generateElementDOM
+ */
+ protected IDOMNode generateElementDOM() throws JavaModelException {
+ if (fCUDOM.getChild(fImportName) == null) {
+ DOMFactory factory = new DOMFactory();
+ //not a duplicate
+ IDOMImport imp = factory.createImport();
+ imp.setName(fImportName);
+ return imp;
+ }
+
+ //no new import was generated
+ fCreationOccurred = false;
+ //all the work has already been done
+ return null;
+ }
+
+ /**
+ * @see CreateElementInCUOperation#generateResultHandle
+ */
+ protected IJavaElement generateResultHandle() {
+ return getCompilationUnit().getImport(fImportName);
+ }
+
+ /**
+ * @see CreateElementInCUOperation#getMainTaskName
+ */
+ public String getMainTaskName() {
+ return "Creating imports...";
+ }
+
+ /**
+ * Sets the correct position for the new import:<ul>
+ * <li> after the last import
+ * <li> if no imports, before the first type
+ * <li> if no type, after the package statement
+ * <li> and if no package statement - first thing in the CU
+ */
+ protected void initializeDefaultPosition() {
+ try {
+ ICompilationUnit cu = getCompilationUnit();
+ IImportDeclaration[] imports = cu.getImports();
+ if (imports.length > 0) {
+ createAfter(imports[imports.length - 1]);
+ return;
+ }
+ IType[] types = cu.getTypes();
+ if (types.length > 0) {
+ createBefore(types[0]);
+ return;
+ }
+ IJavaElement[] children = cu.getChildren();
+ //look for the package declaration
+ for (int i = 0; i < children.length; i++) {
+ if (children[i].getElementType() == IJavaElement.PACKAGE_DECLARATION) {
+ createAfter(children[i]);
+ return;
+ }
+ }
+ } catch (JavaModelException npe) {
+ }
+ }
+
+ /**
+ * Possible failures: <ul>
+ * <li>NO_ELEMENTS_TO_PROCESS - the compilation unit supplied to the operation is
+ * <code>null</code>.
+ * <li>INVALID_NAME - not a valid import declaration name.
+ * </ul>
+ * @see IJavaModelStatus
+ * @see JavaNamingConventions
+ */
+ public IJavaModelStatus verify() {
+ IJavaModelStatus status = super.verify();
+ if (!status.isOK()) {
+ return status;
+ }
+ if (!JavaConventions.validateImportDeclaration(fImportName).isOK()) {
+ return new JavaModelStatus(IJavaModelStatusConstants.INVALID_NAME, fImportName);
+ }
+ return JavaModelStatus.VERIFIED_OK;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateInitializerOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateInitializerOperation.java
new file mode 100644
index 0000000000..4a2a03eb0a
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateInitializerOperation.java
@@ -0,0 +1,110 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.jdom.*;
+import org.eclipse.jdt.core.*;
+
+/**
+ * <p>This operation creates a initializer in a type.
+ *
+ * <p>Required Attributes:<ul>
+ * <li>Containing Type
+ * <li>The source code for the initializer. No verification of the source is
+ * performed.
+ * </ul>
+ */
+public class CreateInitializerOperation extends CreateTypeMemberOperation {
+ /**
+ * The current number of initializers in the parent type.
+ * Used to retrieve the handle of the newly created initializer.
+ */
+ protected int fNumberOfInitializers = 1;
+ /**
+ * When executed, this operation will create an initializer with the given name
+ * in the given type with the specified source.
+ *
+ * <p>By default the new initializer is positioned after the last existing initializer
+ * declaration, or as the first member in the type if there are no
+ * initializers.
+ */
+ public CreateInitializerOperation(IType parentElement, String source) {
+ super(parentElement, source, false);
+ }
+
+ /**
+ * @see CreateTypeMemberOperation#generateElementDOM
+ */
+ protected IDOMNode generateElementDOM() throws JavaModelException {
+ IDOMInitializer domInitializer = (new DOMFactory()).createInitializer(fSource);
+ if (domInitializer == null) {
+ domInitializer = (IDOMInitializer) generateSyntaxIncorrectDOM();
+ }
+ return domInitializer;
+ }
+
+ /**
+ * @see CreateElementInCUOperation#generateResultHandle
+ */
+ protected IJavaElement generateResultHandle() {
+ try {
+ //update the children to be current
+ getType().getCompilationUnit().close();
+ if (fAnchorElement == null) {
+ return getType().getInitializer(fNumberOfInitializers);
+ } else {
+ IJavaElement[] children = getType().getChildren();
+ int count = 0;
+ for (int i = 0; i < children.length; i++) {
+ IJavaElement child = children[i];
+ if (child.equals(fAnchorElement)) {
+ if (child.getElementType() == IJavaElement.INITIALIZER
+ && fInsertionPolicy == CreateElementInCUOperation.INSERT_AFTER) {
+ count++;
+ }
+ return getType().getInitializer(count);
+ } else
+ if (child.getElementType() == IJavaElement.INITIALIZER) {
+ count++;
+ }
+ }
+ }
+ } catch (JavaModelException jme) {
+ }
+ return null;
+ }
+
+ /**
+ * @see CreateElementInCUOperation#getMainTaskName
+ */
+ public String getMainTaskName() {
+ return "Creating an initializer...";
+ }
+
+ /**
+ * By default the new initializer is positioned after the last existing initializer
+ * declaration, or as the first member in the type if there are no
+ * initializers.
+ */
+ protected void initializeDefaultPosition() {
+ IType parentElement = getType();
+ try {
+ IJavaElement[] elements = parentElement.getInitializers();
+ if (elements != null && elements.length > 0) {
+ fNumberOfInitializers = elements.length;
+ createAfter(elements[elements.length - 1]);
+ } else {
+ elements = parentElement.getChildren();
+ if (elements != null && elements.length > 0) {
+ createBefore(elements[0]);
+ }
+ }
+ } catch (JavaModelException e) {
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateMethodOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateMethodOperation.java
new file mode 100644
index 0000000000..38b1512cd6
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateMethodOperation.java
@@ -0,0 +1,111 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.jdom.*;
+
+/**
+ * <p>This operation creates an instance method.
+ *
+ * <p>Required Attributes:<ul>
+ * <li>Containing type
+ * <li>The source code for the method. No verification of the source is
+ * performed.
+ * </ul>
+ */
+public class CreateMethodOperation extends CreateTypeMemberOperation {
+ protected String[] fParameterTypes;
+ /**
+ * When executed, this operation will create a method
+ * in the given type with the specified source.
+ */
+ public CreateMethodOperation(
+ IType parentElement,
+ String source,
+ boolean force) {
+ super(parentElement, source, force);
+ }
+
+ /**
+ * Returns the type signatures of the parameter types of the
+ * current <code>DOMMethod</code>
+ */
+ protected String[] convertDOMMethodTypesToSignatures() {
+ if (fParameterTypes == null) {
+ if (fDOMNode != null) {
+ String[] domParameterTypes = ((IDOMMethod) fDOMNode).getParameterTypes();
+ if (domParameterTypes != null) {
+ fParameterTypes = new String[domParameterTypes.length];
+ // convert the DOM types to signatures
+ int i;
+ for (i = 0; i < fParameterTypes.length; i++) {
+ fParameterTypes[i] =
+ Signature.createTypeSignature(domParameterTypes[i].toCharArray(), false);
+ }
+ }
+ }
+ }
+ return fParameterTypes;
+ }
+
+ /**
+ * @see CreateTypeMemberOperation#generateElementDOM
+ */
+ protected IDOMNode generateElementDOM() throws JavaModelException {
+ if (fDOMNode == null) {
+ fDOMNode = (new DOMFactory()).createMethod(fSource);
+ if (fDOMNode == null) { //syntactically incorrect source
+ fDOMNode = generateSyntaxIncorrectDOM();
+ }
+ if (fAlteredName != null && fDOMNode != null) {
+ fDOMNode.setName(fAlteredName);
+ }
+ }
+ return fDOMNode;
+ }
+
+ /**
+ * @see CreateElementInCUOperation#generateResultHandle
+ */
+ protected IJavaElement generateResultHandle() {
+ String[] types = convertDOMMethodTypesToSignatures();
+ String name;
+ if (((IDOMMethod) fDOMNode).isConstructor()) {
+ name = fDOMNode.getParent().getName();
+ } else {
+ name = fDOMNode.getName();
+ }
+ return getType().getMethod(name, types);
+ }
+
+ /**
+ * @see CreateElementInCUOperation#getMainTaskName
+ */
+ public String getMainTaskName() {
+ return "Creating a method...";
+ }
+
+ /**
+ * @see CreateTypeMemberOperation#verifyNameCollision
+ */
+ protected IJavaModelStatus verifyNameCollision() {
+ if (fDOMNode != null) {
+ IType type = getType();
+ String name = fDOMNode.getName();
+ if (name == null) { //constructor
+ name = type.getElementName();
+ }
+ String[] types = convertDOMMethodTypesToSignatures();
+ if (type.getMethod(name, types).exists()) {
+ return new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION);
+ }
+ }
+ return JavaModelStatus.VERIFIED_OK;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreatePackageDeclarationOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreatePackageDeclarationOperation.java
new file mode 100644
index 0000000000..7238b8eadb
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreatePackageDeclarationOperation.java
@@ -0,0 +1,128 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.jdom.*;
+import org.eclipse.jdt.internal.core.jdom.DOMNode;
+
+/**
+ * <p>This operation adds/replaces a package declaration in an existing compilation unit.
+ * If the compilation unit already includes the specified package declaration,
+ * it is not generated (it does not generate duplicates).
+ *
+ * <p>Required Attributes:<ul>
+ * <li>Compilation unit element
+ * <li>Package name
+ * </ul>
+ */
+public class CreatePackageDeclarationOperation
+ extends CreateElementInCUOperation {
+ /**
+ * The name of the package declaration being created
+ */
+ protected String fName = null;
+ /**
+ * When executed, this operation will add a package declaration to the given compilation unit.
+ */
+ public CreatePackageDeclarationOperation(
+ String name,
+ ICompilationUnit parentElement) {
+ super(parentElement);
+ fName = name;
+ }
+
+ /**
+ * @see CreateTypeMemberOperation#generateElementDOM
+ */
+ protected IDOMNode generateElementDOM() throws JavaModelException {
+ IJavaElement[] children = getCompilationUnit().getChildren();
+ //look for an existing package declaration
+ for (int i = 0; i < children.length; i++) {
+ if (children[i].getElementType() == IJavaElement.PACKAGE_DECLARATION) {
+ IPackageDeclaration pck = (IPackageDeclaration) children[i];
+ IDOMPackage pack = (IDOMPackage) ((JavaElement) pck).findNode(fCUDOM);
+ if (!pack.getName().equals(fName)) {
+ // get the insertion position before setting the name, as this makes it a detailed node
+ // thus the start position is always 0
+ DOMNode node = (DOMNode) pack;
+ fInsertionPosition = node.getStartPosition();
+ fReplacementLength = node.getEndPosition() - fInsertionPosition + 1;
+ pack.setName(fName);
+ fCreatedElement = (org.eclipse.jdt.internal.core.jdom.DOMNode) pack;
+ } else {
+ //equivalent package declaration already exists
+ fCreationOccurred = false;
+ }
+
+ return null;
+ }
+ }
+ IDOMPackage pack = (new DOMFactory()).createPackage();
+ pack.setName(fName);
+ return pack;
+ }
+
+ /**
+ * Creates and returns the handle for the element this operation created.
+ */
+ protected IJavaElement generateResultHandle() {
+ return getCompilationUnit().getPackageDeclaration(fName);
+ }
+
+ /**
+ * @see CreateElementInCUOperation#getMainTaskName
+ */
+ public String getMainTaskName() {
+ return "Creating a package declaration...";
+ }
+
+ /**
+ * Sets the correct position for new package declaration:<ul>
+ * <li> before the first import
+ * <li> if no imports, before the first type
+ * <li> if no type - first thing in the CU
+ * <li>
+ */
+ protected void initializeDefaultPosition() {
+ try {
+ ICompilationUnit cu = getCompilationUnit();
+ IImportDeclaration[] imports = cu.getImports();
+ if (imports.length > 0) {
+ createBefore(imports[0]);
+ return;
+ }
+ IType[] types = cu.getTypes();
+ if (types.length > 0) {
+ createBefore(types[0]);
+ return;
+ }
+ } catch (JavaModelException npe) {
+ }
+ }
+
+ /**
+ * Possible failures: <ul>
+ * <li>NO_ELEMENTS_TO_PROCESS - no compilation unit was supplied to the operation
+ * <li>INVALID_NAME - a name supplied to the operation was not a valid
+ * package declaration name.
+ * </ul>
+ * @see IJavaModelStatus
+ * @see JavaNamingConventions
+ */
+ public IJavaModelStatus verify() {
+ IJavaModelStatus status = super.verify();
+ if (!status.isOK()) {
+ return status;
+ }
+ if (!JavaConventions.validatePackageName(fName).isOK()) {
+ return new JavaModelStatus(IJavaModelStatusConstants.INVALID_NAME, fName);
+ }
+ return JavaModelStatus.VERIFIED_OK;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreatePackageFragmentOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreatePackageFragmentOperation.java
new file mode 100644
index 0000000000..0c45b07607
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreatePackageFragmentOperation.java
@@ -0,0 +1,136 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.Path;
+
+import org.eclipse.jdt.core.*;
+
+import java.util.Vector;
+
+/**
+ * This operation creates a new package fragment under a given package fragment root.
+ * The following must be specified: <ul>
+ * <li>the package fragment root
+ * <li>the package name
+ * </ul>
+ * <p>Any needed folders/package fragments are created.
+ * If the package fragment already exists, this operation has no effect.
+ * The result elements include the <code>IPackageFragment</code> created and any side effect
+ * package fragments that were created.
+ *
+ * <p>NOTE: A default package fragment exists by default for a given root.
+ *
+ * <p>Possible exception conditions: <ul>
+ * <li>Package fragment root is read-only
+ * <li>Package fragment's name is taken by a simple (non-folder) resource
+ * </ul>
+ */
+public class CreatePackageFragmentOperation extends JavaModelOperation {
+ /**
+ * The fully qualified, dot-delimited, package name.
+ */
+ protected String fName;
+ /**
+ * When executed, this operation will create a package fragment with the given name
+ * under the given package fragment root. The dot-separated name is broken into
+ * segments. Intermediate folders are created as required for each segment.
+ * If the folders already exist, this operation has no effect.
+ */
+ public CreatePackageFragmentOperation(
+ IPackageFragmentRoot parentElement,
+ String packageName,
+ boolean force) {
+ super(null, new IJavaElement[] { parentElement }, force);
+ fName = packageName;
+ }
+
+ /**
+ * Execute the operation - creates the new package fragment and any
+ * side effect package fragments.
+ *
+ * @exception JavaModelException if the operation is unable to complete
+ */
+ protected void executeOperation() throws JavaModelException {
+ JavaElementDelta delta = newJavaElementDelta();
+ IPackageFragmentRoot root = (IPackageFragmentRoot) getParentElement();
+ String[] names = Signature.getSimpleNames(fName);
+ beginTask("Creating package fragment(s)...", names.length);
+ IContainer parentFolder = (IContainer) root.getUnderlyingResource();
+ String sideEffectPackageName = "";
+ Vector resultElements = new Vector(names.length);
+ int i;
+ for (i = 0; i < names.length; i++) {
+ String subFolderName = names[i];
+ sideEffectPackageName += subFolderName;
+ IResource subFolder = parentFolder.findMember(subFolderName);
+ if (subFolder == null) {
+ createFolder(parentFolder, subFolderName, fForce);
+ parentFolder = parentFolder.getFolder(new Path(subFolderName));
+ IPackageFragment addedFrag = root.getPackageFragment(sideEffectPackageName);
+ delta.added(addedFrag);
+ resultElements.addElement(addedFrag);
+ } else {
+ parentFolder = (IContainer) subFolder;
+ }
+ sideEffectPackageName += '.';
+ worked(1);
+ }
+ if (resultElements.size() > 0) {
+ fResultElements = new IJavaElement[resultElements.size()];
+ resultElements.copyInto(fResultElements);
+ addDelta(delta);
+ }
+ done();
+ }
+
+ /**
+ * Possible failures: <ul>
+ * <li>NO_ELEMENTS_TO_PROCESS - the root supplied to the operation is
+ * <code>null</code>.
+ * <li>INVALID_NAME - the name provided to the operation
+ * is <code>null</code> or is not a valid package fragment name.
+ * <li>READ_ONLY - the root provided to this operation is read only.
+ * <li>NAME_COLLISION - there is a pre-existing resource (file)
+ * with the same name as a folder in the package fragment's hierarchy.
+ * <li>ELEMENT_NOT_PRESENT - the underlying resource for the root is missing
+ * </ul>
+ * @see IJavaModelStatus
+ * @see JavaNamingConventions
+ */
+ public IJavaModelStatus verify() {
+ if (getParentElement() == null) {
+ return new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
+ }
+
+ if (fName == null
+ || (fName.length() > 0 && !JavaConventions.validatePackageName(fName).isOK())) {
+ return new JavaModelStatus(IJavaModelStatusConstants.INVALID_NAME, fName);
+ }
+ IPackageFragmentRoot root = (IPackageFragmentRoot) getParentElement();
+ if (root.isReadOnly()) {
+ return new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, root);
+ }
+ String[] names = Signature.getSimpleNames(fName);
+ try {
+ IContainer parentFolder = (IContainer) root.getUnderlyingResource();
+ int i;
+ for (i = 0; i < names.length; i++) {
+ IResource subFolder = parentFolder.findMember(names[i]);
+ if (subFolder != null) {
+ if (subFolder.getType() != IResource.FOLDER) {
+ return new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION);
+ }
+ parentFolder = (IContainer) subFolder;
+ }
+ }
+ } catch (JavaModelException npe) {
+ return npe.getJavaModelStatus();
+ }
+ return JavaModelStatus.VERIFIED_OK;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeHierarchyOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeHierarchyOperation.java
new file mode 100644
index 0000000000..e207b91092
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeHierarchyOperation.java
@@ -0,0 +1,108 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.hierarchy.*;
+
+/**
+ * This operation creates an <code>ITypeHierarchy</code> for a specific type within
+ * a specified region, or for all types within a region. The specified
+ * region limits the number of resolved subtypes (i.e. to the subset of
+ * types in the specified region). The resolved supertypes may go outside
+ * of the specified region in order to reach the root(s) of the type
+ * hierarchy. A Java Project is required to provide a context (classpath)
+ * to use while resolving supertypes and subtypes.
+ *
+ * @see ITypeHierarchy
+ */
+
+public class CreateTypeHierarchyOperation extends JavaModelOperation {
+ /**
+ * The generated type hierarchy
+ */
+ protected TypeHierarchy fTypeHierarchy;
+ /**
+ * Constructs an operation to create a type hierarchy for the
+ * given type within the specified region, in the context of
+ * the given project.
+ */
+ public CreateTypeHierarchyOperation(
+ IType element,
+ IRegion region,
+ IJavaProject project,
+ boolean computeSubtypes)
+ throws JavaModelException {
+ super(element);
+ fTypeHierarchy =
+ new RegionBasedTypeHierarchy(region, project, element, computeSubtypes);
+ }
+
+ /**
+ * Constructs an operation to create a type hierarchy for the
+ * given type.
+ */
+ public CreateTypeHierarchyOperation(
+ IType element,
+ IJavaSearchScope scope,
+ boolean computeSubtypes)
+ throws JavaModelException {
+ super(element);
+ fTypeHierarchy = new TypeHierarchy(element, scope, computeSubtypes);
+ }
+
+ /**
+ * Performs the operation - creates the type hierarchy
+ * @exception JavaModelException The operation has failed.
+ */
+ protected void executeOperation() throws JavaModelException {
+ fTypeHierarchy.refresh(this);
+ }
+
+ /**
+ * Returns the generated type hierarchy.
+ */
+ public ITypeHierarchy getResult() {
+ return fTypeHierarchy;
+ }
+
+ /**
+ * @see JavaModelOperation
+ */
+ public boolean isReadOnly() {
+ return true;
+ }
+
+ /**
+ * Possible failures: <ul>
+ * <li>NO_ELEMENTS_TO_PROCESS - at least one of a type or region must
+ * be provided to generate a type hierarchy.
+ * <li>ELEMENT_NOT_PRESENT - the provided type or type's project does not exist
+ * </ul>
+ */
+ public IJavaModelStatus verify() {
+ IJavaElement elementToProcess = getElementToProcess();
+ if (elementToProcess == null
+ && !(fTypeHierarchy instanceof RegionBasedTypeHierarchy)) {
+ return new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
+ }
+ if (elementToProcess != null && !elementToProcess.exists()) {
+ return new JavaModelStatus(
+ IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST,
+ elementToProcess);
+ }
+ IJavaProject project = fTypeHierarchy.javaProject();
+ if (project != null && !project.exists()) {
+ return new JavaModelStatus(
+ IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST,
+ project);
+ }
+ return JavaModelStatus.VERIFIED_OK;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeMemberOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeMemberOperation.java
new file mode 100644
index 0000000000..1702e20066
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeMemberOperation.java
@@ -0,0 +1,144 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.jdom.*;
+
+/**
+ * Implements functionality common to
+ * operations that create type members.
+ */
+public abstract class CreateTypeMemberOperation
+ extends CreateElementInCUOperation {
+ /**
+ * The source code for the new member.
+ */
+ protected String fSource = null;
+ /**
+ * The name of the <code>DOMNode</code> that may be used to
+ * create this new element.
+ * Used by the <code>CopyElementsOperation</code> for renaming
+ */
+ protected String fAlteredName;
+ /**
+ * The JDOM document fragment representing the element that
+ * this operation created.
+ */
+ protected IDOMNode fDOMNode;
+ /**
+ * When executed, this operation will create a type member
+ * in the given parent element with the specified source.
+ */
+ public CreateTypeMemberOperation(
+ IJavaElement parentElement,
+ String source,
+ boolean force) {
+ super(parentElement);
+ fSource = source;
+ fForce = force;
+ }
+
+ /**
+ * @see CreateElementInCUOperation#generateNewCompilationUnitDOM
+ */
+ protected void generateNewCompilationUnitDOM(ICompilationUnit cu)
+ throws JavaModelException {
+ char[] prevSource = cu.getBuffer().getCharacters();
+
+ // create a JDOM for the compilation unit
+ fCUDOM =
+ (new DOMFactory()).createCompilationUnit(prevSource, cu.getElementName());
+ IDOMNode parent = ((JavaElement) getParentElement()).findNode(fCUDOM);
+ if (parent == null) {
+ //#findNode does not work for autogenerated CUs as the contents are empty
+ parent = fCUDOM;
+ }
+ IDOMNode child = generateElementDOM();
+ if (child != null) {
+ insertDOMNode(parent, child);
+ }
+ worked(1);
+ }
+
+ /**
+ * Generates a <code>IDOMNode</code> based on the source of this operation
+ * when there is likely a syntax error in the source.
+ */
+ protected IDOMNode generateSyntaxIncorrectDOM() throws JavaModelException {
+ //create some dummy source to generate a dom node
+ StringBuffer buff = new StringBuffer();
+ buff.append(
+ JavaModelManager.LINE_SEPARATOR
+ + " public class A {"
+ + JavaModelManager.LINE_SEPARATOR);
+ buff.append(fSource);
+ buff.append(JavaModelManager.LINE_SEPARATOR).append('}');
+ IDOMCompilationUnit domCU =
+ (new DOMFactory()).createCompilationUnit(buff.toString(), "A.java");
+ IDOMNode node = (IDOMNode) domCU.getChild("A").getChildren().nextElement();
+ if (node != null) {
+ node.remove();
+ }
+ return node;
+ }
+
+ /**
+ * Returns the IType the member is to be created in.
+ */
+ protected IType getType() {
+ return (IType) getParentElement();
+ }
+
+ /**
+ * Sets the name of the <code>DOMNode</code> that will be used to
+ * create this new element.
+ * Used by the <code>CopyElementsOperation</code> for renaming
+ */
+ protected void setAlteredName(String newName) {
+ fAlteredName = newName;
+ }
+
+ /**
+ * Possible failures: <ul>
+ * <li>NO_ELEMENTS_TO_PROCESS - the parent element supplied to the operation is
+ * <code>null</code>.
+ * <li>INVALID_CONTENTS - The source is <code>null</code> or has serious syntax errors.
+ * <li>NAME_COLLISION - A name collision occurred in the destination
+ * </ul>
+ */
+ public IJavaModelStatus verify() {
+ IJavaModelStatus status = super.verify();
+ if (!status.isOK()) {
+ return status;
+ }
+ if (fSource == null) {
+ return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CONTENTS);
+ }
+ if (!fForce) {
+ //check for name collisions
+ try {
+ IDOMNode node = generateElementDOM();
+ if (node == null) {
+ return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CONTENTS);
+ }
+ } catch (JavaModelException jme) {
+ }
+ return verifyNameCollision();
+ }
+
+ return JavaModelStatus.VERIFIED_OK;
+ }
+
+ /**
+ * Verify for a name collision in the destination container.
+ */
+ protected IJavaModelStatus verifyNameCollision() {
+ return JavaModelStatus.VERIFIED_OK;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeOperation.java
new file mode 100644
index 0000000000..891744b2e0
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeOperation.java
@@ -0,0 +1,101 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.jdom.*;
+
+/**
+ * <p>This operation creates a class or interface.
+ *
+ * <p>Required Attributes:<ul>
+ * <li>Parent element - must be a compilation unit, or type.
+ * <li>The source code for the type. No verification of the source is
+ * performed.
+ * </ul>
+ */
+public class CreateTypeOperation extends CreateTypeMemberOperation {
+ /**
+ * When executed, this operation will create a type unit
+ * in the given parent element (a compilation unit, type)
+ */
+ public CreateTypeOperation(
+ IJavaElement parentElement,
+ String source,
+ boolean force) {
+ super(parentElement, source, force);
+ }
+
+ /**
+ * @see CreateTypeMemberOperation#generateElementDOM
+ */
+ protected IDOMNode generateElementDOM() throws JavaModelException {
+ if (fDOMNode == null) {
+ fDOMNode = (new DOMFactory()).createType(fSource);
+ if (fDOMNode == null) {
+ fDOMNode = generateSyntaxIncorrectDOM();
+ }
+ if (fAlteredName != null && fDOMNode != null) {
+ fDOMNode.setName(fAlteredName);
+ }
+ }
+ return fDOMNode;
+ }
+
+ /**
+ * @see CreateElementInCUOperation#generateResultHandle
+ */
+ protected IJavaElement generateResultHandle() {
+ IJavaElement parent = getParentElement();
+ int type = parent.getElementType();
+ if (type == IJavaElement.TYPE) {
+ return ((IType) parent).getType(fDOMNode.getName());
+ } else
+ if (type == IJavaElement.COMPILATION_UNIT) {
+ return ((ICompilationUnit) parent).getType(fDOMNode.getName());
+ }
+ return null;
+ }
+
+ /**
+ * @see CreateElementInCUOperation#getMainTaskName
+ */
+ public String getMainTaskName() {
+ return "Creating a type...";
+ }
+
+ /**
+ * Returns the <code>IType</code> the member is to be created in.
+ */
+ protected IType getType() {
+ IJavaElement parent = getParentElement();
+ if (parent.getElementType() == IJavaElement.TYPE) {
+ return (IType) parent;
+ }
+ return null;
+ }
+
+ /**
+ * @see CreateTypeMemberOperation#verifyNameCollision
+ */
+ protected IJavaModelStatus verifyNameCollision() {
+ IJavaElement parent = getParentElement();
+ int type = parent.getElementType();
+ if (type == IJavaElement.TYPE) {
+ if (((IType) parent).getType(fDOMNode.getName()).exists()) {
+ return new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION);
+ }
+ } else
+ if (type == IJavaElement.COMPILATION_UNIT) {
+ if (((ICompilationUnit) parent).getType(fDOMNode.getName()).exists()) {
+ return new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION);
+ }
+ }
+ return JavaModelStatus.VERIFIED_OK;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeleteElementsOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeleteElementsOperation.java
new file mode 100644
index 0000000000..ccd6c88727
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeleteElementsOperation.java
@@ -0,0 +1,169 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.jdom.*;
+
+import java.util.*;
+
+/**
+ * This operation deletes a collection of elements (and
+ * all of their children).
+ * If an element does not exist, it is ignored.
+ *
+ * <p>NOTE: This operation only deletes elements contained within leaf resources -
+ * i.e. elements within compilation units. To delete a compilation unit or
+ * a package, etc (i.e. an actual resource), a DeleteResourcesOperation
+ * should be used.
+ */
+public class DeleteElementsOperation extends MultiOperation {
+ /**
+ * The elements this operation processes grouped by compilation unit
+ * @see processElements(). Keys are compilation units,
+ * values are <code>IRegion</code>s of elements to be processed in each
+ * compilation unit.
+ */
+ protected Hashtable fChildrenToRemove;
+ /**
+ * The <code>DOMFactory</code> used to manipulate the source code of
+ * <code>ICompilationUnit</code>s.
+ */
+ protected DOMFactory fFactory;
+ /**
+ * When executed, this operation will delete the given elements. The elements
+ * to delete cannot be <code>null</code> or empty, and must be contained within a
+ * compilation unit.
+ */
+ public DeleteElementsOperation(
+ IJavaElement[] elementsToDelete,
+ boolean force) {
+ super(elementsToDelete, force);
+ fFactory = new DOMFactory();
+ }
+
+ /**
+ * Saves the new contents of the compilation unit that has had
+ * a member element deleted.
+ */
+ protected void commitChanges(IDOMCompilationUnit cuDOM, ICompilationUnit cu)
+ throws JavaModelException {
+ // save the resources that need to be saved
+ char[] newContents = cuDOM.getCharacters();
+ if (newContents == null) {
+ newContents = new char[0];
+ }
+ ((Buffer) cu.getBuffer()).setContents(newContents, true);
+ cu.save(getSubProgressMonitor(1), fForce);
+ }
+
+ /**
+ * @see MultiOperation
+ */
+ protected String getMainTaskName() {
+ return "Deleting elements...";
+ }
+
+ /**
+ * Groups the elements to be processed by their compilation unit.
+ * If parent/child combinations are present, children are
+ * discarded (only the parents are processed). Removes any
+ * duplicates specified in elements to be processed.
+ */
+ protected void groupElements() throws JavaModelException {
+ fChildrenToRemove = new Hashtable(1);
+ int uniqueCUs = 0;
+ for (int i = 0, length = fElementsToProcess.length; i < length; i++) {
+ IJavaElement e = fElementsToProcess[i];
+ ICompilationUnit cu = getCompilationUnitFor(e);
+ if (cu == null) {
+ throw new JavaModelException(new JavaModelStatus(JavaModelStatus.READ_ONLY, e));
+ } else {
+ IRegion region = (IRegion) fChildrenToRemove.get(cu);
+ if (region == null) {
+ region = new Region();
+ fChildrenToRemove.put(cu, region);
+ uniqueCUs += 1;
+ }
+ region.add(e);
+ }
+ }
+ fElementsToProcess = new IJavaElement[uniqueCUs];
+ Enumeration enum = fChildrenToRemove.keys();
+ int i = 0;
+ while (enum.hasMoreElements()) {
+ fElementsToProcess[i++] = (IJavaElement) enum.nextElement();
+ }
+ }
+
+ /**
+ * Deletes this element from its compilation unit.
+ * @see MultiOperation
+ */
+ protected void processElement(IJavaElement element) throws JavaModelException {
+ ICompilationUnit cu = (ICompilationUnit) element;
+
+ // keep track of the import statements - if all are removed, delete
+ // the import container (i.e. report it in the delta)
+ int numberOfImports = cu.getImports().length;
+
+ IDOMCompilationUnit cuDOM =
+ fFactory.createCompilationUnit(
+ cu.getBuffer().getCharacters(),
+ cu.getElementName());
+ JavaElementDelta delta = new JavaElementDelta(cu);
+ IJavaElement[] cuElements = ((IRegion) fChildrenToRemove.get(cu)).getElements();
+ for (int i = 0; i < cuElements.length; i++) {
+ IJavaElement e = cuElements[i];
+ if (e.exists()) {
+ IDOMNode node = ((JavaElement) e).findNode(cuDOM);
+ // TBD
+ Assert.isTrue(
+ node != null,
+ "Failed to locate " + e.getElementName() + " in " + cuDOM.getName());
+ node.remove();
+ delta.removed(e);
+ if (e.getElementType() == IJavaElement.IMPORT_DECLARATION) {
+ numberOfImports--;
+ if (numberOfImports == 0) {
+ delta.removed(cu.getImportContainer());
+ }
+ }
+ }
+ }
+ if (delta.getAffectedChildren().length > 0) {
+ commitChanges(cuDOM, cu);
+ addDelta(delta);
+ }
+ }
+
+ /**
+ * @see MultiOperation
+ * This method first group the elements by <code>ICompilationUnit</code>,
+ * and then processes the <code>ICompilationUnit</code>.
+ */
+ protected void processElements() throws JavaModelException {
+ groupElements();
+ super.processElements();
+ }
+
+ /**
+ * @see MultiOperation
+ */
+ protected void verify(IJavaElement element) throws JavaModelException {
+ IJavaElement[] children =
+ ((IRegion) fChildrenToRemove.get(element)).getElements();
+ for (int i = 0; i < children.length; i++) {
+ IJavaElement child = children[i];
+ if (child.getCorrespondingResource() != null)
+ error(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, child);
+ if (child.isReadOnly())
+ error(IJavaModelStatusConstants.READ_ONLY, child);
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeleteResourceElementsOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeleteResourceElementsOperation.java
new file mode 100644
index 0000000000..74cefd18f5
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeleteResourceElementsOperation.java
@@ -0,0 +1,130 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.JavaModelException;
+
+import java.util.Enumeration;
+
+/**
+ * This operation deletes a collection of resources and all of their children.
+ * It does not delete resources which do not belong to the Java Model
+ * (eg GIF files).
+ */
+public class DeleteResourceElementsOperation extends MultiOperation {
+ /**
+ * When executed, this operation will delete the given elements. The elements
+ * to delete cannot be <code>null</code> or empty, and must have a corresponding
+ * resource.
+ */
+ protected DeleteResourceElementsOperation(
+ IJavaElement[] elementsToProcess,
+ boolean force) {
+ super(elementsToProcess, force);
+ }
+
+ /**
+ * Deletes the direct children of <code>frag</code> corresponding to its kind
+ * (K_SOURCE or K_BINARY), and deletes the corresponding folder if it is then
+ * empty.
+ */
+ private void deletePackageFragment(IPackageFragment frag)
+ throws JavaModelException {
+ IResource res = frag.getCorrespondingResource();
+ if (res != null && res.getType() == IResource.FOLDER) {
+ // collect the children to remove
+ IJavaElement[] childrenOfInterest;
+ if (frag.getKind() == IPackageFragmentRoot.K_SOURCE) {
+ childrenOfInterest = frag.getCompilationUnits();
+ } else { // K_BINARY
+ childrenOfInterest = frag.getClassFiles();
+ }
+ if (childrenOfInterest.length > 0) {
+ IResource[] resources = new IResource[childrenOfInterest.length];
+ // remove the children
+ for (int i = 0; i < childrenOfInterest.length; i++) {
+ resources[i] = childrenOfInterest[i].getCorrespondingResource();
+ }
+ deleteResources(resources, fForce);
+ }
+
+ // Discard non-java resources
+ Object[] nonJavaResources = frag.getNonJavaResources();
+ int actualResourceCount = 0;
+ for (int i = 0, max = nonJavaResources.length; i < max; i++) {
+ if (nonJavaResources[i] instanceof IResource)
+ actualResourceCount++;
+ }
+ IResource[] actualNonJavaResources = new IResource[actualResourceCount];
+ for (int i = 0, max = nonJavaResources.length, index = 0; i < max; i++) {
+ if (nonJavaResources[i] instanceof IResource)
+ actualNonJavaResources[index++] = (IResource) nonJavaResources[i];
+ }
+ deleteResources(actualNonJavaResources, fForce);
+
+ // remove the folder if it is empty
+ IResource[] members;
+ try {
+ members = ((IFolder) res).members();
+ } catch (CoreException ce) {
+ throw new JavaModelException(ce);
+ }
+ if (members.length == 0) {
+ deleteEmptyPackageFragment(frag, fForce);
+ }
+ }
+ }
+
+ /**
+ * @see MultiOperation
+ */
+ protected String getMainTaskName() {
+ return "Deleting resources...";
+ }
+
+ /**
+ * @see MultiOperation. This method delegate to <code>deleteResource</code> or
+ * <code>deletePackageFragment</code> depending on the type of <code>element</code>.
+ */
+ protected void processElement(IJavaElement element) throws JavaModelException {
+ switch (element.getElementType()) {
+ case IJavaElement.CLASS_FILE :
+ case IJavaElement.COMPILATION_UNIT :
+ deleteResource(element.getCorrespondingResource(), fForce);
+ break;
+ case IJavaElement.PACKAGE_FRAGMENT :
+ deletePackageFragment((IPackageFragment) element);
+ break;
+ default :
+ throw new JavaModelException(
+ new JavaModelStatus(JavaModelStatus.INVALID_ELEMENT_TYPES, element));
+ }
+ }
+
+ /**
+ * @see MultiOperation
+ */
+ protected void verify(IJavaElement element) throws JavaModelException {
+ if (element == null || !element.exists())
+ error(JavaModelStatus.ELEMENT_DOES_NOT_EXIST, element);
+
+ int type = element.getElementType();
+ if (type <= IJavaElement.PACKAGE_FRAGMENT_ROOT
+ || type > IJavaElement.COMPILATION_UNIT)
+ error(JavaModelStatus.INVALID_ELEMENT_TYPES, element);
+ else
+ if (type == IJavaElement.PACKAGE_FRAGMENT
+ && element instanceof JarPackageFragment)
+ error(JavaModelStatus.INVALID_ELEMENT_TYPES, element);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java
new file mode 100644
index 0000000000..d765993ec0
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java
@@ -0,0 +1,901 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.QualifiedName;
+
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaElementDelta;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
+
+import org.eclipse.jdt.internal.core.search.indexing.*;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+/**
+ * This class is used by <code>JavaModelManager</code> to convert
+ * <code>IResourceDelta</code>s into <code>IJavaElementDelta</code>s.
+ * It also does some processing on the <code>JavaElement</code>s involved
+ * (e.g. closing them or updating classpaths).
+ */
+public class DeltaProcessor {
+ /**
+ * The <code>JavaElementDelta</code> corresponding to the <code>IResourceDelta</code> being translated.
+ */
+ protected JavaElementDelta fCurrentDelta;
+
+ /**
+ * JavaProjects that need classpaths updated when resource delta
+ * translation is complete.
+ */
+ protected Hashtable fJavaProjectsToUpdate = null;
+
+ /**
+ * PackageFragmentRoots that have been removed. When delta translation
+ * is compelte, these roots are removed from classpaths.
+ */
+ protected Vector fRootsRemoved = null;
+
+ /**
+ * Flag can be set to avoid processing children of current element
+ */
+ protected boolean fProcessChildren = true;
+
+ protected IndexManager indexManager = JavaModelManager.ENABLE_INDEXING ? new IndexManager() : null;
+/**
+ * Inserts the new classpath entry after the specified entry, in the give
+ * projects info. This is done such that resources in this root can be
+ * translated into JavaElement by the factory. The classpath is not persisted
+ * until delta translation is complete.
+ */
+protected void addClasspathEntry(JavaProject project, IClasspathEntry after, IClasspathEntry newEntry) {
+ try {
+ IClasspathEntry[] cp = project.getRawClasspath();
+ IClasspathEntry[] newPath = new IClasspathEntry[cp.length + 1];
+ int j = 0;
+ for (int i = 0; i < cp.length; i++) {
+ newPath[j] = cp[i];
+ if (cp[i].equals(after)) {
+ j++;
+ newPath[j] = newEntry;
+ }
+ j++;
+ }
+ ((JavaProjectElementInfo)project.getElementInfo()).setRawClasspath(newPath);
+ resetNonJavaResourcesForPackageFragmentRoots(project);
+ } catch (JavaModelException e) {
+ // nothing
+ }
+
+}
+/**
+ * Adds the given child handle to its parent's cache of children.
+ */
+protected void addToParentInfo(Openable child) {
+ Openable parent = (Openable)child.getParent();
+ if (parent != null && parent.isOpen()) {
+ try {
+ JavaElementInfo info = parent.getElementInfo();
+ info.addChild(child);
+ } catch (JavaModelException e) {
+ // do nothing - we already checked if open
+ }
+ }
+}
+/**
+ * Generic processing for an element that has been added:<ul>
+ * <li>The element is added to its parent's cache of children
+ * <li>The element is closed (to ensure consistency)
+ * <li>An entry is made in the delta reporting it as added (ADDED).
+ * </ul>
+ * <p>
+ * If the element is an archive, and it has just been added, it may not be specified
+ * on the project's classpath. In this case, the new element is not added as a child
+ * of its parent (since only package fragment roots on the classpath are considered to
+ * be children of a project).
+ */
+protected void basicElementAdded(Openable element, IResourceDelta delta) {
+ if (isOpen(delta.getResource())) {
+ boolean onClasspath = isOnClasspath(element);
+
+ // only add as a child if it is on the classpath
+ if (onClasspath) {
+ addToParentInfo(element);
+ switch (element.getElementType()) {
+ case IJavaElement.PACKAGE_FRAGMENT_ROOT :
+ // when a root is added, and is on the classpath, the project must be updated
+ JavaProject project = (JavaProject)element.getJavaProject();
+ updateProject(project);
+ //1G1TW2T - get rid of namelookup since it holds onto obsolete cached info
+ try {
+ project.getJavaProjectElementInfo().setNameLookup(null);
+ } catch(JavaModelException e){
+ }
+ break;
+ case IJavaElement.PACKAGE_FRAGMENT :
+ //1G1TW2T - get rid of namelookup since it holds onto obsolete cached info
+ project = (JavaProject)element.getJavaProject();
+ try {
+ project.getJavaProjectElementInfo().setNameLookup(null);
+ } catch(JavaModelException e){
+ }
+ break;
+ }
+ }
+
+ close(element);
+ fCurrentDelta.added(element);
+ }
+}
+/**
+ * Check whether the updated file is affecting some of the properties of a given project (like
+ * its classpath persisted as a file).
+ *
+ */
+public static void checkProjectPropertyFileUpdate(IResourceDelta delta, IJavaElement parent){
+
+ IResource resource = delta.getResource();
+ IJavaElement element = JavaCore.create(resource);
+
+ boolean processChildren = false;
+
+ switch (resource.getType()) {
+
+ case IResource.PROJECT :
+ try {
+ if (((IProject) resource).hasNature(JavaCore.NATURE_ID)) {
+ processChildren = true;
+ }
+ } catch(CoreException e) {
+ }
+ break;
+ case IResource.FILE :
+ if (parent.getElementType() == IJavaElement.JAVA_PROJECT) {
+ IFile file = (IFile)resource;
+ JavaProject project = (JavaProject)parent;
+
+ /* check classpath property file change */
+ QualifiedName classpathProp;
+ if (file.getName().equals(project.computeSharedPropertyFileName(classpathProp = project.getClasspathPropertyName()))){
+ switch(delta.getKind()){
+ case IResourceDelta.REMOVED : // recreate one based on in-memory path
+ try {
+ project.saveClasspath();
+ } catch(JavaModelException e){
+ }
+ break; // might consider to regenerate the file (accidental deletion?)
+ case IResourceDelta.ADDED :
+ case IResourceDelta.CHANGED : // check if any actual difference
+ IPath oldOutputLocation = null;
+ try {
+ oldOutputLocation = project.getOutputLocation();
+ // force to (re)read the property file
+ String fileClasspathString = project.getSharedProperty(classpathProp);
+ if (fileClasspathString == null) break; // did not find the file
+ IClasspathEntry[] fileEntries = project.readPaths(fileClasspathString);
+ if (fileEntries == null) break; // could not read, ignore
+ if (project.isClasspathEqualsTo(fileEntries)) break;
+
+ // will force an update of the classpath/output location based on the file information
+ // extract out the output location
+ IPath outputLocation= null;
+ if (fileEntries != null && fileEntries.length > 0) {
+ IClasspathEntry entry = fileEntries[fileEntries.length - 1];
+ if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
+ outputLocation = entry.getPath();
+ IClasspathEntry[] copy= new IClasspathEntry[fileEntries.length - 1];
+ System.arraycopy(fileEntries, 0, copy, 0, copy.length);
+ fileEntries = copy;
+ }
+ }
+ // restore output location
+ if (outputLocation != null) {
+ project.setOutputLocation0(outputLocation);
+ }
+ try {
+ project.setRawClasspath(fileEntries, null, false);
+ } catch(JavaModelException e){ // undo output location change
+ project.setOutputLocation0(oldOutputLocation);
+ }
+ } catch(IOException e){
+ break;
+ } catch(RuntimeException e){
+ break;
+ } catch(CoreException e){
+ break;
+ }
+
+ }
+ }
+ }
+ break;
+ }
+ if (processChildren){
+ IResourceDelta[] children = delta.getAffectedChildren();
+ for (int i = 0; i < children.length; i++) {
+ checkProjectPropertyFileUpdate(children[i], element);
+ }
+ }
+}
+/**
+ * Clears the caches related to classpath updates.
+ */
+protected void clearState() {
+ fJavaProjectsToUpdate = null;
+ fRootsRemoved = null;
+}
+/**
+ * Closes the given element, which removes it from the cache of open elements.
+ */
+protected static void close(Openable element) {
+ try {
+ element.close();
+ } catch (JavaModelException e) {
+ // do nothing
+ }
+}
+/**
+ * Traverse an existing delta and close the affected compilation units.
+ */
+protected void closeAffectedElements(IResourceDelta delta) {
+
+ Openable element = (Openable)JavaCore.create(delta.getResource());
+ boolean processChildren = true;
+ if (element != null){
+ int flags = delta.getFlags();
+ switch(element.getElementType()){
+ case IJavaElement.CLASS_FILE :
+ case IJavaElement.COMPILATION_UNIT :
+ processChildren = false;
+ switch (delta.getKind()) {
+ case IResourceDelta.ADDED:
+ break;
+ case IResourceDelta.CHANGED:
+ if ((flags & IResourceDelta.CONTENT) > 1) {
+ try {
+ element.close();
+ } catch(JavaModelException e){
+ }
+ }
+ break;
+ case IResourceDelta.REMOVED:
+ try {
+ element.close();
+ } catch(JavaModelException e){
+ }
+ }
+ }
+ }
+ if (processChildren){
+ IResourceDelta[] children = delta.getAffectedChildren();
+ for (int i = 0; i < children.length; i++) {
+ closeAffectedElements(children[i]);
+ }
+ }
+}
+/**
+ * Generic processing for elements with changed contents:<ul>
+ * <li>The element is closed such that any subsequent accesses will re-open
+ * the element reflecting its new structure.
+ * <li>An entry is made in the delta reporting a content change (K_CHANGE with F_CONTENT flag set).
+ * </ul>
+ */
+protected void contentChanged(Openable element, IResourceDelta delta) {
+
+ close(element);
+ fCurrentDelta.changed(element, IJavaElementDelta.F_CONTENT);
+}
+/**
+ * Creates the openables corresponding to this resource.
+ * Returns null if none was found.
+ * In general, there is only one openable corresponding to a resource,
+ * except for jar and zip files that can correspond to one or more
+ * JarPackageFragmentRoots.
+ */
+protected Openable[] createElements(IResource resource) {
+ if (resource == null) return null;
+ String extension = resource.getFileExtension();
+ extension = extension == null ? null : extension.toLowerCase();
+ if ("jar".equals(extension) || "zip".equals(extension)) {
+ IJavaProject[] projects = null;
+ try {
+ projects = JavaModelManager.getJavaModel(resource.getWorkspace()).getJavaProjects();
+ } catch (JavaModelException e) {
+ return null;
+ }
+ Vector jars = new Vector();
+ for (int i = 0, length = projects.length; i < length; i++) {
+ IJavaProject project = projects[i];
+ // Create a jar package fragment root only if on the classpath
+ IPath resourcePath = resource.getFullPath();
+ try {
+ IClasspathEntry[] entries = project.getResolvedClasspath(true);
+ for (int j = 0, length2 = entries.length; j < length2; j++) {
+ IClasspathEntry entry = entries[j];
+ IPath rootPath = entry.getPath();
+ if (rootPath.equals(resourcePath)) {
+ jars.add(project.getPackageFragmentRoot((IFile)resource));
+ }
+ }
+ } catch (JavaModelException e) {
+ }
+ }
+ int size = jars.size();
+ if (size == 0) return null;
+ Openable[] result = new Openable[size];
+ jars.copyInto(result);
+ return result;
+ } else {
+ Openable element = (Openable)JavaCore.create(resource);
+ if (element == null) {
+ return null;
+ } else {
+ return new Openable[] {element};
+ }
+ }
+}
+/**
+ * Processing for an element that has been added:<ul>
+ * <li>If the element is a project, do nothing, and do not process
+ * children, as when a project is created it does not yet have any
+ * natures - specifically a java nature.
+ * <li>If the elemet is not a project, process it as added (see
+ * <code>basicElementAdded</code>.
+ * </ul>
+ */
+protected void elementAdded(Openable element, IResourceDelta delta) {
+ if (element.getElementType() == IJavaElement.JAVA_PROJECT) {
+ // project add is handled by JavaProject.configure() because
+ // when a project is created, it does not yet have a java nature
+ if (hasJavaNature(delta.getResource())) {
+ basicElementAdded(element, delta);
+ }
+ fProcessChildren = false;
+ return;
+ } else {
+ basicElementAdded(element, delta);
+ }
+}
+/**
+ * Processing for the closing of an element - there are two cases:<ul>
+ * <li>when a project is closed (in the platform sense), the
+ * JavaModel reports this as if the JavaProject has been removed.
+ * <li>otherwise, the JavaModel reports this
+ * as a the element being closed (CHANGED + F_CLOSED).
+ * </ul>
+ * <p>In both cases, the children of the element are not processed. When
+ * a resource is closed, the platform reports all children as removed. This
+ * would effectively delete the classpath if we processed children.
+ */
+protected void elementClosed(Openable element, IResourceDelta delta) {
+ if (element.getElementType() == IJavaElement.JAVA_PROJECT) {
+ // treat project closing as removal
+ elementRemoved(element, delta);
+ } else {
+ removeFromParentInfo(element);
+ close(element);
+ fCurrentDelta.closed(element);
+ }
+ // do not process any children
+ fProcessChildren = false;
+}
+/**
+ * Processing for the opening of an element - there are two cases:<ul>
+ * <li>when a project is opened (in the platform sense), the
+ * JavaModel reports this as if the JavaProject has been added.
+ * <li>otherwise, the JavaModel reports this
+ * as a the element being opened (CHANGED + F_CLOSED).
+ * </ul>
+ */
+protected void elementOpened(Openable element, IResourceDelta delta) {
+ if (element.getElementType() == IJavaElement.JAVA_PROJECT) {
+ // treat project opening as addition
+ if (hasJavaNature(delta.getResource())) {
+ basicElementAdded(element, delta);
+ }
+ } else {
+ addToParentInfo(element);
+ fCurrentDelta.opened(element);
+ }
+}
+/**
+ * Generic processing for a removed element:<ul>
+ * <li>Close the element, removing its structure from the cache
+ * <li>Remove the element from its parent's cache of children
+ * <li>Add a REMOVED entry in the delta
+ * </ul>
+ * When a package fragment root is removed, and it is on its project's classpath,
+ * the classpath entry is marked to be removed when delta translation it done.
+ * We postpone removing the classpath entry until delta translation is complete
+ * so the factory can still translate resources into JavaElements for resources
+ * which are children of the root. The delta for the removed mark is also annotated
+ * with the F_REMOVED_FROM_CLASSPATH change flag.
+ */
+protected void elementRemoved(Openable element, IResourceDelta delta) {
+ close(element);
+ removeFromParentInfo(element);
+ fCurrentDelta.removed(element);
+
+ switch(element.getElementType()){
+ case IJavaElement.JAVA_PROJECT :
+ JavaModelManager.getJavaModelManager().removePerProjectInfo((JavaProject) element);
+ break;
+ case IJavaElement.PACKAGE_FRAGMENT_ROOT :
+ // when a root on the classpath is removed, the classpath must be updated
+ if (isOnClasspath(element)) {
+ rootRemoved((IPackageFragmentRoot)element);
+ JavaElementDelta rootDelta = fCurrentDelta.find(element);
+ rootDelta.setFlags(rootDelta.getFlags() | IJavaElementDelta.F_REMOVED_FROM_CLASSPATH);
+ //1G1TW2T - get rid of namelookup since it holds onto obsolete cached info
+ JavaProject project = (JavaProject)element.getJavaProject();
+ try {
+ project.getJavaProjectElementInfo().setNameLookup(null);
+ } catch(JavaModelException e){
+ }
+ }
+ break;
+ case IJavaElement.PACKAGE_FRAGMENT :
+ //1G1TW2T - get rid of namelookup since it holds onto obsolete cached info
+ if (isOnClasspath(element)) {
+ JavaProject project = (JavaProject)element.getJavaProject();
+ try {
+ project.getJavaProjectElementInfo().setNameLookup(null);
+ } catch(JavaModelException e){
+ }
+ }
+ break;
+ case IJavaElement.JAVA_MODEL:
+ element.getJavaModelManager().getIndexManager().reset();
+ element.getJavaModelManager().fModelInfo = null;
+ break;
+ }
+}
+/**
+ * Filters the generated <code>JavaElementDelta</code>s to remove those
+ * which should not be fired (because they don't represent a real change
+ * in the Java Model).
+ */
+protected IJavaElementDelta[] filterRealDeltas(IJavaElementDelta[] deltas) {
+ IJavaElementDelta[] realDeltas = new IJavaElementDelta[deltas.length];
+ int index = 0;
+ for (int i = 0; i < deltas.length; i++) {
+ IJavaElementDelta delta = deltas[i];
+ if (delta == null) {
+ continue;
+ }
+ if (delta.getAffectedChildren().length > 0 ||
+ delta.getKind() != IJavaElementDelta.CHANGED ||
+ delta.getFlags() == IJavaElementDelta.F_CLOSED ||
+ delta.getFlags() == IJavaElementDelta.F_OPENED) {
+
+ realDeltas[index++] = delta;
+ }
+ }
+ IJavaElementDelta[] result = new IJavaElementDelta[index];
+ if (result.length > 0) {
+ System.arraycopy(realDeltas, 0, result, 0, result.length);
+ }
+ return result;
+}
+/**
+ * Returns true if the given resource is contained in an open project
+ * with a java nature, otherwise false.
+ */
+protected boolean hasJavaNature(IResource resource) {
+ // ensure the project has a java nature (if open)
+ IProject project = resource.getProject();
+ if (project.isOpen()) {
+ try {
+ return project.hasNature(JavaCore.NATURE_ID);
+ } catch (CoreException e) {
+ // do nothing
+ }
+ }
+ return false;
+}
+/**
+ * Returns true if on of the following holds, otherwise false:<ul>
+ * <li>the given element is a package fragment root and is specified
+ * on its project's classpath
+ * <li>the given element is not a package fragment root
+ * </ul>
+ */
+protected boolean isOnClasspath(IJavaElement element) {
+
+ if (element.getElementType() == IJavaElement.PACKAGE_FRAGMENT_ROOT) {
+ IPackageFragmentRoot root = (IPackageFragmentRoot)element;
+ JavaProject jp= (JavaProject)element.getJavaProject();
+ try {
+ return jp.getClasspathEntryFor(root.getPath()) != null;
+ } catch (JavaModelException e) {
+ return false;
+ }
+ } else {
+ return true;
+ }
+
+}
+/**
+ * Returns true if the given resource is considered open (in the
+ * platform sense), otherwise false.
+ */
+protected boolean isOpen(IResource resource) {
+ IProject project = resource.getProject();
+ if (project == null) {
+ return true; // workspace is always open
+ } else {
+ return project.isOpen();
+ }
+}
+/**
+ * Creates and returns a new classpath entry of the same kind as the
+ * old entry, but with the new specified path.
+ */
+protected IClasspathEntry newClasspathEntry(IJavaProject project, IClasspathEntry oldEntry, IPath to) {
+ IClasspathEntry newEntry = null;
+ switch (oldEntry.getEntryKind()) {
+ case IClasspathEntry.CPE_LIBRARY :
+ newEntry = JavaCore.newLibraryEntry(to, oldEntry.getSourceAttachmentPath(), oldEntry.getSourceAttachmentRootPath());
+ break;
+ case IClasspathEntry.CPE_PROJECT :
+ newEntry = JavaCore.newProjectEntry(to);
+ break;
+ case IClasspathEntry.CPE_SOURCE :
+ newEntry = JavaCore.newSourceEntry(to);
+ break;
+ }
+ return newEntry;
+}
+/**
+ * Generic processing for elements with changed contents:<ul>
+ * <li>The element is closed such that any subsequent accesses will re-open
+ * the element reflecting its new structure.
+ * <li>An entry is made in the delta reporting a content change (K_CHANGE with F_CONTENT flag set).
+ * </ul>
+ */
+protected void nonJavaResourcesChanged(Openable element, IResourceDelta delta) throws JavaModelException {
+ JavaElementInfo info = element.getElementInfo();
+ switch (element.getElementType()) {
+ case IJavaElement.JAVA_PROJECT :
+ IResource resource = delta.getResource();
+ ((JavaProjectElementInfo) info).setNonJavaResources(null);
+
+ // if a package fragment root is the project, clear it too
+ PackageFragmentRoot projectRoot = (PackageFragmentRoot)((JavaProject)element).getPackageFragmentRoot(new Path(IPackageFragment.DEFAULT_PACKAGE_NAME));
+ if (projectRoot.isOpen()) {
+ ((PackageFragmentRootInfo)projectRoot.getElementInfo()).setNonJavaResources(null);
+ }
+
+ if (delta.getResource().getFullPath().equals(((JavaProject)element).getOutputLocation())) {
+ fProcessChildren = false;
+ return;
+ }
+ break;
+ case IJavaElement.PACKAGE_FRAGMENT :
+ ((PackageFragmentInfo) info).setNonJavaResources(null);
+ break;
+ case IJavaElement.PACKAGE_FRAGMENT_ROOT :
+ ((PackageFragmentRootInfo) info).setNonJavaResources(null);
+ };
+
+ JavaElementDelta elementDelta = fCurrentDelta.find(element);
+ if (elementDelta == null) {
+ fCurrentDelta.changed(element, IJavaElementDelta.F_CONTENT);
+ elementDelta = fCurrentDelta.find(element);
+ }
+ elementDelta.addResourceDelta(delta);
+}
+/**
+ * Removes classpath entries associated with removed roots, from the
+ * corresponding project's.
+ */
+protected void processRemovedRoots() {
+ if (fRootsRemoved != null) {
+ Enumeration roots = fRootsRemoved.elements();
+ while (roots.hasMoreElements()) {
+ PackageFragmentRoot root = (PackageFragmentRoot)roots.nextElement();
+ JavaProject jp = (JavaProject)root.getJavaProject();
+ try {
+ IClasspathEntry entry = jp.getClasspathEntryFor(root.getPath());
+ if (entry != null) {
+ removeClasspathEntry(jp, entry);
+ } else {
+ // The root was not referenced, do nothing.
+ }
+ } catch (JavaModelException e) {
+ // do nothing
+ }
+
+ }
+ }
+}
+/**
+ * Converts a <code>IResourceDelta</code> rooted in a <code>Workspace</code> into
+ * the corresponding set of <code>IJavaElementDelta</code>, rooted in the
+ * relevant <code>JavaModel</code>s.
+ */
+public IJavaElementDelta[] processResourceDelta(IResourceDelta changes) {
+
+ // clear state
+ clearState();
+
+ // get the workspace delta, and start processing there.
+ IResourceDelta[] deltas = changes.getAffectedChildren();
+ IJavaElementDelta[] translatedDeltas = new JavaElementDelta[deltas.length];
+ for (int i = 0; i < deltas.length; i++) {
+ IResourceDelta delta = deltas[i];
+ JavaModel model = JavaModelManager.getJavaModel(delta.getResource().getWorkspace());
+ if (model != null) {
+ fCurrentDelta = new JavaElementDelta(model);
+ traverseDelta(delta, model); // traverse delta
+ translatedDeltas[i] = fCurrentDelta;
+ }
+ }
+ // process removed roots
+ processRemovedRoots();
+ // update classpaths
+ updateClasspaths(false);
+
+ // clear state
+ clearState();
+
+ return filterRealDeltas(translatedDeltas);
+}
+/**
+ * Removes the specified classpath entry from the given project's info.
+ */
+protected void removeClasspathEntry(JavaProject project, IClasspathEntry entry) {
+ try {
+ IClasspathEntry[] cp = project.getRawClasspath();
+ IClasspathEntry[] newPath = new IClasspathEntry[cp.length - 1];
+ int pos = 0;
+ for (int i = 0; i < cp.length; i++) {
+ if (!cp[i].equals(entry)) {
+ newPath[pos] = cp[i];
+ pos++;
+ }
+ }
+
+ ((JavaProjectElementInfo)project.getElementInfo()).setRawClasspath(newPath);
+ resetNonJavaResourcesForPackageFragmentRoots(project);
+ } catch (JavaModelException e) {
+ // failed to update classpath
+ }
+}
+/**
+ * Removes the given element from its parents cache of children. If the
+ * element does not have a parent, or the parent is not currently open,
+ * this has no effect.
+ */
+protected void removeFromParentInfo(Openable child) {
+ Openable parent = (Openable)child.getParent();
+ if (parent != null && parent.isOpen()) {
+ try {
+ JavaElementInfo info = parent.getElementInfo();
+ info.removeChild(child);
+ } catch (JavaModelException e) {
+ // do nothing - we already checked if open
+ }
+ }
+}
+/**
+ * Reset the non-java resources collection for package fragment roots of the
+ * corresponding project.
+ */
+protected void resetNonJavaResourcesForPackageFragmentRoots(JavaProject project) throws JavaModelException {
+ IPackageFragmentRoot[] roots = project.getAllPackageFragmentRoots();
+ if (roots == null) return;
+ for (int i = 0, max = roots.length; i < max; i++) {
+ IPackageFragmentRoot root = roots[i];
+ IResource res = root.getUnderlyingResource();
+ if (res != null) {
+ ((PackageFragmentRoot)root).resetNonJavaResources();
+ }
+ }
+}
+/**
+ * Add the given root to the list of roots that have been removed, and mark
+ * its project as requiring an update. When delta translation is complete,
+ * projects will have their classpaths updated.
+ */
+protected void rootRemoved(IPackageFragmentRoot root) {
+ if (fRootsRemoved == null) {
+ fRootsRemoved = new Vector(2);
+ }
+ fRootsRemoved.addElement(root);
+ updateProject(root.getJavaProject());
+}
+/**
+ * Converts an <code>IResourceDelta</code> and its children into
+ * the corresponding <code>IJavaElementDelta</code>s.
+ */
+protected void traverseDelta(IResourceDelta delta, Openable parentElement) {
+ Openable[] elements = this.createElements(delta.getResource());
+ Openable element = null;
+ int flags = delta.getFlags();
+ fProcessChildren = true;
+ if (elements != null) {
+ for (int i = 0, length = elements.length; i < length; i++) {
+ element = elements[i];
+ IResource res = delta.getResource();
+
+ updateIndex(element, delta);
+ switch (delta.getKind()) {
+ case IResourceDelta.ADDED:
+ switch(res.getType()) {
+ case IResource.FILE :
+ case IResource.FOLDER:
+ IProject fileProject = delta.getResource().getProject();
+ IJavaProject project = (IJavaProject) JavaCore.create(fileProject);
+ try {
+ IPackageFragmentRoot pkgRoot;
+ if (parentElement != null
+ && ((pkgRoot = parentElement.getPackageFragmentRoot()) != null)
+ && !pkgRoot.exists()) {
+ nonJavaResourcesChanged(parentElement, delta);
+ break;
+ }
+ } catch(JavaModelException e) {
+ }
+ break;
+ }
+ elementAdded(element, delta);
+ break;
+ case IResourceDelta.REMOVED:
+ switch(res.getType()) {
+ case IResource.FILE :
+ case IResource.FOLDER:
+ IProject fileProject = delta.getResource().getProject();
+ IJavaProject project = (IJavaProject) JavaCore.create(fileProject);
+ try {
+ IPackageFragmentRoot pkgRoot;
+ if (parentElement != null
+ && ((pkgRoot = parentElement.getPackageFragmentRoot()) != null)
+ && !pkgRoot.exists()) {
+ nonJavaResourcesChanged(parentElement, delta);
+ break;
+ }
+ } catch(JavaModelException e) {
+ }
+ break;
+ }
+ elementRemoved(element, delta);
+ break;
+ case IResourceDelta.CHANGED:
+ if ((flags & IResourceDelta.CONTENT) > 1) {
+ contentChanged(element, delta);
+ break;
+ }
+ if ((flags & IResourceDelta.OPEN) > 1) {
+ res = delta.getResource();
+ if (isOpen(res)) {
+ elementOpened(element, delta);
+ } else {
+ elementClosed(element, delta);
+ }
+ break;
+ }
+ break;
+ }
+ }
+ } else {
+ try {
+ if (parentElement != null && delta.getResource() != null) {
+ switch (delta.getResource().getType()) {
+ case IResource.FILE:
+ case IResource.FOLDER:
+ nonJavaResourcesChanged(parentElement, delta);
+ }
+ }
+ } catch (JavaModelException e) {
+ // do nothing
+ }
+
+ // checked for a moved root - the factory cannot create elements for roots not specified
+ // on the classpath.
+ if (delta.getKind() == IResourceDelta.ADDED &&
+ ((flags & IResourceDelta.MOVED_FROM) > 1)) {
+ IProject project = delta.getResource().getProject();
+ if (project != null) {
+ JavaProject jp = (JavaProject)JavaCore.create(project);
+ if (jp != null) {
+ try {
+ IClasspathEntry oldEntry = jp.getClasspathEntryFor(delta.getMovedFromPath());
+ if (oldEntry != null) {
+ IClasspathEntry newEntry = newClasspathEntry(jp, oldEntry, delta.getResource().getFullPath());
+ addClasspathEntry(jp, oldEntry, newEntry);
+ // now the factory can create the root.
+ element = (Openable)JavaCore.create(delta.getResource());
+ elementAdded(element, delta);
+ JavaElementDelta rootDelta = fCurrentDelta.find(element);
+ rootDelta.setFlags(rootDelta.getFlags() | IJavaElementDelta.F_ADDED_TO_CLASSPATH);
+ }
+ } catch (JavaModelException e) {
+ // nothing
+ }
+ }
+ }
+ }
+ }
+ if (fProcessChildren) {
+ IResourceDelta[] children = delta.getAffectedChildren();
+ for (int i = 0; i < children.length; i++) {
+ traverseDelta(children[i], element);
+ }
+ }
+}
+/**
+ * Updates the classpath of each project requiring update. This refreshes
+ * the cached info in each project's namelookup facility, and persists
+ * classpaths.
+ */
+protected void updateClasspaths(boolean saveClasspath) {
+ if (fJavaProjectsToUpdate != null) {
+ Enumeration projects = fJavaProjectsToUpdate.elements();
+ while (projects.hasMoreElements()) {
+ JavaProject project = (JavaProject)projects.nextElement();
+ try {
+ project.updateClassPath();
+ if (saveClasspath) project.saveClasspath();
+ } catch (JavaModelException e) {
+ }
+ }
+ }
+
+}
+protected void updateIndex(Openable element, IResourceDelta delta){
+
+ if (indexManager == null) return;
+
+ switch(element.getElementType()){
+ case IJavaElement.JAVA_PROJECT :
+ switch (delta.getKind()) {
+ case IResourceDelta.ADDED :
+ case IResourceDelta.OPEN:
+ indexManager.indexAll((IProject)delta.getResource());
+ break;
+ }
+ break;
+ case IJavaElement.CLASS_FILE :
+ break;
+ case IJavaElement.COMPILATION_UNIT :
+ IFile file = (IFile)delta.getResource();
+ String extension;
+ switch (delta.getKind()) {
+ case IResourceDelta.ADDED:
+ case IResourceDelta.CHANGED:
+ if (file.isLocal(IResource.DEPTH_ZERO)) indexManager.add(file);
+ break;
+ case IResourceDelta.REMOVED:
+ extension = file.getFileExtension();
+ indexManager.remove(file.getFullPath().toString(), file.getProject());
+ break;
+ }
+ }
+}
+/**
+ * Adds the given project to the cache of projects requiring classpath
+ * updates when delta translation is complete.
+ */
+protected void updateProject(IJavaProject project) {
+ if (fJavaProjectsToUpdate == null) {
+ fJavaProjectsToUpdate = new Hashtable(2);
+ }
+ fJavaProjectsToUpdate.put(project, project);
+}
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ElementCache.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ElementCache.java
new file mode 100644
index 0000000000..11cfdf8ec8
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ElementCache.java
@@ -0,0 +1,61 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.IOpenable;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.internal.core.util.LRUCache;
+
+/**
+ * An LRU cache of <code>JavaElements</code>.
+ */
+public class ElementCache extends OverflowingLRUCache {
+ /**
+ * Constructs a new element cache of the given size.
+ */
+ public ElementCache(int size) {
+ super(size);
+ }
+
+ /**
+ * Constructs a new element cache of the given size.
+ */
+ public ElementCache(int size, int overflow) {
+ super(size, overflow);
+ }
+
+ /**
+ * Returns true if the element is successfully closed and
+ * removed from the cache, otherwise false.
+ *
+ * <p>NOTE: this triggers an external removal of this element
+ * by closing the element.
+ */
+ protected boolean close(LRUCacheEntry entry) {
+ IOpenable element = (IOpenable) entry._fKey;
+ synchronized (element) {
+ try {
+ if (element.hasUnsavedChanges()) {
+ return false;
+ } else {
+ element.close();
+ return true;
+ }
+ } catch (JavaModelException npe) {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Returns a new instance of the reciever.
+ */
+ protected LRUCache newInstance(int size, int overflow) {
+ return new ElementCache(size, overflow);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/FailedReconciliationException.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/FailedReconciliationException.java
new file mode 100644
index 0000000000..0efac3a1d4
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/FailedReconciliationException.java
@@ -0,0 +1,19 @@
+package org.eclipse.jdt.internal.core;
+
+public class FailedReconciliationException extends RuntimeException {
+ /**
+ * FailReconciliationException constructor comment.
+ */
+ public FailedReconciliationException() {
+ super();
+ }
+
+ /**
+ * FailReconciliationException constructor comment.
+ * @param s java.lang.String
+ */
+ public FailedReconciliationException(String s) {
+ super(s);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/HandleFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/HandleFactory.java
new file mode 100644
index 0000000000..5c23c24f6d
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/HandleFactory.java
@@ -0,0 +1,183 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.*;
+import org.eclipse.core.runtime.*;
+import org.eclipse.core.resources.*;
+
+import org.eclipse.core.resources.*;
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.core.index.impl.*;
+
+/**
+ * Creates java element handles.
+ */
+public class HandleFactory {
+
+ private JavaModelManager manager;
+
+ /**
+ * Cache package fragment root information to optimize speed performance.
+ */
+ private String lastPkgFragmentRootPath;
+ private IPackageFragmentRoot lastPkgFragmentRoot;
+
+ /**
+ * Cache package handles to optimize memory.
+ */
+ private Hashtable packageHandles;
+
+ private IWorkspaceRoot workspaceRoot;
+
+ public HandleFactory(IWorkspaceRoot workspaceRoot, JavaModelManager manager) {
+ this.workspaceRoot = workspaceRoot;
+ this.manager = manager;
+ }
+
+ /**
+ * Creates an Openable handle from the given resource path.
+ * The resource path can be a path to a file in the workbench (eg. /Proj/com/ibm/jdt/core/HandleFactory.java)
+ * or a path to a file in a jar file - it then contains the path to the jar file and the path to the file in the jar
+ * (eg. c:/jdk1.2.2/jre/lib/rt.jar|java/lang/Object.class or c:/workbench/Proj/rt.jar|java/lang/Object.class)
+ * NOTE: This assumes that the resource path is the toString() of an IPath,
+ * i.e. it uses the IPath.SEPARATOR for file path
+ * and it uses '/' for entries in a zip file.
+ */
+ public Openable createOpenable(String resourcePath) {
+ int separatorIndex;
+ if ((separatorIndex =
+ resourcePath.indexOf(JarFileEntryDocument.JAR_FILE_ENTRY_SEPARATOR))
+ > -1) {
+ // path to a class file inside a jar
+ String jarPath = resourcePath.substring(0, separatorIndex);
+
+ // Optimization: cache package fragment root handle and package handles
+ if (!jarPath.equals(this.lastPkgFragmentRootPath)) {
+ this.lastPkgFragmentRootPath = jarPath;
+ this.lastPkgFragmentRoot = this.getJarPkgFragmentRoot(jarPath);
+ this.packageHandles = new Hashtable(5);
+ }
+
+ // create handle
+ String classFilePath = resourcePath.substring(separatorIndex + 1);
+ int lastSlash = classFilePath.lastIndexOf('/');
+ String packageName =
+ lastSlash > -1
+ ? classFilePath.substring(0, lastSlash).replace('/', '.')
+ : IPackageFragment.DEFAULT_PACKAGE_NAME;
+ IPackageFragment pkgFragment =
+ (IPackageFragment) this.packageHandles.get(packageName);
+ if (pkgFragment == null) {
+ pkgFragment = this.lastPkgFragmentRoot.getPackageFragment(packageName);
+ this.packageHandles.put(packageName, pkgFragment);
+ }
+ IClassFile classFile =
+ pkgFragment.getClassFile(classFilePath.substring(lastSlash + 1));
+ return (Openable) classFile;
+ } else {
+ // path to a file in a directory
+
+ // Optimization: cache package fragment root handle and package handles
+ int length = -1;
+ if (this.lastPkgFragmentRootPath == null
+ || !(resourcePath.startsWith(this.lastPkgFragmentRootPath)
+ && (length = this.lastPkgFragmentRootPath.length()) > 0
+ && resourcePath.charAt(length) == '/')) {
+
+ IPackageFragmentRoot root = this.getPkgFragmentRoot(resourcePath);
+ if (root == null)
+ return null; // match is outside classpath
+ this.lastPkgFragmentRoot = root;
+ this.lastPkgFragmentRootPath = this.lastPkgFragmentRoot.getPath().toString();
+ this.packageHandles = new Hashtable(5);
+ }
+
+ // create handle
+ int lastSlash = resourcePath.lastIndexOf(IPath.SEPARATOR);
+ String packageName =
+ lastSlash > (length = this.lastPkgFragmentRootPath.length())
+ ? resourcePath.substring(length + 1, lastSlash).replace(IPath.SEPARATOR, '.')
+ : IPackageFragment.DEFAULT_PACKAGE_NAME;
+ IPackageFragment pkgFragment =
+ (IPackageFragment) this.packageHandles.get(packageName);
+ if (pkgFragment == null) {
+ pkgFragment = this.lastPkgFragmentRoot.getPackageFragment(packageName);
+ this.packageHandles.put(packageName, pkgFragment);
+ }
+ String simpleName = resourcePath.substring(lastSlash + 1);
+ if (simpleName.endsWith(".java")) {
+ ICompilationUnit unit = pkgFragment.getCompilationUnit(simpleName);
+ return (Openable) unit;
+ } else {
+ IClassFile classFile = pkgFragment.getClassFile(simpleName);
+ return (Openable) classFile;
+ }
+ }
+ }
+
+ /**
+ * Returns the package fragment root that corresponds to the given jar path.
+ * See createOpenable(...) for the format of the jar path string.
+ */
+ private IPackageFragmentRoot getJarPkgFragmentRoot(String jarPathString) {
+
+ IPath jarPath = new Path(jarPathString);
+ JavaModel javaModel =
+ this.manager.getJavaModel(this.workspaceRoot.getWorkspace());
+ IResource jarFile = this.workspaceRoot.findMember(jarPath);
+ if (jarFile != null) {
+ // internal jar
+ return javaModel.getJavaProject(jarFile).getPackageFragmentRoot(jarFile);
+ } else {
+ // external jar: walk all projects and find the first one that has the given jar path in its classpath
+ try {
+ IProject[] projects = this.workspaceRoot.getProjects();
+ for (int i = 0, projectCount = projects.length; i < projectCount; i++) {
+ IProject project = projects[i];
+ if (project.isAccessible()) {
+ IJavaProject javaProject = javaModel.getJavaProject(project);
+ IClasspathEntry[] classpathEntries = javaProject.getResolvedClasspath(true);
+ for (int j = 0, entryCount = classpathEntries.length; j < entryCount; j++) {
+ if (classpathEntries[j].getPath().equals(jarPath)) {
+ return javaProject.getPackageFragmentRoot(jarPathString);
+ }
+ }
+ }
+ }
+ } catch (JavaModelException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Returns the package fragment root that contains the given resource path.
+ */
+ private IPackageFragmentRoot getPkgFragmentRoot(String pathString) {
+
+ IPath path = new Path(pathString);
+ try {
+ JavaModel javaModel =
+ this.manager.getJavaModel(this.workspaceRoot.getWorkspace());
+ IProject[] projects = this.workspaceRoot.getProjects();
+ for (int i = 0, max = projects.length; i < max; i++) {
+ IJavaProject javaProject = javaModel.getJavaProject(projects[i]);
+ IPackageFragmentRoot[] roots = javaProject.getPackageFragmentRoots();
+ for (int j = 0, rootCount = roots.length; j < rootCount; j++) {
+ IPackageFragmentRoot root = roots[j];
+ if (root.getPath().isPrefixOf(path)) {
+ return root;
+ }
+ }
+ }
+ } catch (JavaModelException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IBufferManager.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IBufferManager.java
new file mode 100644
index 0000000000..3166079b8b
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IBufferManager.java
@@ -0,0 +1,54 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.jdt.core.*;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+/**
+ * The buffer manager manages the set of open buffers.
+ */
+public interface IBufferManager {
+
+ /**
+ * Returns the open buffer associated with the given owner,
+ * or <code>null</code> if the owner does not have an open
+ * buffer associated with it.
+ */
+ IBuffer getBuffer(IOpenable owner);
+ /**
+ * Returns an enumeration of all open buffers.
+ *
+ * @return Enumeration of IBuffer
+ */
+ public Enumeration getOpenBuffers();
+ /**
+ * Opens a buffer with the given contents, not associated with any resource,
+ * assigned to the specified owner.
+ *
+ * @exception IllegalArgumentException if contents or owner is <code>null</code>
+ */
+ public IBuffer openBuffer(
+ char[] contents,
+ IProgressMonitor progress,
+ IOpenable owner,
+ boolean readOnly)
+ throws IllegalArgumentException;
+ /**
+ * Opens a buffer on the current contents of the specified file,
+ * assigned to the specified owner.
+ */
+ public IBuffer openBuffer(
+ IFile file,
+ IProgressMonitor progress,
+ IOpenable owner,
+ boolean readOnly)
+ throws JavaModelException;
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ICacheEnumeration.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ICacheEnumeration.java
new file mode 100644
index 0000000000..b1924e683e
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ICacheEnumeration.java
@@ -0,0 +1,33 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.Enumeration;
+
+/**
+ * The <code>ICacheEnumeration</code> is used to iterate over both the keys
+ * and values in an LRUCache. The <code>getValue()</code> method returns the
+ * value of the last key to be retrieved using <code>nextElement()</code>.
+ * The <code>nextElement()</code> method must be called before the
+ * <code>getValue()</code> method.
+ *
+ * <p>The iteration can be made efficient by making use of the fact that values in
+ * the cache (instances of <code>LRUCacheEntry</code>), know their key. For this reason,
+ * Hashtable lookups don't have to be made at each step of the iteration.
+ *
+ * <p>Modifications to the cache must not be performed while using the
+ * enumeration. Doing so will lead to an illegal state.
+ *
+ * @see LRUCache
+ */
+public interface ICacheEnumeration extends Enumeration {
+ /**
+ * Returns the value of the previously accessed key in the enumeration.
+ * Must be called after a call to nextElement().
+ *
+ * @return Value of current cache entry
+ */
+ public Object getValue();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IJavaElementRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IJavaElementRequestor.java
new file mode 100644
index 0000000000..8295ea517f
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IJavaElementRequestor.java
@@ -0,0 +1,30 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+
+/**
+ * This interface is used by IRequestorNameLookup. As results
+ * are found by IRequestorNameLookup, they are reported to this
+ * interface. An IJavaElementRequestor is able to cancel
+ * at any time (i.e. stop receiving results), by responding
+ * <code>true</code> to <code>#isCancelled</code>.
+ */
+public interface IJavaElementRequestor {
+ public void acceptField(IField field);
+ public void acceptInitializer(IInitializer initializer);
+ public void acceptMemberType(IType type);
+ public void acceptMethod(IMethod method);
+ public void acceptPackageFragment(IPackageFragment packageFragment);
+ public void acceptType(IType type);
+ /**
+ * Returns <code>true</code> if this IJavaElementRequestor does
+ * not want to receive any more results.
+ */
+ boolean isCanceled();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IJavaReconciler.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IJavaReconciler.java
new file mode 100644
index 0000000000..76d05e0714
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IJavaReconciler.java
@@ -0,0 +1,42 @@
+package org.eclipse.jdt.internal.core;
+
+public interface IJavaReconciler {
+ /**
+ * Reconciles a deletion of contiguous text.
+ *
+ * <p>Reports deltas for any elements added/removed from the compilation
+ * unit. If a container (<code>IParent</code>), is added/removed, deltas
+ * are not reported for any of its children - only the top level
+ * container. For example, if a type is removed, deltas are not
+ * provided for its deleted members.
+ *
+ * <p>Updates children properties and source ranges for elements
+ * in the compilation unit.
+ *
+ * <p>It is assumed that the <code>IBuffer</code> of the
+ * <code>ICompilationUnit</code> used in the creation of this
+ * <code>IncrementalReconciler</code> has already been updated with
+ * the text deletion, but the structure of the <code>ICompilationUnit</code>
+ * has not.
+ */
+ public void textDeleted(int position, int length);
+ /**
+ * Reconciles a insertion of contiguous text.
+ *
+ * <p>Reports deltas for any elements added/removed from the compilation
+ * unit. If a container (<code>IParent</code>), is added/removed, deltas
+ * are not reported for any of its children - only the top level
+ * container. For example, if a type is removed, deltas are not
+ * provided for its deleted members.
+ *
+ * <p>Updates children properties and source ranges for elements
+ * in the compilation unit.
+ *
+ * <p>It is assumed that the <code>IBuffer</code> of the
+ * <code>ICompilationUnit</code> used in the creation of this
+ * <code>IncrementalReconciler</code> has already been updated with
+ * the text deletion, but the structure of the <code>ICompilationUnit</code>
+ * has not.
+ */
+ public void textInserted(int position, int length);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/INameLookup.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/INameLookup.java
new file mode 100644
index 0000000000..55fdb4f10b
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/INameLookup.java
@@ -0,0 +1,151 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.IPath;
+
+import org.eclipse.jdt.core.*;
+
+/**
+ * <code>INameLookup</code> provides name resolution within a Java project.
+ * The name lookup facility uses the
+ * project's classpath to prioritize the order in which package
+ * fragments are searched when resolving a name.
+ *
+ * <p>Name lookup only returns a handle when the named element actually
+ * exists in the model; otherwise <code>null</code> is returned.
+ *
+ * <p>There are two logical sets of methods within this interface. Methods
+ * which start with <code>find*</code> are intended to be convenience methods for quickly
+ * finding an element within another element, i.e. finding a class within a
+ * package. The other set of methods all begin with <code>seek*</code>. These methods
+ * do comprehensive searches of the <code>IJavaProject</code> returning hits
+ * in real time through an <code>IJavaElementRequestor</code>.
+ *
+ */
+public interface INameLookup {
+ /**
+ * Accept flag for specifying classes.
+ */
+ public static final int ACCEPT_CLASSES = 0x00000002;
+ /**
+ * Accept flag for specifying interfaces.
+ */
+ public static final int ACCEPT_INTERFACES = 0x00000004;
+ /**
+ * Returns the <code>ICompilationUnit</code> which defines the type
+ * named <code>qualifiedTypeName</code>, or <code>null</code> if
+ * none exists. The domain of the search is bounded by the classpath
+ * of the <code>IJavaProject</code> this <code>INameLookup</code> was
+ * obtained from.
+ * <p>
+ * The name must be fully qualified (eg "java.lang.Object", "java.util.Hashtable$Entry")
+ */
+ ICompilationUnit findCompilationUnit(String qualifiedTypeName);
+ /**
+ * Returns the package fragment whose path matches the given
+ * (absolute) path, or <code>null</code> if none exist. The domain of
+ * the search is bounded by the classpath of the <code>IJavaProject</code>
+ * this <code>INameLookup</code> was obtained from.
+ * The path can be:
+ * - internal to the workbench: "/Project/src"
+ * - external to the workbench: "c:/jdk/classes.zip/java/lang"
+ */
+ IPackageFragment findPackageFragment(IPath path);
+ /**
+ * Returns the package fragment root whose path matches the given
+ * (absolute) path, or <code>null</code> if none exist. The domain of
+ * the search is bounded by the classpath of the <code>IJavaProject</code>
+ * this <code>INameLookup</code> was obtained from.
+ * The path can be:
+ * - internal to the workbench: "/Compiler/src"
+ * - external to the workbench: "c:/jdk/classes.zip"
+ */
+ IPackageFragmentRoot findPackageFragmentRoot(IPath path);
+ /**
+ * Returns the package fragments whose name matches the given
+ * (qualified) name, or <code>null</code> if none exist.
+ *
+ * The name can be:
+ * - empty: ""
+ * - qualified: "pack.pack1.pack2"
+ * @param partialMatch partial name matches qualify when <code>true</code>,
+ * only exact name matches qualify when <code>false</code>
+ */
+ IPackageFragment[] findPackageFragments(String name, boolean partialMatch);
+ /**
+ * Returns the first type in the given package whose name
+ * matches the given (unqualified) name, or <code>null</code> if none
+ * exist. Specifying a <code>null</code> package will result in no matches.
+ * The domain of the search is bounded by the Java project from which
+ * this name lookup was obtained.
+ *
+ * @name the name of the type to find
+ * @pkg the package to search
+ * @param partialMatch partial name matches qualify when <code>true</code>,
+ * only exact name matches qualify when <code>false</code>
+ * @param acceptFlags a bit mask describing if classes, interfaces or both classes and interfaces
+ * are desired results. If no flags are specified, all types are returned.
+ *
+ * @see ACCEPT_CLASSES
+ * @see ACCEPT_INTERFACES
+ */
+ IType findType(
+ String name,
+ IPackageFragment pkg,
+ boolean partialMatch,
+ int acceptFlags);
+ /**
+ * Returns the type specified by the qualified name, or <code>null</code>
+ * if none exist. The domain of
+ * the search is bounded by the Java project from which this name lookup was obtained.
+ *
+ * @name the name of the type to find
+ * @param partialMatch partial name matches qualify when <code>true</code>,
+ * only exact name matches qualify when <code>false</code>
+ * @param acceptFlags a bit mask describing if classes, interfaces or both classes and interfaces
+ * are desired results. If no flags are specified, all types are returned.
+ *
+ * @see ACCEPT_CLASSES
+ * @see ACCEPT_INTERFACES
+ */
+ public IType findType(String name, boolean partialMatch, int acceptFlags);
+ /**
+ * Notifies the given requestor of all package fragments with the
+ * given name. Checks the requestor at regular intervals to see if the
+ * requestor has canceled. The domain of
+ * the search is bounded by the <code>IJavaProject</code>
+ * this <code>INameLookup</code> was obtained from.
+ *
+ * @param partialMatch partial name matches qualify when <code>true</code>;
+ * only exact name matches qualify when <code>false</code>
+ */
+ public void seekPackageFragments(
+ String name,
+ boolean partialMatch,
+ IJavaElementRequestor requestor);
+ /**
+ * Notifies the given requestor of all types (classes and interfaces) in the
+ * given package fragment with the given (unqualified) name.
+ * Checks the requestor at regular intervals to see if the requestor
+ * has canceled. If the given package fragment is <code>null</code>, all types in the
+ * project whose simple name matches the given name are found.
+ *
+ * @param partialMatch partial name matches qualify when <code>true</code>;
+ * only exact name matches qualify when <code>false</code>
+ * @param acceptFlags a bit mask describing if classes, interfaces or both classes and interfaces
+ * are desired results. If no flags are specified, all types are returned.
+ *
+ * @see ACCEPT_CLASSES
+ * @see ACCEPT_INTERFACES
+ */
+ public void seekTypes(
+ String name,
+ IPackageFragment pkg,
+ boolean partialMatch,
+ int acceptFlags,
+ IJavaElementRequestor requestor);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IPathRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IPathRequestor.java
new file mode 100644
index 0000000000..8b923df3ee
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IPathRequestor.java
@@ -0,0 +1,5 @@
+package org.eclipse.jdt.internal.core;
+
+public interface IPathRequestor {
+ void acceptPath(String path);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportContainer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportContainer.java
new file mode 100644
index 0000000000..f3259fa679
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportContainer.java
@@ -0,0 +1,87 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+
+/**
+ * @see IImportContainer
+ */
+public class ImportContainer
+ extends SourceRefElement
+ implements IImportContainer {
+ protected ImportContainer(ICompilationUnit parent) {
+ super(IMPORT_CONTAINER, parent, "");
+ }
+
+ /**
+ * @see JavaElement#getHandleMemento()
+ */
+ public String getHandleMemento() {
+ return ((JavaElement) getParent()).getHandleMemento();
+ }
+
+ /**
+ * @see JavaElement#getHandleMemento()
+ */
+ protected char getHandleMementoDelimiter() {
+ throw new Error("should not be called");
+ }
+
+ /**
+ * @see IImportContainer
+ */
+ public IImportDeclaration getImport(String name) {
+ return new ImportDeclaration(this, name);
+ }
+
+ /**
+ * @see ISourceReference
+ */
+ public ISourceRange getSourceRange() throws JavaModelException {
+ IJavaElement[] imports = getChildren();
+ ISourceRange firstRange = ((ISourceReference) imports[0]).getSourceRange();
+ ISourceRange lastRange =
+ ((ISourceReference) imports[imports.length - 1]).getSourceRange();
+ SourceRange range =
+ new SourceRange(
+ firstRange.getOffset(),
+ lastRange.getOffset() + lastRange.getLength() - firstRange.getOffset());
+ return range;
+ }
+
+ /**
+ * Import containers only exist if they have children.
+ * @see IParent
+ */
+ public boolean hasChildren() throws JavaModelException {
+ return true;
+ }
+
+ /**
+ */
+ public String readableName() {
+
+ return null;
+ }
+
+ /**
+ * @private Debugging purposes
+ */
+ protected void toString(int tab, StringBuffer buffer) {
+ Object info = fgJavaModelManager.getInfo(this);
+ if (info == null || !(info instanceof JavaElementInfo))
+ return;
+ IJavaElement[] children = ((JavaElementInfo) info).getChildren();
+ for (int i = 0; i < children.length; i++) {
+ if (i > 0)
+ buffer.append("\n");
+ ((JavaElement) children[i]).toString(tab, buffer);
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportDeclaration.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportDeclaration.java
new file mode 100644
index 0000000000..36e789a412
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportDeclaration.java
@@ -0,0 +1,69 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.jdom.IDOMNode;
+
+/**
+ * @see IImportDeclaration
+ */
+
+/* package */
+class ImportDeclaration
+ extends SourceRefElement
+ implements IImportDeclaration {
+
+ /**
+ * Constructs an ImportDeclartaion in the given import container
+ * with the given name.
+ */
+ protected ImportDeclaration(IImportContainer parent, String name) {
+ super(IMPORT_DECLARATION, parent, name);
+ }
+
+ /**
+ * @see JavaElement#equalsDOMNode
+ */
+ protected boolean equalsDOMNode(IDOMNode node) throws JavaModelException {
+ return (node.getNodeType() == IDOMNode.IMPORT)
+ && getElementName().equals(node.getName());
+ }
+
+ /**
+ * @see JavaElement#getHandleMemento()
+ */
+ protected char getHandleMementoDelimiter() {
+ return JavaElement.JEM_IMPORTDECLARATION;
+ }
+
+ /**
+ * Returns true if the import is on-demand (ends with ".*")
+ */
+ public boolean isOnDemand() {
+ return fName.endsWith(".*");
+ }
+
+ /**
+ */
+ public String readableName() {
+
+ return null;
+ }
+
+ /**
+ * @private Debugging purposes
+ */
+ protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+ buffer.append("import ");
+ buffer.append(getElementName());
+ if (info == null) {
+ buffer.append(" (not open)");
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IncrementalDeterministicRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IncrementalDeterministicRequestor.java
new file mode 100644
index 0000000000..a9aa6b0aaf
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IncrementalDeterministicRequestor.java
@@ -0,0 +1,353 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.core.util.ReferenceInfoAdapter;
+
+import java.util.*;
+
+/**
+ * Handles the results of a source element parse, and with
+ * the help of the <code>Reconciler</code>, throws element
+ * changed deltas.
+ */
+public class IncrementalDeterministicRequestor
+ extends ReferenceInfoAdapter
+ implements ISourceElementRequestor {
+
+ /**
+ * The expected elements
+ */
+ protected IJavaElement[] fElements;
+
+ /**
+ * The next element expected
+ */
+ protected IJavaElement fNextElement;
+
+ /**
+ * The index of the next expected element
+ */
+ protected int fNextIndex = 0;
+
+ /**
+ * Creates a requestor
+ */
+ public IncrementalDeterministicRequestor(IJavaElement[] expectations) {
+ fElements = expectations;
+ next();
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void acceptImport(
+ int declarationStart,
+ int declarationEnd,
+ char[] name,
+ boolean onDemand) {
+ if (fNextElement.getElementType() == IJavaElement.IMPORT_DECLARATION) {
+ if (isIdentical((IImportDeclaration) fNextElement, name, onDemand)) {
+ next();
+ return;
+ }
+ }
+ throw new FailedReconciliationException();
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void acceptInitializer(
+ int modifiers,
+ int declarationSourceStart,
+ int declarationSourceEnd) {
+ if (fNextElement.getElementType() == IJavaElement.IMPORT_DECLARATION) {
+ next();
+ return;
+ }
+ throw new FailedReconciliationException();
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void acceptLineSeparatorPositions(int[] positions) {
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void acceptPackage(
+ int declarationStart,
+ int declarationEnd,
+ char[] name) {
+ if (fNextElement.getElementType() == IJavaElement.PACKAGE_DECLARATION) {
+ if (isIdentical((IPackageDeclaration) fNextElement, name)) {
+ next();
+ return;
+ }
+ }
+ throw new FailedReconciliationException();
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void acceptProblem(IProblem problem) {
+ }
+
+ /**
+ * Advances to the next expected element
+ */
+ protected void advance() {
+ if (fNextIndex < fElements.length) {
+ fNextElement = fElements[fNextIndex];
+ fNextIndex++;
+ } else {
+ fNextElement = null;
+ }
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterClass(
+ int declarationStart,
+ int modifiers,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[] superclass,
+ char[][] superinterfaces) {
+ if (fNextElement.getElementType() == IJavaElement.TYPE) {
+ if (isIdentical((IType) fNextElement, name)) {
+ next();
+ return;
+ }
+ }
+ throw new FailedReconciliationException();
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterCompilationUnit() {
+ if (fNextElement.getElementType() == IJavaElement.COMPILATION_UNIT) {
+ next();
+ return;
+ }
+ throw new FailedReconciliationException();
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterConstructor(
+ int declarationStart,
+ int modifiers,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[][] parameterTypes,
+ char[][] parameterNames,
+ char[][] exceptionTypes) {
+ if (fNextElement.getElementType() == IJavaElement.METHOD) {
+ if (isIdentical((IMethod) fNextElement, name, parameterTypes)) {
+ next();
+ return;
+ }
+ }
+ throw new FailedReconciliationException();
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterField(
+ int declarationStart,
+ int modifiers,
+ char[] type,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd) {
+ if (fNextElement.getElementType() == IJavaElement.FIELD) {
+ if (isIdentical((IField) fNextElement, name)) {
+ next();
+ return;
+ }
+ }
+ throw new FailedReconciliationException();
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterInterface(
+ int declarationStart,
+ int modifiers,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[][] superinterfaces) {
+ if (fNextElement.getElementType() == IJavaElement.TYPE) {
+ if (isIdentical((IType) fNextElement, name)) {
+ next();
+ return;
+ }
+ }
+ throw new FailedReconciliationException();
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterMethod(
+ int declarationStart,
+ int modifiers,
+ char[] returnType,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[][] parameterTypes,
+ char[][] parameterNames,
+ char[][] exceptionTypes) {
+ if (fNextElement.getElementType() == IJavaElement.METHOD) {
+ if (isIdentical((IMethod) fNextElement, name, parameterTypes)) {
+ next();
+ return;
+ }
+ }
+ throw new FailedReconciliationException();
+ }
+
+ /**
+ * Answers true if the two arguments are equal. If either are null answers false, if
+ * both are null answers true;
+ */
+ protected static final boolean equals(String string, char[] chars) {
+ if (string == null ^ chars == null)
+ return false;
+ if (string == null)
+ return true;
+ int length = chars.length;
+ if (string.length() != length)
+ return false;
+ while (length-- != 0) {
+ if (string.charAt(length) != chars[length])
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitClass(int declarationEnd) {
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitCompilationUnit(int declarationEnd) {
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitConstructor(int declarationEnd) {
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitField(int declarationEnd) {
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitInterface(int declarationEnd) {
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitMethod(int declarationEnd) {
+ }
+
+ protected boolean isIdentical(IField field, char[] name) {
+ if (!equals(field.getElementName(), name))
+ return false;
+ return true;
+ }
+
+ protected boolean isIdentical(
+ IImportDeclaration anImport,
+ char[] name,
+ boolean isOnDemand) {
+ String importString = new String(name);
+ if (isOnDemand)
+ importString += ".*";
+ if (!anImport.getElementName().equals(importString))
+ return false;
+ return true;
+ }
+
+ protected boolean isIdentical(
+ IMethod method,
+ char[] name,
+ char[][] parameterTypes) {
+ if (!equals(method.getElementName(), name))
+ return false;
+ String[] parameters = method.getParameterTypes();
+ if (parameters == null || parameters.length == 0) {
+ if (parameterTypes == null || parameterTypes.length == 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ if (parameters.length != parameterTypes.length)
+ return false;
+ for (int i = 0, length = parameters.length; i < length; i++) {
+ if (parameters[i] == null ^ parameterTypes[i] == null)
+ return false;
+ if (parameters[i] == null)
+ continue;
+ if (!parameters[i]
+ .equals(Signature.createTypeSignature(parameterTypes[i], false)))
+ return false;
+ }
+ return true;
+ }
+
+ protected boolean isIdentical(IPackageDeclaration aPackage, char[] name) {
+ if (!equals(aPackage.getElementName(), name))
+ return false;
+ return true;
+ }
+
+ protected boolean isIdentical(IType type, char[] name) {
+ if (!equals(type.getElementName(), name))
+ return false;
+ return true;
+ }
+
+ /**
+ * Advances the next element expected.
+ */
+ protected void next() {
+ advance();
+ if (fNextElement.getElementType() == IJavaElement.IMPORT_CONTAINER)
+ next();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IncrementalReconciler.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IncrementalReconciler.java
new file mode 100644
index 0000000000..5f2e0bccbb
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IncrementalReconciler.java
@@ -0,0 +1,381 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.ISourceType;
+import org.eclipse.jdt.core.*;
+
+import java.util.*;
+
+/**
+ * The <code>IncrementalReconciler</code> notifies the
+ * JavaModel of changes made the compilation unit that
+ * this reconciler watches.
+ *
+ * <p>The <code>IncrementalReconciler</code> attempts to
+ * improve the performance and functionality of the
+ * <code>Reconciler</code> by only reconciling elements
+ * which are effected by a text edit.
+ *
+ * <p>The implementation is not thread safe.
+ *
+ * <p>The API expects all text edits to have already occured
+ * in the buffer of the <code>ICompilationUnit</code>
+ * which this reconciler is using.
+ *
+ * @see Reconciler
+ */
+public class IncrementalReconciler implements IJavaReconciler {
+ /**
+ * The current compilation unit
+ */
+ protected ICompilationUnit fCompilationUnit = null;
+ /**
+ * Create a reconciler on a compilation unit
+ *
+ * @exception IllegalArgumentException if the compilation unit is not
+ * a working copy.
+ */
+ public IncrementalReconciler(ICompilationUnit cu) {
+ fCompilationUnit = cu;
+ if (!cu.isWorkingCopy()) {
+ throw new IllegalArgumentException("must create reconciler on a working copy");
+ }
+ }
+
+ /**
+ * Does a full reconcile.
+ */
+ protected void doFullReconcile() {
+ try {
+ fCompilationUnit.reconcile();
+ } catch (JavaModelException e) {
+ }
+ }
+
+ /**
+ * Answers the <code>IJavaElement</code> closest too and after the given
+ * position in the given parent, or <code>null</code> if there is no element
+ * after the given position.
+ */
+ protected IJavaElement getElementAfter(int position, IJavaElement parent) {
+ IJavaElement[] children = null;
+ try {
+ children = ((IParent) parent).getChildren();
+ } catch (JavaModelException npe) {
+ return null;
+ }
+ if (children == null)
+ return null;
+ int length = children.length;
+ if (length > 0) {
+ for (int i = 0; i < length; i++) {
+ IJavaElement child = children[i];
+ if (getSourceOffset(child) + getSourceLength(child) - 1 > position)
+ return child;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Answers the <code>IJavaElement</code> following the
+ * given element, or <code>null</code> if there is no element
+ * following the given element.
+ */
+ protected IJavaElement getElementAfter(IJavaElement element) {
+ IJavaElement[] children = null;
+ try {
+ children = ((IParent) element.getParent()).getChildren();
+ } catch (JavaModelException npe) {
+ return null;
+ }
+ if (children == null)
+ return null;
+ int length = children.length;
+ if (length > 0) {
+ for (int i = 0; i < length; i++) {
+ IJavaElement child = children[i];
+ if (child.equals(element) && i < length - 1)
+ return children[i + 1];
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Answers the <code>IJavaElement</code> closest too and before the given
+ * position in the given parent, or <code>null</code> if there is no element
+ * before the given position.
+ */
+ protected IJavaElement getElementBefore(int position, IJavaElement parent) {
+ IJavaElement[] children = null;
+ try {
+ children = ((IParent) parent).getChildren();
+ } catch (JavaModelException npe) {
+ return null;
+ }
+ if (children == null)
+ return null;
+ int length = children.length;
+ if (length > 0) {
+ for (int i = length - 1; i >= 0; i--) {
+ IJavaElement child = children[i];
+ if (getSourceOffset(child) + getSourceLength(child) - 1 < position)
+ return child;
+ }
+ }
+ return null;
+ }
+
+ /**
+ *
+ */
+ protected IJavaElement[] getElementsBetween(
+ IJavaElement first,
+ IJavaElement last) {
+ if (first.equals(last)) {
+ return new IJavaElement[] { first };
+ }
+
+ IJavaElement[] children = null;
+ IParent parent = (IParent) first.getParent();
+ Vector elements = new Vector();
+
+ try {
+ children = ((IParent) parent).getChildren();
+ } catch (JavaModelException npe) {
+ return null;
+ }
+ if (children == null)
+ return null;
+
+ boolean inside = false;
+ for (int i = 0; i < children.length; i++) {
+ IJavaElement child = children[i];
+ if (inside) {
+ elements.addElement(child);
+ if (child.equals(last)) {
+ inside = false;
+ break;
+ }
+ } else {
+ if (child.equals(first)) {
+ inside = true;
+ elements.addElement(child);
+ }
+ }
+ }
+
+ IJavaElement[] array = new IJavaElement[elements.size()];
+ elements.copyInto(array);
+ return array;
+ }
+
+ /**
+ * Answers the closest enclosing type of the element
+ */
+ protected IType getEnclosingType(IJavaElement element) {
+ IJavaElement parent = element.getParent();
+ while (parent != null && !(parent.getElementType() == IJavaElement.TYPE))
+ parent = parent.getParent();
+ return (IType) parent;
+ }
+
+ /**
+ * Returns the source length of the element or
+ * 0 if the element is not present or not a source element.
+ */
+ protected int getSourceLength(IJavaElement element) {
+ if (element instanceof SourceRefElement) {
+ try {
+ return ((SourceRefElement) element).getSourceRange().getLength();
+ } catch (JavaModelException npe) {
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Returns the source offset of the element or
+ * -1 if the element is not present or not a source element.
+ */
+ protected int getSourceOffset(IJavaElement element) {
+ if (element instanceof SourceRefElement) {
+ try {
+ return ((SourceRefElement) element).getSourceRange().getOffset();
+ } catch (JavaModelException npe) {
+ }
+ }
+ return -1;
+ }
+
+ protected boolean isWhitespace(int position, int length) {
+ int end = position + length;
+ try {
+ IBuffer buffer = fCompilationUnit.getBuffer();
+ for (int i = position; i < end; i++) {
+ if (!Character.isWhitespace(buffer.getChar(i)))
+ return false;
+ }
+ return true;
+ } catch (JavaModelException npe) {
+ return false;
+ }
+ }
+
+ protected void reconcile(
+ SourceType type,
+ IncrementalDeterministicRequestor requestor,
+ int start,
+ int end) {
+ SourceElementParser parser =
+ new SourceElementParser(requestor, new ProblemFactory());
+ try {
+ if (type != null) {
+ try {
+ parser.parseTypeMemberDeclarations(
+ (ISourceType) type.getElementInfo(),
+ (CompilationUnit) fCompilationUnit,
+ start,
+ end,
+ false);
+ } catch (JavaModelException npe) {
+ doFullReconcile();
+ return;
+ }
+ } else {
+ parser.parseCompilationUnit(
+ (CompilationUnit) fCompilationUnit,
+ start,
+ end,
+ false);
+ }
+ } catch (FailedReconciliationException fre) {
+ doFullReconcile();
+ return;
+ }
+ System.out.println("Did incremental");
+ }
+
+ /**
+ * @see IReconciler
+ */
+ public void textDeleted(int position, int length) {
+ doFullReconcile();
+ if (true) {
+ return;
+ }
+ try {
+ if (isWhitespace(position, length)) {
+ System.out.println("Whitespace");
+ return;
+ }
+
+ int endPosition = position + length;
+ IJavaElement first = fCompilationUnit.getElementAt(position);
+ IJavaElement last = fCompilationUnit.getElementAt(endPosition);
+
+ if (first == last) {
+ if (first == null) {
+ first = fCompilationUnit;
+ last = fCompilationUnit;
+ }
+ } else {
+ doFullReconcile();
+ return;
+ }
+
+ if (first instanceof IParent) {
+ first = getElementBefore(position, first);
+ last = getElementAfter(endPosition, last);
+ }
+
+ if (first != last) {
+ doFullReconcile();
+ return;
+ }
+
+ int offset = getSourceOffset(first);
+ int end = offset + getSourceLength(first) - length;
+
+ if (end <= offset) {
+ doFullReconcile();
+ return;
+ }
+
+ SourceType type = (SourceType) getEnclosingType(first);
+
+ IncrementalDeterministicRequestor requestor =
+ new IncrementalDeterministicRequestor(new IJavaElement[] { first });
+ reconcile(type, requestor, offset, end);
+ } catch (JavaModelException e) {
+ return;
+ }
+ }
+
+ /**
+ * @see IReconciler
+ */
+ public void textInserted(int position, int length) {
+ doFullReconcile();
+ if (true) {
+ return;
+ }
+ try {
+ if (isWhitespace(position, length)) {
+ System.out.println("Whitespace");
+ return;
+ }
+
+ IJavaElement element = fCompilationUnit.getElementAt(position);
+ IJavaElement first = null, last = null;
+
+ if (element == null)
+ element = fCompilationUnit;
+
+ if (element instanceof IParent) {
+ first = getElementBefore(position, element);
+ last = getElementAfter(position, element);
+ } else {
+ if (position == getSourceOffset(element)) {
+ first = getElementBefore(position, element.getParent());
+ last = element;
+ } else {
+ first = element;
+ last = getElementAfter(element);
+ }
+ }
+
+ if (first == null || last == null) {
+ doFullReconcile();
+ return;
+ }
+
+ int offset = getSourceOffset(first);
+ int end = offset + getSourceLength(last) + length - 1;
+
+ if (end <= offset) {
+ doFullReconcile();
+ return;
+ }
+
+ SourceType type = (SourceType) getEnclosingType(first);
+ // parse the new text, hoping for the same elements
+ IncrementalDeterministicRequestor requestor =
+ new IncrementalDeterministicRequestor(new IJavaElement[] { first, last });
+
+ reconcile(type, requestor, offset, end);
+
+ } catch (JavaModelException e) {
+ return;
+ }
+
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IncrementalReconcilerRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IncrementalReconcilerRequestor.java
new file mode 100644
index 0000000000..b5c0b8fecc
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IncrementalReconcilerRequestor.java
@@ -0,0 +1,489 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.core.util.ReferenceInfoAdapter;
+
+import java.util.*;
+
+/**
+ * Handles the results of a source element parse, and with
+ * the help of the <code>Reconciler</code>, throws element
+ * changed deltas.
+ */
+public class IncrementalReconcilerRequestor
+ extends ReferenceInfoAdapter
+ implements ISourceElementRequestor {
+ /**
+ * The compilation unit the reconciler is working on
+ */
+ protected ICompilationUnit fCompilationUnit;
+
+ /**
+ * The last expected element
+ */
+ protected IJavaElement fLastElement;
+
+ /**
+ * As the compilation unit is traversed, this stack
+ * maintains lists of children and positions in the list
+ */
+ protected Stack fStack;
+
+ /**
+ * The next element expected from the parser.
+ */
+ protected IJavaElement fNextElement;
+
+ /**
+ * A helper class which stores children and array position information
+ */
+ class TraversalInfo {
+ protected IJavaElement[] fArray;
+ protected int fLength;
+ protected int fPosition;
+ protected boolean fIsType;
+ protected String fParentName;
+ protected int fInitializerCount;
+
+ public TraversalInfo(IJavaElement[] array, String parentName, boolean isType) {
+ fArray = array;
+ fParentName = parentName;
+ fIsType = isType;
+ fLength = (fArray != null) ? fArray.length : 0;
+ fPosition = 0;
+ fInitializerCount = 0;
+ }
+ public IJavaElement next() {
+ if (fPosition < fLength)
+ return fArray[fPosition++];
+ return null;
+ }
+ public String getParentName() {
+ return fParentName;
+ }
+ public int getNextInitializer() {
+ return ++fInitializerCount;
+ }
+ public int getInitializerCount() {
+ return fInitializerCount;
+ }
+ public boolean isType() {
+ return fIsType;
+ }
+ }
+
+ /**
+ * Creates a requestor
+ */
+ public IncrementalReconcilerRequestor(
+ ICompilationUnit cu,
+ IJavaElement first,
+ IJavaElement last) {
+ fCompilationUnit = cu;
+ fStack = new Stack();
+ initializeStack();
+ advanceTo(first);
+ fLastElement = last;
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void acceptImport(
+ int declarationStart,
+ int declarationEnd,
+ char[] name,
+ boolean onDemand) {
+ if (fNextElement.getElementType() == IJavaElement.IMPORT_DECLARATION) {
+ if (isIdentical((IImportDeclaration) fNextElement, name, onDemand)) {
+ next();
+ return;
+ }
+ }
+ throw new FailedReconciliationException();
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void acceptInitializer(
+ int modifiers,
+ int declarationSourceStart,
+ int declarationSourceEnd) {
+ if (fNextElement.getElementType() == IJavaElement.IMPORT_DECLARATION) {
+ next();
+ return;
+ }
+ throw new FailedReconciliationException();
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void acceptLineSeparatorPositions(int[] positions) {
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void acceptPackage(
+ int declarationStart,
+ int declarationEnd,
+ char[] name) {
+ if (fNextElement.getElementType() == IJavaElement.PACKAGE_DECLARATION) {
+ if (isIdentical((IPackageDeclaration) fNextElement, name)) {
+ next();
+ return;
+ }
+ }
+ throw new FailedReconciliationException();
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void acceptProblem(IProblem problem) {
+ }
+
+ /**
+ * Advances to the next expected element
+ */
+ protected void advance() {
+ if (!fStack.empty()) {
+ TraversalInfo info = (TraversalInfo) fStack.peek();
+ fNextElement = info.next();
+ if (fNextElement == null) {
+ fStack.pop();
+ next();
+ return;
+ } else {
+ if (fNextElement instanceof IParent)
+ push(fNextElement);
+ }
+ } else {
+ fNextElement = null;
+ }
+ }
+
+ /**
+ * Advances to the given element.
+ */
+ protected void advanceTo(IJavaElement element) {
+ while (fNextElement != element)
+ advance();
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterClass(
+ int declarationStart,
+ int modifiers,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[] superclass,
+ char[][] superinterfaces) {
+ if (fNextElement.getElementType() == IJavaElement.TYPE) {
+ if (isIdentical((IType) fNextElement, name)) {
+ next();
+ return;
+ }
+ }
+ throw new FailedReconciliationException();
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterCompilationUnit() {
+ if (fNextElement.getElementType() == IJavaElement.COMPILATION_UNIT) {
+ next();
+ return;
+ }
+ throw new FailedReconciliationException();
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterConstructor(
+ int declarationStart,
+ int modifiers,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[][] parameterTypes,
+ char[][] parameterNames,
+ char[][] exceptionTypes) {
+ if (fNextElement.getElementType() == IJavaElement.METHOD) {
+ if (isIdentical((IMethod) fNextElement, name, parameterTypes)) {
+ next();
+ return;
+ }
+ }
+ throw new FailedReconciliationException();
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterField(
+ int declarationStart,
+ int modifiers,
+ char[] type,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd) {
+ if (fNextElement.getElementType() == IJavaElement.FIELD) {
+ if (isIdentical((IField) fNextElement, name)) {
+ next();
+ return;
+ }
+ }
+ throw new FailedReconciliationException();
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterInterface(
+ int declarationStart,
+ int modifiers,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[][] superinterfaces) {
+ if (fNextElement.getElementType() == IJavaElement.TYPE) {
+ if (isIdentical((IType) fNextElement, name)) {
+ next();
+ return;
+ }
+ }
+ throw new FailedReconciliationException();
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterMethod(
+ int declarationStart,
+ int modifiers,
+ char[] returnType,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[][] parameterTypes,
+ char[][] parameterNames,
+ char[][] exceptionTypes) {
+ if (fNextElement.getElementType() == IJavaElement.METHOD) {
+ if (isIdentical((IMethod) fNextElement, name, parameterTypes)) {
+ next();
+ return;
+ }
+ }
+ throw new FailedReconciliationException();
+ }
+
+ /**
+ * Answers true if the two arguments are equal. If either are null answers false, if
+ * both are null answers true;
+ */
+ protected static final boolean equals(String string, char[] chars) {
+ if (string == null ^ chars == null)
+ return false;
+ if (string == null)
+ return true;
+ int length = chars.length;
+ if (string.length() != length)
+ return false;
+ while (length-- != 0) {
+ if (string.charAt(length) != chars[length])
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitClass(int declarationEnd) {
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitCompilationUnit(int declarationEnd) {
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitConstructor(int declarationEnd) {
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitField(int declarationEnd) {
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitInterface(int declarationEnd) {
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitMethod(int declarationEnd) {
+ }
+
+ /**
+ * Returns the first type encountered on the top of the stack
+ */
+ protected IType getCurrentType() {
+ IType type = null;
+ for (int i = 0, length = fStack.size(); i < length; i++) {
+ TraversalInfo info = (TraversalInfo) fStack.elementAt(i);
+ if (info.isType()) {
+ if (type == null) {
+ type = fCompilationUnit.getType(info.getParentName());
+ } else {
+ type = type.getType(info.getParentName());
+ }
+ }
+ }
+ return type;
+ }
+
+ /**
+ * Answers the next initializer number for the current type
+ */
+ protected int getNextInitializerNumber() {
+ // reverse traversal intentional
+ for (int i = fStack.size() - 1; i >= 0; i--) {
+ }
+ return -1;
+ }
+
+ /**
+ * Initializes the stack to contain <code>fCompilationUnit</code>
+ */
+ protected void initializeStack() {
+ IJavaElement[] elements = { fCompilationUnit };
+ fStack.push(new TraversalInfo(elements, null, false));
+ next();
+ }
+
+ protected boolean isIdentical(IField field, char[] name) {
+ if (!equals(field.getElementName(), name))
+ return false;
+ return true;
+ }
+
+ protected boolean isIdentical(
+ IImportDeclaration anImport,
+ char[] name,
+ boolean isOnDemand) {
+ String importString = new String(name);
+ if (isOnDemand)
+ importString += ".*";
+ if (!anImport.getElementName().equals(importString))
+ return false;
+ return true;
+ }
+
+ protected boolean isIdentical(
+ IMethod method,
+ char[] name,
+ char[][] parameterTypes) {
+ if (!equals(method.getElementName(), name))
+ return false;
+ String[] parameters = method.getParameterTypes();
+ if (parameters == null || parameters.length == 0) {
+ if (parameterTypes == null || parameterTypes.length == 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ if (parameters.length != parameterTypes.length)
+ return false;
+ for (int i = 0, length = parameters.length; i < length; i++) {
+ if (parameters[i] == null ^ parameterTypes[i] == null)
+ return false;
+ if (parameters[i] == null)
+ continue;
+ if (!parameters[i]
+ .equals(Signature.createTypeSignature(parameterTypes[i], false)))
+ return false;
+ }
+ return true;
+ }
+
+ protected boolean isIdentical(IPackageDeclaration aPackage, char[] name) {
+ if (!equals(aPackage.getElementName(), name))
+ return false;
+ return true;
+ }
+
+ protected boolean isIdentical(IType type, char[] name) {
+ if (!equals(type.getElementName(), name))
+ return false;
+ return true;
+ }
+
+ /**
+ * Advances the next element expected.
+ */
+ protected void next() {
+ advance();
+ if (fNextElement.getElementType() == IJavaElement.IMPORT_CONTAINER)
+ next();
+ }
+
+ /**
+ * Pushes the children of the container on the stack
+ */
+ protected void push(IJavaElement element) {
+ IParent parent = (IParent) element;
+ boolean hasChildren = false;
+ try {
+ hasChildren = parent.hasChildren();
+ } catch (JavaModelException npe) {
+ }
+ if (hasChildren) {
+ IJavaElement[] children = null;
+ try {
+ children = parent.getChildren();
+ } catch (JavaModelException npe) {
+ }
+ if (children != null) {
+ TraversalInfo info =
+ new TraversalInfo(
+ children,
+ element.getElementName(),
+ element.getElementType() == IJavaElement.TYPE);
+ fStack.push(info);
+ }
+ }
+ }
+
+ /**
+ * Updates the source ranges of the elements which weren't effected by
+ * the parse, but follow the parsed elements.
+ */
+ void updateSourceRanges() {
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Initializer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Initializer.java
new file mode 100644
index 0000000000..81f9bb6322
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Initializer.java
@@ -0,0 +1,98 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.jdom.IDOMInitializer;
+import org.eclipse.jdt.core.jdom.IDOMNode;
+
+/**
+ * @see IInitializer
+ */
+
+/* package */
+class Initializer extends Member implements IInitializer {
+
+ protected Initializer(IType parent, int occurrenceCount) {
+ super(INITIALIZER, parent, "");
+ // 0 is not valid: this first occurrence is occurrence 1.
+ if (occurrenceCount <= 0)
+ throw new IllegalArgumentException();
+ fOccurrenceCount = occurrenceCount;
+ }
+
+ /**
+ * @see JavaElement#equalsDOMNode
+ */
+ protected boolean equalsDOMNode(IDOMNode node) throws JavaModelException {
+ if (node.getNodeType() == IDOMNode.INITIALIZER) {
+ IDOMInitializer i = (IDOMInitializer) node;
+ return node.getContents().trim().equals(getSource());
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @see JavaElement#getHandleMemento()
+ */
+ public String getHandleMemento() {
+ StringBuffer buff =
+ new StringBuffer(((JavaElement) getParent()).getHandleMemento());
+ buff.append(getHandleMementoDelimiter());
+ buff.append(fOccurrenceCount);
+ return buff.toString();
+ }
+
+ /**
+ * @see JavaElement#getHandleMemento()
+ */
+ protected char getHandleMementoDelimiter() {
+ return JavaElement.JEM_INITIALIZER;
+ }
+
+ public int hashCode() {
+ return Util.combineHashCodes(fParent.hashCode(), fOccurrenceCount);
+ }
+
+ /**
+ */
+ public String readableName() {
+
+ return ((JavaElement) getDeclaringType()).readableName();
+ }
+
+ /**
+ * @see ISourceManipulation
+ */
+ public void rename(String name, boolean force, IProgressMonitor monitor)
+ throws JavaModelException {
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, this));
+ }
+
+ /**
+ * @private Debugging purposes
+ */
+ protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+ if (info == null) {
+ buffer.append("<initializer>");
+ buffer.append(" (not open)");
+ } else {
+ try {
+ if (Flags.isStatic(this.getFlags())) {
+ buffer.append("static ");
+ }
+ buffer.append("initializer");
+ } catch (JavaModelException e) {
+ buffer.append("<JavaModelException in toString of " + getElementName());
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/InitializerElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/InitializerElementInfo.java
new file mode 100644
index 0000000000..6e7a34be7d
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/InitializerElementInfo.java
@@ -0,0 +1,14 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+/**
+ * Element info for IInitializer elements.
+ */
+/* package */
+class InitializerElementInfo extends MemberElementInfo {
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryFile.java
new file mode 100644
index 0000000000..ff47e72c5c
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryFile.java
@@ -0,0 +1,74 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.core.*;
+
+import java.io.*;
+import java.util.zip.*;
+
+/**
+ * A jar entry that represents a non-java resource found in a JAR.
+ *
+ * @see IStorage
+ */
+public class JarEntryFile extends PlatformObject implements IStorage {
+ private String entryName;
+ private String zipName;
+ private IPath path;
+
+ public JarEntryFile(String entryName, String zipName) {
+ this.entryName = entryName;
+ this.zipName = zipName;
+ this.path = new Path(this.entryName);
+ }
+
+ public InputStream getContents() throws CoreException {
+
+ try {
+ ZipFile zipFile = new ZipFile(this.zipName);
+ ZipEntry zipEntry = zipFile.getEntry(this.entryName);
+ if (zipEntry == null) {
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, this.entryName));
+ }
+ return zipFile.getInputStream(zipEntry);
+ } catch (IOException e) {
+ throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
+ }
+ }
+
+ /**
+ * @see IStorage#getFullPath
+ */
+ public IPath getFullPath() {
+ return this.path;
+ }
+
+ /**
+ * @see IStorage#getName
+ */
+ public String getName() {
+ return this.path.lastSegment();
+ }
+
+ /**
+ * @see IStorage#isReadOnly()
+ */
+ public boolean isReadOnly() {
+ return true;
+ }
+
+ /**
+ * @see IStorage#isReadOnly()
+ */
+ public String toString() {
+ return "JarEntryFile[" + this.zipName + "::" + this.entryName + "]";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragment.java
new file mode 100644
index 0000000000..3857d6843b
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragment.java
@@ -0,0 +1,160 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.core.*;
+
+import java.util.*;
+import java.util.zip.*;
+
+/**
+ * A package fragment that represents a package fragment found in a JAR.
+ *
+ * @see IPackageFragment
+ */
+class JarPackageFragment extends PackageFragment {
+ /**
+ * Constructs a package fragment that is contained within a jar or a zip.
+ */
+ protected JarPackageFragment(IPackageFragmentRoot root, String name) {
+ super(root, name);
+ }
+
+ /**
+ * Compute the children of this package fragment. Children of jar package fragments
+ * can only be IClassFile (representing .class files).
+ */
+ protected boolean computeChildren(OpenableElementInfo info) {
+ Vector vChildren = new Vector();
+ JarPackageFragmentInfo jInfo = (JarPackageFragmentInfo) info;
+ for (Enumeration e = jInfo.fEntryNames.elements(); e.hasMoreElements();) {
+ String child = (String) e.nextElement();
+ IClassFile classFile = getClassFile(child);
+ vChildren.addElement(classFile);
+ }
+ vChildren.trimToSize();
+ IJavaElement[] children = new IJavaElement[vChildren.size()];
+ vChildren.copyInto(children);
+ info.setChildren(children);
+ return true;
+ }
+
+ /**
+ * Compute all the non-java resources according to the entry name found in the jar file.
+ */
+ /* package */
+ void computeNonJavaResources(
+ String[] resNames,
+ JarPackageFragmentInfo info,
+ String zipName) {
+ if (resNames == null) {
+ info.setNonJavaResources(null);
+ return;
+ }
+ int max = resNames.length;
+ Object[] res = new Object[max];
+ for (int i = 0; i < max; i++) {
+ res[i] = new JarEntryFile(resNames[i], zipName);
+ }
+ info.setNonJavaResources(res);
+ }
+
+ /**
+ * Returns true if this fragment contains at least one java resource.
+ * Returns false otherwise.
+ */
+ public boolean containsJavaResources() throws JavaModelException {
+ return ((JarPackageFragmentInfo) getElementInfo()).containsJavaResources();
+ }
+
+ /**
+ * @see IPackageFragment
+ */
+ public ICompilationUnit createCompilationUnit(
+ String name,
+ String contents,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this));
+ }
+
+ /**
+ * @see JavaElement
+ */
+ protected OpenableElementInfo createElementInfo() {
+ return new JarPackageFragmentInfo();
+ }
+
+ /**
+ * @see IPackageFragment
+ */
+ public IClassFile[] getClassFiles() throws JavaModelException {
+ Vector v = getChildrenOfType(CLASS_FILE);
+ IClassFile[] array = new IClassFile[v.size()];
+ v.copyInto(array);
+ return array;
+ }
+
+ /**
+ * A jar package fragment never contains compilation units.
+ * @see IPackageFragment
+ */
+ public ICompilationUnit[] getCompilationUnits() throws JavaModelException {
+ return fgEmptyCompilationUnitList;
+ }
+
+ /**
+ * A package fragment in a jar has no corresponding resource.
+ *
+ * @see IJavaElement
+ */
+ public IResource getCorrespondingResource() throws JavaModelException {
+ return null;
+ }
+
+ /**
+ * Returns an array of non-java resources contained in the receiver.
+ */
+ public Object[] getNonJavaResources() throws JavaModelException {
+ if (this.isDefaultPackage()) {
+ // We don't want to show non java resources of the default package (see PR #1G58NB8)
+ return JavaElementInfo.NO_NON_JAVA_RESOURCES;
+ } else {
+ return this.storedNonJavaResources();
+ }
+ }
+
+ /**
+ * Jars and jar entries are all read only
+ */
+ public boolean isReadOnly() {
+ return true;
+ }
+
+ /**
+ * @see Openable#openWhenClosed()
+ */
+ protected void openWhenClosed(IProgressMonitor pm) throws JavaModelException {
+ // Open my jar
+ getOpenableParent().open(pm);
+ }
+
+ /**
+ * A package fragment in an archive cannot refresh its children.
+ */
+ public void refreshChildren() {
+ // do nothing
+ }
+
+ protected Object[] storedNonJavaResources() throws JavaModelException {
+ return ((JarPackageFragmentInfo) getElementInfo()).getNonJavaResources();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentInfo.java
new file mode 100644
index 0000000000..ae7f9e2487
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentInfo.java
@@ -0,0 +1,45 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.CoreException;
+
+import java.util.Vector;
+import java.util.Enumeration;
+
+/**
+ * Element info for JarPackageFragments. Caches the zip entry names
+ * of the types (.class files) of the JarPackageFragment. The entries
+ * are used to compute the children of the JarPackageFragment.
+ */
+class JarPackageFragmentInfo extends PackageFragmentInfo {
+ /**
+ * The names of the zip entries that are the class files associated
+ * with this package fragment info in the JAR file of the JarPackageFragmentRootInfo.
+ */
+ protected Vector fEntryNames = new Vector();
+ /**
+ */
+ boolean containsJavaResources() {
+ return fEntryNames.size() != 0;
+ }
+
+ /**
+ * Returns an array of non-java resources contained in the receiver.
+ */
+ Object[] getNonJavaResources() {
+ return fNonJavaResources;
+ }
+
+ /**
+ * Set the names of the zip entries that are the types associated
+ * with this package fragment info in the JAR file of the JarPackageFragmentRootInfo.
+ */
+ protected void setEntryNames(Vector entries) {
+ fEntryNames = entries;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java
new file mode 100644
index 0000000000..1e2b1f361e
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java
@@ -0,0 +1,661 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.*;
+import org.eclipse.core.resources.*;
+import org.eclipse.jdt.core.*;
+
+import java.io.*;
+import java.util.*;
+import java.util.zip.*;
+
+/**
+ * A package fragment root that corresponds to a .jar or .zip.
+ *
+ * <p>NOTE: The only visible entries from a .jar or .zip package fragment root
+ * are .class files.
+ * <p>NOTE: A jar package fragment root may or may not have an associated resource.
+ *
+ * @see IPackageFragmentRoot
+ * @see JarPackageFragmentRootInfo
+ */
+public class JarPackageFragmentRoot extends PackageFragmentRoot {
+ /**
+ * The absolute path to the jar file.
+ */
+ protected IPath fJarPath= null;
+
+ /**
+ * The delimiter between the zip path and source path in the
+ * attachment server property.
+ */
+ protected final static char ATTACHMENT_PROPERTY_DELIMITER= '*';
+
+ /**
+ * The name of the meta-inf directory not to be included as a
+ * jar package fragment.
+ * @see #computeJarChildren
+ */
+ //protected final static String META_INF_NAME = "META-INF/";
+ /**
+ * Constructs a package fragment root which is the root of the Java package directory hierarchy
+ * based on a JAR file that is not contained in a <code>IJavaProject</code> and
+ * does not have an associated <code>IResource</code>.
+ */
+ protected JarPackageFragmentRoot(String jarPath, IJavaProject project) {
+ super(null, project, jarPath);
+ fJarPath= new Path(jarPath);
+ }
+ /**
+ * Constructs a package fragment root which is the root of the Java package directory hierarchy
+ * based on a JAR file.
+ */
+ protected JarPackageFragmentRoot(IResource resource, IJavaProject project) {
+ super(resource, project);
+ fJarPath= resource.getFullPath();
+ }
+ /**
+ * @see IPackageFragmentRoot
+ */
+ public void attachSource(IPath zipPath, IPath rootPath, IProgressMonitor monitor) throws JavaModelException {
+ QualifiedName qName= getSourceAttachmentPropertyName();
+ try {
+ verifyAttachSource(zipPath);
+ if (monitor != null) {
+ monitor.beginTask("Attaching source...", 2);
+ }
+ SourceMapper mapper= null;
+ SourceMapper oldMapper= getSourceMapper();
+ IWorkspace workspace= getJavaModel().getWorkspace();
+ boolean rootNeedsToBeClosed= false;
+
+ if (zipPath == null) {
+ //source being detached
+ rootNeedsToBeClosed= true;
+ /* Disable deltas (see 1GDTUSD)
+ // fire a delta to notify the UI about the source detachement.
+ JavaModelManager manager = (JavaModelManager) JavaModelManager.getJavaModelManager();
+ JavaModel model = (JavaModel) getJavaModel();
+ JavaElementDelta attachedSourceDelta = new JavaElementDelta(model);
+ attachedSourceDelta .sourceDetached(this); // this would be a JarPackageFragmentRoot
+ manager.registerResourceDelta(attachedSourceDelta );
+ manager.fire(); // maybe you want to fire the change later. Let us know about it.
+ */
+ } else {
+ /*
+ // fire a delta to notify the UI about the source attachement.
+ JavaModelManager manager = (JavaModelManager) JavaModelManager.getJavaModelManager();
+ JavaModel model = (JavaModel) getJavaModel();
+ JavaElementDelta attachedSourceDelta = new JavaElementDelta(model);
+ attachedSourceDelta .sourceAttached(this); // this would be a JarPackageFragmentRoot
+ manager.registerResourceDelta(attachedSourceDelta );
+ manager.fire(); // maybe you want to fire the change later. Let us know about it.
+ */
+ String rootPathString= null;
+ if (rootPath == null) {
+ rootPath= new Path(IPackageFragmentRoot.DEFAULT_PACKAGEROOT_PATH);
+ }
+
+ //check if different from the current attachment
+ IPath storedZipPath= getSourceAttachmentPath();
+ IPath storedRootPath= getSourceAttachmentRootPath();
+ if (monitor != null) {
+ monitor.worked(1);
+ }
+ if (storedZipPath != null) {
+ if (!(storedZipPath.equals(zipPath) && rootPath.equals(storedRootPath))) {
+ rootNeedsToBeClosed= true;
+ }
+ }
+ if ((zipPath.isAbsolute() && workspace.getRoot().findMember(zipPath) != null) || !zipPath.isAbsolute()) {
+ // internal to the workbench
+ // a resource
+ IResource zipFile= workspace.getRoot().findMember(zipPath);
+ if (zipFile == null) {
+ if (monitor != null) {
+ monitor.done();
+ }
+ throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, zipPath));
+ }
+ if (!(zipFile.getType() == IResource.FILE)) {
+ if (monitor != null) {
+ monitor.done();
+ }
+ throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, zipPath));
+ }
+ }
+ mapper= new SourceMapper(zipPath, rootPath.toOSString(), (JavaModel) getJavaModel());
+ }
+ setSourceMapper(mapper);
+ if (zipPath == null) {
+ //remove the property
+ getWorkspace().getRoot().setPersistentProperty(qName, null);
+ } else {
+ //set the property to the path of the mapped zip
+ getWorkspace().getRoot().setPersistentProperty(qName, zipPath.toString() + ATTACHMENT_PROPERTY_DELIMITER + rootPath.toString());
+ }
+ if (rootNeedsToBeClosed) {
+ if (oldMapper != null) {
+ oldMapper.close();
+ }
+ IBufferManager manager= BufferManager.getDefaultBufferManager();
+ Enumeration openBuffers= manager.getOpenBuffers();
+ while (openBuffers.hasMoreElements()) {
+ IBuffer buffer= (IBuffer) openBuffers.nextElement();
+ IOpenable possibleJarMember= buffer.getOwner();
+ if (isAncestorOf((IJavaElement) possibleJarMember)) {
+ buffer.close();
+ }
+ }
+ if (monitor != null) {
+ monitor.worked(1);
+ }
+ }
+ } catch (JavaModelException e) {
+ try {
+ getWorkspace().getRoot().setPersistentProperty(qName, null); // loose info - will be recomputed
+ } catch(CoreException ce){
+ }
+ throw e;
+ } catch (CoreException rae) {
+ try {
+ getWorkspace().getRoot().setPersistentProperty(qName, null); // loose info - will be recomputed
+ } catch(CoreException ce){
+ }
+ throw new JavaModelException(rae);
+ } finally {
+ if (monitor != null) {
+ monitor.done();
+ }
+ }
+ }
+ /**
+ * Close the associated JAR file stored in the info of this element. If
+ * this jar has an associated ZIP source attachment, close it too.
+ *
+ * @see IOpenable
+ */
+ protected void closing(Object info) throws JavaModelException {
+ SourceMapper mapper= getSourceMapper();
+ if (mapper != null) {
+ mapper.close();
+ }
+ super.closing(info);
+ }
+ /**
+ * Compute the package fragment children of this package fragment root.
+ * These are all of the directory zip entries, and any directories implied
+ * by the path of class files contained in the jar of this package fragment root.
+ * Has the side effect of opening the package fragment children.
+ */
+ protected boolean computeChildren(OpenableElementInfo info) throws JavaModelException {
+ Vector vChildren= new Vector();
+ computeJarChildren((JarPackageFragmentRootInfo) info, vChildren);
+ IJavaElement[] children= new IJavaElement[vChildren.size()];
+ vChildren.copyInto(children);
+ info.setChildren(children);
+ return true;
+ }
+/**
+ * Determine all of the package fragments associated with this package fragment root.
+ * Cache the zip entries for each package fragment in the info for the package fragment.
+ * The package fragment children are all opened.
+ * Add all of the package fragments to vChildren.
+ *
+ * @exception JavaModelException The resource (the jar) associated with this package fragment root does not exist
+ */
+protected void computeJarChildren(JarPackageFragmentRootInfo info, Vector vChildren) throws JavaModelException {
+ ZipFile jar= null;
+ try {
+ jar= getJar();
+ Hashtable packageFragToTypes= new Hashtable();
+
+ // always create the default package
+ packageFragToTypes.put(IPackageFragment.DEFAULT_PACKAGE_NAME, new Vector[] { new Vector(), new Vector()
+ });
+
+ Vector[] temp;
+ for (Enumeration e= jar.entries(); e.hasMoreElements();) {
+ ZipEntry member= (ZipEntry) e.nextElement();
+ String eName= member.getName();
+ if (member.isDirectory()) {
+ eName= eName.substring(0, eName.length() - 1);
+ eName= eName.replace('/', '.');
+ temp= (Vector[]) packageFragToTypes.get(eName);
+ if (temp == null) {
+ temp= new Vector[] { new Vector(), new Vector()
+ };
+ packageFragToTypes.put(eName, temp);
+ }
+ } else {
+ if (eName.toUpperCase().endsWith(".CLASS")) {
+ //only interested in class files
+ //store the class file entry name to be cached in the appropriate package fragment
+ //zip entries only use '/'
+ Vector classTemp;
+ int lastSeparator= eName.lastIndexOf('/');
+ String key= IPackageFragment.DEFAULT_PACKAGE_NAME;
+ String value= eName;
+ if (lastSeparator != -1) {
+ //not in the default package
+ eName= eName.replace('/', '.');
+ value= eName.substring(lastSeparator + 1);
+ key= eName.substring(0, lastSeparator);
+ }
+ temp= (Vector[]) packageFragToTypes.get(key);
+ if (temp == null) {
+ // build all package fragments in the key
+ lastSeparator= key.indexOf('.');
+ while (lastSeparator > 0) {
+ String prefix= key.substring(0, lastSeparator);
+ if (packageFragToTypes.get(prefix) == null) {
+ packageFragToTypes.put(prefix, new Vector[] { new Vector(), new Vector()
+ });
+ }
+ lastSeparator= key.indexOf('.', lastSeparator + 1);
+ }
+ classTemp= new Vector();
+ classTemp.addElement(value);
+ packageFragToTypes.put(key, new Vector[] {classTemp, new Vector()
+ });
+ } else {
+ classTemp= temp[0];
+ classTemp.addElement(value);
+ }
+ } else {
+ Vector resTemp;
+ int lastSeparator= eName.lastIndexOf('/');
+ String key= IPackageFragment.DEFAULT_PACKAGE_NAME;
+ String value= eName;
+ if (lastSeparator != -1) {
+ //not in the default package
+ eName= eName.replace('/', '.');
+ key= eName.substring(0, lastSeparator);
+ }
+ temp= (Vector[]) packageFragToTypes.get(key);
+ if (temp == null) {
+ // build all package fragments in the key
+ lastSeparator= key.indexOf('.');
+ while (lastSeparator > 0) {
+ String prefix= key.substring(0, lastSeparator);
+ if (packageFragToTypes.get(prefix) == null) {
+ packageFragToTypes.put(prefix, new Vector[] { new Vector(), new Vector()
+ });
+ }
+ lastSeparator= key.indexOf('.', lastSeparator + 1);
+ }
+ resTemp= new Vector();
+ resTemp.addElement(value);
+ packageFragToTypes.put(key, new Vector[] { new Vector(), resTemp });
+ } else {
+ resTemp= temp[1];
+ resTemp.addElement(value);
+ }
+ }
+ }
+ }
+ //loop through all of referenced packages, creating package fragments if necessary
+ // and cache the entry names in the infos created for those package fragments
+ Enumeration packages= packageFragToTypes.keys();
+ while (packages.hasMoreElements()) {
+ String packName= (String) packages.nextElement();
+ Vector[] entries= (Vector[]) packageFragToTypes.get(packName);
+ JarPackageFragment packFrag= (JarPackageFragment) getPackageFragment(packName);
+ JarPackageFragmentInfo fragInfo= (JarPackageFragmentInfo) packFrag.createElementInfo();
+ fragInfo.setEntryNames(entries[0]);
+ int resLength= entries[1].size();
+ if (resLength == 0) {
+ packFrag.computeNonJavaResources(new String[] {}, fragInfo, jar.getName());
+ } else {
+ String[] resNames= new String[resLength];
+ entries[1].copyInto(resNames);
+ packFrag.computeNonJavaResources(resNames, fragInfo, jar.getName());
+ }
+ packFrag.computeChildren(fragInfo);
+ fgJavaModelManager.putInfo(packFrag, fragInfo);
+ vChildren.addElement(packFrag);
+ }
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ } finally {
+ if (jar != null) {
+ try {
+ jar.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+}
+ /**
+ * Returns a new element info for this element.
+ */
+ protected OpenableElementInfo createElementInfo() {
+ return new JarPackageFragmentRootInfo();
+ }
+ /**
+ * A Jar is always K_BINARY.
+ *
+ * @exception NotPresentException if the project and root do
+ * not exist.
+ */
+ protected int determineKind(IResource underlyingResource) throws JavaModelException {
+ return IPackageFragmentRoot.K_BINARY;
+ }
+ /**
+ * Returns true if this handle represents the same jar
+ * as the given handle. Two jars are equal if they share
+ * the same zip file.
+ *
+ * @see Object#equals
+ */
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o instanceof JarPackageFragmentRoot) {
+ JarPackageFragmentRoot other= (JarPackageFragmentRoot) o;
+ return fJarPath.equals(other.fJarPath);
+ }
+ return false;
+ }
+public IClasspathEntry findSourceAttachmentRecommendation() {
+
+ try {
+
+ IPath rootPath = this.getPath();
+ IClasspathEntry entry;
+ IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
+
+ // try on enclosing project first
+ JavaProject parentProject = (JavaProject) getJavaProject();
+ try {
+ entry = parentProject.getClasspathEntryFor(rootPath);
+ if (entry != null){
+ Object target = JavaModel.getTarget(workspaceRoot, entry.getSourceAttachmentPath());
+ if (target instanceof IFile){
+ IFile file = (IFile) target;
+ if ("jar".equalsIgnoreCase(file.getFileExtension()) || "zip".equalsIgnoreCase(file.getFileExtension())){
+ return entry;
+ }
+ }
+ if (target instanceof java.io.File){
+ java.io.File file = (java.io.File) target;
+ String name = file.getName().toLowerCase();
+ if (name.endsWith(".jar") || name.endsWith(".zip")){
+ return entry;
+ }
+ }
+ }
+ } catch(JavaModelException e){
+ }
+
+ // iterate over all projects
+ IJavaModel model = getJavaModel();
+ IJavaProject[] jProjects = model.getJavaProjects();
+ for (int i = 0, max = jProjects.length; i < max; i++){
+ JavaProject jProject = (JavaProject) jProjects[i];
+ if (jProject == parentProject) continue; // already done
+ try {
+ entry = jProject.getClasspathEntryFor(rootPath);
+ if (entry != null){
+ Object target = JavaModel.getTarget(workspaceRoot, entry.getSourceAttachmentPath());
+ if (target instanceof IFile){
+ IFile file = (IFile) target;
+ if ("jar".equalsIgnoreCase(file.getFileExtension()) || "zip".equalsIgnoreCase(file.getFileExtension())){
+ return entry;
+ }
+ }
+ if (target instanceof java.io.File){
+ java.io.File file = (java.io.File) target;
+ String name = file.getName().toLowerCase();
+ if (name.endsWith(".jar") || name.endsWith(".zip")){
+ return entry;
+ }
+ }
+ }
+ } catch(JavaModelException e){
+ }
+ }
+ } catch(JavaModelException e){
+ }
+
+ return null;
+}
+/**
+ * @see JavaElement#getHandleMemento()
+ */
+public String getHandleMemento(){
+ StringBuffer buff= new StringBuffer(((JavaElement)getParent()).getHandleMemento());
+ buff.append(getHandleMementoDelimiter());
+ buff.append(this.fJarPath.toString()); // 1GEP51U
+ return buff.toString();
+}
+ /**
+ * Returns the underlying ZipFile for this Jar package fragment root.
+ *
+ * @exception CoreException if an error occurs accessing the jar
+ */
+ public ZipFile getJar() throws CoreException {
+ return fgJavaModelManager.getZipFile(getPath());
+ }
+ /**
+ * @see IJavaElement
+ */
+ public IJavaProject getJavaProject() {
+ IJavaElement parent= getParent();
+ if (parent == null) {
+ return null;
+ } else {
+ return parent.getJavaProject();
+ }
+ }
+ /**
+ * @see IPackageFragmentRoot
+ */
+ public int getKind() {
+ return IPackageFragmentRoot.K_BINARY;
+ }
+ /**
+ * Returns an array of non-java resources contained in the receiver.
+ */
+ public Object[] getNonJavaResources() throws JavaModelException {
+ // We want to show non java resources of the default package at the root (see PR #1G58NB8)
+ return ((JarPackageFragment) this.getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME)).storedNonJavaResources();
+ }
+ /**
+ * @see IPackageFragmentRoot
+ */
+ public IPackageFragment getPackageFragment(String packageName) {
+
+ return new JarPackageFragment(this, packageName);
+ }
+ /**
+ * @see IPackageFragmentRoot
+ */
+ public IPath getPath() {
+ if (fResource == null) {
+ return fJarPath;
+ } else {
+ return super.getPath();
+ }
+ }
+ /**
+ * @see IPackageFragmentRoot
+ */
+ public IPath getSourceAttachmentPath() throws JavaModelException {
+ String serverPathString= getSourceAttachmentProperty();
+ if (serverPathString == null) {
+ return null;
+ }
+ int index= serverPathString.lastIndexOf(ATTACHMENT_PROPERTY_DELIMITER);
+ String serverZipPathString= serverPathString.substring(0, index);
+ return new Path(serverZipPathString);
+ }
+ /**
+ * Returns the server property for this package fragment root's
+ * source attachement.
+ */
+ protected String getSourceAttachmentProperty() throws JavaModelException {
+ String propertyString = null;
+ QualifiedName qName= getSourceAttachmentPropertyName();
+ try {
+ propertyString = getWorkspace().getRoot().getPersistentProperty(qName);
+
+ // if no existing source attachment information, then lookup a recommendation from classpath entries
+ if (propertyString == null || propertyString.lastIndexOf(ATTACHMENT_PROPERTY_DELIMITER) < 0){
+ IClasspathEntry recommendation = findSourceAttachmentRecommendation();
+ if (recommendation != null){
+ propertyString = recommendation.getSourceAttachmentPath().toString()
+ + ATTACHMENT_PROPERTY_DELIMITER
+ + (recommendation.getSourceAttachmentRootPath() == null ? "" : recommendation.getSourceAttachmentRootPath().toString());
+ getWorkspace().getRoot().setPersistentProperty(qName, propertyString);
+ }
+ }
+ return propertyString;
+ } catch (CoreException ce) {
+ throw new JavaModelException(ce);
+ }
+ }
+ /**
+ * Returns the qualified name for the source attachment property
+ * of this jar.
+ */
+ protected QualifiedName getSourceAttachmentPropertyName() throws JavaModelException {
+ ZipFile jarFile = null;
+ try {
+ jarFile = getJar();
+ return new QualifiedName(JavaCore.PLUGIN_ID, "sourceattachment: " + jarFile.getName());
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ } finally {
+ try {
+ if (jarFile != null) {
+ jarFile.close();
+ }
+ } catch(IOException e) {
+ // ignore
+ }
+ }
+ }
+ /**
+ * @see IPackageFragmentRoot
+ */
+ public IPath getSourceAttachmentRootPath() throws JavaModelException {
+ String serverPathString= getSourceAttachmentProperty();
+ if (serverPathString == null) {
+ return null;
+ }
+ int index= serverPathString.lastIndexOf(ATTACHMENT_PROPERTY_DELIMITER);
+ String serverRootPathString= IPackageFragmentRoot.DEFAULT_PACKAGEROOT_PATH;
+ if (index != serverPathString.length() - 1) {
+ serverRootPathString= serverPathString.substring(index + 1);
+ }
+ return new Path(serverRootPathString);
+ }
+ /**
+ * @see JavaElement
+ */
+ public SourceMapper getSourceMapper() {
+ try {
+ return ((JarPackageFragmentRootInfo) getElementInfo()).getSourceMapper();
+ } catch (JavaModelException e) {
+ return null;
+ }
+ }
+ /**
+ * @see IJavaElement
+ */
+ public IResource getUnderlyingResource() throws JavaModelException {
+ if (fResource == null) {
+ return null;
+ } else {
+ return super.getUnderlyingResource();
+ }
+ }
+ /**
+ * If I am not open, return true to avoid parsing.
+ *
+ * @see IParent
+ */
+ public boolean hasChildren() throws JavaModelException {
+ if (isOpen()) {
+ return getChildren().length > 0;
+ } else {
+ return true;
+ }
+ }
+ public int hashCode() {
+ return fJarPath.hashCode();
+ }
+ /**
+ * @see IPackageFragmentRoot
+ */
+ public boolean isArchive() {
+ return true;
+ }
+ /**
+ * @see IPackageFragmentRoot
+ */
+ public boolean isExternal() {
+ return fResource == null;
+ }
+ /**
+ * Jars and jar entries are all read only
+ */
+ public boolean isReadOnly() {
+ return true;
+ }
+ /**
+ * @see Openable#openWhenClosed()
+ */
+ protected void openWhenClosed(IProgressMonitor pm) throws JavaModelException {
+ super.openWhenClosed(pm);
+ try {
+ //restore any stored attached source zip
+ IPath zipPath= getSourceAttachmentPath();
+ if (zipPath != null) {
+ IPath rootPath= getSourceAttachmentRootPath();
+ attachSource(zipPath, rootPath, pm);
+ }
+ } catch(JavaModelException e){ // no attached source
+ }
+ }
+ /**
+ * An archive cannot refresh its children.
+ */
+ public void refreshChildren() {
+ // do nothing
+ }
+ /**
+ * Reset the array of non-java resources contained in the receiver to null.
+ */
+ public void resetNonJavaResources() throws JavaModelException {
+ ((JarPackageFragmentRootInfo) getElementInfo()).setNonJavaResources(null);
+ }
+ /**
+ * @private - for use by <code>AttachSourceOperation</code> only.
+ * Sets the source mapper associated with this jar.
+ */
+ public void setSourceMapper(SourceMapper mapper) throws JavaModelException {
+ ((JarPackageFragmentRootInfo) getElementInfo()).setSourceMapper(mapper);
+ }
+ /**
+ * Possible failures: <ul>
+ * <li>RELATIVE_PATH - the path supplied to this operation must be
+ * an absolute path
+ * <li>ELEMENT_NOT_PRESENT - the jar supplied to the operation
+ * does not exist
+ * </ul>
+ */
+ protected void verifyAttachSource(IPath zipPath) throws JavaModelException {
+ IJavaModelStatus status= null;
+ if (!exists0()) {
+ throw newNotPresentException();
+ } else if (zipPath != null && !zipPath.isAbsolute()) {
+ throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.RELATIVE_PATH, zipPath));
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRootInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRootInfo.java
new file mode 100644
index 0000000000..9d12eecc95
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRootInfo.java
@@ -0,0 +1,41 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/**
+ * The element info for <code>JarPackageFragmentRoot</code>s.
+ */
+import org.eclipse.core.resources.IResource;
+
+class JarPackageFragmentRootInfo extends PackageFragmentRootInfo {
+ /**
+ * The SourceMapper for this JAR (or <code>null</code> if
+ * this JAR does not have source attached).
+ */
+ protected SourceMapper fSourceMapper = null;
+ /**
+ * Returns an array of non-java resources contained in the receiver.
+ */
+ public Object[] getNonJavaResources() {
+ fNonJavaResources = NO_NON_JAVA_RESOURCES;
+ return fNonJavaResources;
+ }
+
+ /**
+ * Retuns the SourceMapper for this JAR, or <code>null</code>
+ * if this JAR does not have attached source.
+ */
+ protected SourceMapper getSourceMapper() {
+ return fSourceMapper;
+ }
+
+ /**
+ * Sets the SourceMapper for this JAR.
+ */
+ protected void setSourceMapper(SourceMapper mapper) {
+ fSourceMapper = mapper;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java
new file mode 100644
index 0000000000..465e998269
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java
@@ -0,0 +1,666 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.jdom.*;
+
+import java.util.Vector;
+
+/**
+ * Root of Java element handle hierarchy.
+ *
+ * @see IJavaElement
+ */
+public abstract class JavaElement
+ extends PlatformObject
+ implements IJavaElement {
+
+ public static final char JEM_JAVAPROJECT = '=';
+ public static final char JEM_PACKAGEFRAGMENTROOT = Path.SEPARATOR;
+ public static final char JEM_PACKAGEFRAGMENT = '<';
+ public static final char JEM_FIELD = '^';
+ public static final char JEM_METHOD = '~';
+ public static final char JEM_INITIALIZER = '|';
+ public static final char JEM_COMPILATIONUNIT = '{';
+ public static final char JEM_CLASSFILE = '(';
+ public static final char JEM_TYPE = '[';
+ public static final char JEM_PACKAGEDECLARATION = '%';
+ public static final char JEM_IMPORTDECLARATION = '#';
+
+ /**
+ * A count to uniquely identify this element in the case
+ * that a duplicate named element exists. For example, if
+ * there are two fields in a compilation unit with the
+ * same name, the occurrence count is used to distinguish
+ * them. The occurrence count starts at 1 (i.e. the first
+ * occurrence is occurrence 1, not occurrence 0).
+ */
+ protected int fOccurrenceCount = 1;
+
+ /**
+ * This element's type - one of the constants defined
+ * in IJavaLanguageElementTypes.
+ */
+ protected int fLEType = 0;
+
+ /**
+ * This element's parent, or <code>null</code> if this
+ * element does not have a parent.
+ */
+ protected IJavaElement fParent;
+
+ /**
+ * This element's name, or an empty <code>String</code> if this
+ * element does not have a name.
+ */
+ protected String fName;
+
+ /**
+ * Direct access to the Java Model Manager
+ */
+ protected static JavaModelManager fgJavaModelManager =
+ JavaModelManager.getJavaModelManager();
+
+ /**
+ * Constructs a handle for a java element of the specified type, with
+ * the given parent element and name.
+ *
+ * @param type - one of the constants defined in IJavaLanguageElementTypes
+ *
+ * @exception IllegalArgumentException if the type is not one of the valid
+ * Java element type constants
+ *
+ */
+ protected JavaElement(int type, IJavaElement parent, String name)
+ throws IllegalArgumentException {
+ if (type < JAVA_MODEL || type > IMPORT_DECLARATION) {
+ throw new IllegalArgumentException("type is not one of the defined constants");
+ }
+ fLEType = type;
+ fParent = parent;
+ fName = name;
+ }
+
+ /**
+ * @see IOpenable
+ */
+ public void close() throws JavaModelException {
+ Object info = fgJavaModelManager.peekAtInfo(this);
+ if (info != null) {
+ if (this instanceof IParent) {
+ IJavaElement[] children = ((JavaElementInfo) info).getChildren();
+ for (int i = 0, size = children.length; i < size; ++i) {
+ JavaElement child = (JavaElement) children[i];
+ child.close();
+ }
+ }
+ closing(info);
+ fgJavaModelManager.removeInfo(this);
+ }
+ }
+
+ /**
+ * This element is being closed. Do any necessary cleanup.
+ */
+ protected void closing(Object info) throws JavaModelException {
+ }
+
+ /**
+ * Returns true if this handle represents the same Java element
+ * as the given handle. By default, two handles represent the same
+ * element if they are identical or if they represent the same type
+ * of element, have equal names, parents, and occurrence counts.
+ *
+ * <p>If a subclass has other requirements for equality, this method
+ * must be overridden.
+ *
+ * @see Object#equals
+ */
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o instanceof JavaElement) {
+ JavaElement other = (JavaElement) o;
+ if (fLEType != other.fLEType)
+ return false;
+ return fName.equals(other.fName)
+ && fParent.equals(other.fParent)
+ && fOccurrenceCount == other.fOccurrenceCount;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if this <code>JavaElement</code> is equivalent to the given
+ * <code>IDOMNode</code>.
+ */
+ protected boolean equalsDOMNode(IDOMNode node) throws JavaModelException {
+ return false;
+ }
+
+ /**
+ * @see IJavaElement
+ */
+ public boolean exists() {
+ try {
+ getRawInfo();
+ return true;
+ } catch (JavaModelException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Returns the <code>IDOMNode</code> that corresponds to this <code>JavaElement</code>
+ * or <code>null</code> if there is no corresponding node.
+ */
+ public IDOMNode findNode(IDOMCompilationUnit dom) {
+ int type = getElementType();
+ if (type == IJavaElement.COMPILATION_UNIT
+ || type == IJavaElement.FIELD
+ || type == IJavaElement.IMPORT_DECLARATION
+ || type == IJavaElement.INITIALIZER
+ || type == IJavaElement.METHOD
+ || type == IJavaElement.PACKAGE_DECLARATION
+ || type == IJavaElement.TYPE) {
+ Vector path = new Vector();
+ IJavaElement element = this;
+ while (element != null
+ && element.getElementType() != IJavaElement.COMPILATION_UNIT) {
+ if (element.getElementType() != IJavaElement.IMPORT_CONTAINER) {
+ // the DOM does not have import containers, so skip them
+ path.insertElementAt(element, 0);
+ }
+ element = element.getParent();
+ }
+ if (path.size() == 0) {
+ try {
+ if (equalsDOMNode(dom)) {
+ return dom;
+ } else {
+ return null;
+ }
+ } catch (JavaModelException e) {
+ return null;
+ }
+ }
+ return ((JavaElement) path.elementAt(0)).followPath(
+ path,
+ 0,
+ dom.getFirstChild());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ */
+ protected IDOMNode followPath(Vector path, int position, IDOMNode node) {
+
+ try {
+ if (equalsDOMNode(node)) {
+ if (position == (path.size() - 1)) {
+ return node;
+ } else {
+ if (node.getFirstChild() != null) {
+ position++;
+ return ((JavaElement) path.elementAt(position)).followPath(
+ path,
+ position,
+ node.getFirstChild());
+ } else {
+ return null;
+ }
+ }
+ } else
+ if (node.getNextNode() != null) {
+ return followPath(path, position, node.getNextNode());
+ } else {
+ return null;
+ }
+ } catch (JavaModelException e) {
+ return null;
+ }
+
+ }
+
+ /**
+ * @see IParent
+ */
+ public IJavaElement[] getChildren() throws JavaModelException {
+ return getElementInfo().getChildren();
+ }
+
+ /**
+ * Returns a collection of (immediate) children of this node of the
+ * specified type.
+ *
+ * @param type - one of constants defined by IJavaLanguageElementTypes
+ */
+ public Vector getChildrenOfType(int type) throws JavaModelException {
+ IJavaElement[] children = getChildren();
+ int size = children.length;
+ Vector v = new Vector(size);
+ for (int i = 0; i < size; ++i) {
+ JavaElement elt = (JavaElement) children[i];
+ if (elt.getElementType() == type) {
+ v.addElement(elt);
+ }
+ }
+ return v;
+ }
+
+ /**
+ * @see IMember
+ */
+ public IClassFile getClassFile() {
+ return null;
+ }
+
+ /**
+ * @see IMember
+ */
+ public ICompilationUnit getCompilationUnit() {
+ return null;
+ }
+
+ /**
+ * Returns the info for this handle.
+ * If this element is not already open, it and all of its parents are opened.
+ * Does not return null.
+ *
+ * @exception JavaModelException if the element is not present or not accessible
+ */
+ protected JavaElementInfo getElementInfo() throws JavaModelException {
+ synchronized (fgJavaModelManager) {
+ Object info = fgJavaModelManager.getInfo(this);
+ if (info == null) {
+ openHierarchy();
+ info = fgJavaModelManager.getInfo(this);
+ if (info == null) {
+ throw newNotPresentException();
+ }
+ }
+ return (JavaElementInfo) info;
+ }
+ }
+
+ /**
+ * @see IAdaptable
+ */
+ public String getElementName() {
+ return fName;
+ }
+
+ /**
+ * @see IJavaElement
+ */
+ public int getElementType() {
+ return fLEType;
+ }
+
+ /**
+ * @see IJavaElement
+ */
+ public String getHandleIdentifier() {
+ return getHandleMemento();
+ }
+
+ /**
+ * @see JavaElement#getHandleMemento()
+ */
+ public String getHandleMemento() {
+ StringBuffer buff =
+ new StringBuffer(((JavaElement) getParent()).getHandleMemento());
+ buff.append(getHandleMementoDelimiter());
+ buff.append(getElementName());
+ return buff.toString();
+ }
+
+ /**
+ * Returns the <code>char</code> that marks the start of this handles
+ * contribution to a memento.
+ */
+ protected abstract char getHandleMementoDelimiter();
+ /**
+ * @see IJavaElement
+ */
+ public IJavaModel getJavaModel() {
+ return getParent().getJavaModel();
+ }
+
+ /**
+ * Returns the JavaModelManager
+ */
+ public JavaModelManager getJavaModelManager() {
+ return fgJavaModelManager;
+ }
+
+ /**
+ * @see IJavaElement
+ */
+ public IJavaProject getJavaProject() {
+ return getParent().getJavaProject();
+ }
+
+ /**
+ * Returns the occurrence count of the handle.
+ */
+ protected int getOccurrenceCount() {
+ return fOccurrenceCount;
+ }
+
+ /**
+ * Return the first instance of IOpenable in the parent
+ * hierarchy of this element.
+ *
+ * <p>Subclasses that are not IOpenable's must override this method.
+ */
+ public IOpenable getOpenableParent() {
+
+ return (IOpenable) fParent;
+ }
+
+ /**
+ * @see IJavaElement
+ */
+ public IJavaElement getParent() {
+ return fParent;
+ }
+
+ /**
+ * Returns the info for this handle.
+ * If this element is not already open, it and all of its parents are opened.
+ * Does not return null.
+ *
+ * @exception JavaModelException if the element is not present or not accessible
+ */
+ public Object getRawInfo() throws JavaModelException {
+ Object info = fgJavaModelManager.getInfo(this);
+ if (info == null) {
+ openHierarchy();
+ info = fgJavaModelManager.getInfo(this);
+ if (info == null) {
+ throw newNotPresentException();
+ }
+ }
+ return info;
+ }
+
+ /**
+ * Returns the element that is located at the given source position
+ * in this element. This is a helper method for <code>ICompilationUnit#getElementAt</code>,
+ * and only works on compilation units and types. The position given is
+ * known to be within this element's source range already, and if no finer
+ * grained element is found at the position, this element is returned.
+ */
+ protected IJavaElement getSourceElementAt(int position)
+ throws JavaModelException {
+ if (this instanceof ISourceReference) {
+ IJavaElement[] children = getChildren();
+ int i;
+ for (i = 0; i < children.length; i++) {
+ IJavaElement aChild = children[i];
+ if (aChild instanceof SourceRefElement) {
+ SourceRefElement child = (SourceRefElement) children[i];
+ ISourceRange range = child.getSourceRange();
+ if (position < range.getOffset() + range.getLength()
+ && position >= range.getOffset()) {
+ if (child.getElementType() == TYPE) {
+ return child.getSourceElementAt(position);
+ } else {
+ return child;
+ }
+ }
+ }
+ }
+ } else {
+ // should not happen
+ Assert.isTrue(false);
+ }
+ return this;
+ }
+
+ /**
+ * Returns the SourceMapper facility for this element, or
+ * <code>null</code> if this element does not have a
+ * SourceMapper.
+ */
+ public SourceMapper getSourceMapper() {
+ return ((JavaElement) getParent()).getSourceMapper();
+ }
+
+ public abstract IResource getUnderlyingResource() throws JavaModelException;
+ /**
+ * Returns the workspace associated with this object.
+ */
+ public IWorkspace getWorkspace() {
+ return getJavaModel().getWorkspace();
+ }
+
+ /**
+ * Returns the hash code for this Java element. By default,
+ * the hash code for an element is a combination of its name
+ * and parent's hash code. Elements with other requirements must
+ * override this method.
+ */
+ public int hashCode() {
+ return Util.combineHashCodes(fName.hashCode(), fParent.hashCode());
+ }
+
+ /**
+ * Returns true if this element is an ancestor of the given element,
+ * otherwise false.
+ */
+ protected boolean isAncestorOf(IJavaElement e) {
+ IJavaElement parent = e.getParent();
+ while (parent != null && !parent.equals(this)) {
+ parent = parent.getParent();
+ }
+ return parent != null;
+ }
+
+ /**
+ * @see IJavaElement
+ */
+ public boolean isReadOnly() {
+ return false;
+ }
+
+ /**
+ * @see IJavaElement
+ */
+ public boolean isStructureKnown() throws JavaModelException {
+ return getElementInfo().isStructureKnown();
+ }
+
+ /**
+ * Creates and returns and not present exception for this element.
+ */
+ protected JavaModelException newNotPresentException() {
+ return new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
+ }
+
+ /**
+ * Default is to not do any source indices updates.
+ */
+ public void offsetSourceEndAndChildren(int amount, IJavaElement child) {
+
+ }
+
+ /**
+ * Default behaviour is not to change the source range
+ * for the Java element
+ */
+ public void offsetSourceRange(int amount) {
+ }
+
+ /**
+ * Opens this element and all parents that are not already open.
+ *
+ * @exception JavaModelException this element is not present or accessible
+ */
+ protected void openHierarchy() throws JavaModelException {
+ if (this instanceof IOpenable) {
+ ((Openable) this).openWhenClosed(null);
+ } else {
+ Openable openableParent = (Openable) getOpenableParent();
+ if (openableParent != null) {
+ JavaElementInfo openableParentInfo =
+ (JavaElementInfo) fgJavaModelManager.getInfo((IJavaElement) openableParent);
+ if (openableParentInfo == null) {
+ openableParent.openWhenClosed(null);
+ } else {
+ throw newNotPresentException();
+ }
+ }
+ }
+ }
+
+ /**
+ * This element has just been opened. Do any necessary setup.
+ */
+ protected void opening(Object info) {
+ }
+
+ /**
+ */
+ public String readableName() {
+
+ return this.getElementName();
+ }
+
+ /**
+ * Removes all cached info from the Java Model, including all children,
+ * but does not close this element.
+ */
+ protected void removeInfo() {
+ Object info = fgJavaModelManager.peekAtInfo(this);
+ if (info != null) {
+ if (this instanceof IParent) {
+ IJavaElement[] children = ((JavaElementInfo) info).getChildren();
+ for (int i = 0, size = children.length; i < size; ++i) {
+ JavaElement child = (JavaElement) children[i];
+ child.removeInfo();
+ }
+ }
+ fgJavaModelManager.removeInfo(this);
+ }
+ }
+
+ /**
+ * Runs a Java Model Operation
+ */
+ protected void runOperation(
+ JavaModelOperation operation,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ fgJavaModelManager.runOperation(operation, monitor);
+ }
+
+ /**
+ * Sets the occurrence count of the handle.
+ */
+ protected void setOccurrenceCount(int count) {
+ fOccurrenceCount = count;
+ }
+
+ protected String tabString(int tab) {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = tab; i > 0; i--)
+ buffer.append(" ");
+ return buffer.toString();
+ }
+
+ /**
+ * @private Debugging purposes
+ */
+ protected String toDebugString() {
+ StringBuffer buffer = new StringBuffer();
+ Object info = fgJavaModelManager.getInfo(this);
+ this.toStringInfo(0, buffer, info);
+ return buffer.toString();
+ }
+
+ /**
+ * @private Debugging purposes
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ toString(0, buffer);
+ return buffer.toString();
+ }
+
+ /**
+ * @private Debugging purposes
+ */
+ protected void toString(int tab, StringBuffer buffer) {
+ buffer.append(this.tabString(tab));
+ Object info = fgJavaModelManager.getInfo(this);
+ this.toStringInfo(tab, buffer, info);
+ if (tab == 0) {
+ this.toStringAncestors(buffer);
+ }
+ this.toStringChildren(tab, buffer, info);
+ }
+
+ /**
+ * @private Debugging purposes
+ */
+ protected void toStringAncestors(StringBuffer buffer) {
+ JavaElement parent = (JavaElement) this.getParent();
+ if (parent != null) {
+ buffer.append(" [in ");
+ Object parentInfo = fgJavaModelManager.getInfo(parent);
+ parent.toStringInfo(0, buffer, parentInfo);
+ parent.toStringAncestors(buffer);
+ buffer.append("]");
+ }
+ }
+
+ /**
+ * @private Debugging purposes
+ */
+ protected void toStringChildren(int tab, StringBuffer buffer, Object info) {
+ if (info == null || !(info instanceof JavaElementInfo))
+ return;
+ IJavaElement[] children = ((JavaElementInfo) info).getChildren();
+ for (int i = 0; i < children.length; i++) {
+ buffer.append("\n");
+ ((JavaElement) children[i]).toString(tab + 1, buffer);
+ }
+ }
+
+ /**
+ * @private Debugging purposes
+ */
+ protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+ buffer.append(getElementName());
+ if (info == null) {
+ buffer.append(" (not open)");
+ }
+ }
+
+ /**
+ * Updates the source end position for this element.
+ * Default behaviour is to do nothing.
+ */
+ public void triggerSourceEndOffset(int amount, int nameStart, int nameEnd) {
+ }
+
+ /**
+ * Updates the source positions for this element.
+ * Default behaviour is to do nothing.
+ */
+ public void triggerSourceRangeOffset(int amount, int nameStart, int nameEnd) {
+
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDelta.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDelta.java
new file mode 100644
index 0000000000..094fc89bc4
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDelta.java
@@ -0,0 +1,645 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+
+import java.util.Vector;
+
+/**
+ * @see IJavaElementDelta
+ */
+public class JavaElementDelta implements IJavaElementDelta {
+ /**
+ * The element that this delta describes the change to.
+ * @see #getElement()
+ */
+ protected IJavaElement fChangedElement;
+ /**
+ * @see #getKind()
+ */
+ private int fKind;
+ /**
+ * @see #getFlags()
+ */
+ private int fChangeFlags = 0;
+ /**
+ * @see #getAffectedChildren()
+ */
+ protected IJavaElementDelta[] fAffectedChildren = fgEmptyDelta;
+
+ /**
+ * Collection of resource deltas that correspond to non java resources deltas.
+ */
+ protected IResourceDelta[] resourceDeltas = null;
+
+ /**
+ * Counter of resource deltas
+ */
+ protected int resourceDeltasCounter;
+ /**
+ * @see #getMovedFromHandle()
+ */
+ protected IJavaElement fMovedFromHandle = null;
+ /**
+ * @see #getMovedToHandle()
+ */
+ protected IJavaElement fMovedToHandle = null;
+ /**
+ * Empty array of IJavaElementDelta
+ */
+ protected static IJavaElementDelta[] fgEmptyDelta = new IJavaElementDelta[] {
+ };
+
+ /**
+ * Creates the root delta. To create the nested delta
+ * hierarchies use the following convenience methods. The root
+ * delta can be created at any level (i.e. project, package root,
+ * package fragment...).
+ * <ul>
+ * <li><code>added(IJavaElement)</code>
+ * <li><code>changed(IJavaElement)</code>
+ * <li><code>moved(IJavaElement, IJavaElement)</code>
+ * <li><code>removed(IJavaElement)</code>
+ * <li><code>renamed(IJavaElement, IJavaElement)</code>
+ * </ul>
+ */
+ public JavaElementDelta(IJavaElement element) {
+ super();
+ fChangedElement = element;
+ fKind = CHANGED;
+ fChangeFlags = F_CHILDREN;
+ }
+
+ /**
+ * Adds the child delta to the collection of affected children. If the
+ * child is already in the collection, walk down the hierarchy.
+ */
+ protected void addAffectedChild(JavaElementDelta child) {
+ if (fAffectedChildren.length == 0) {
+ fAffectedChildren = new IJavaElementDelta[] { child };
+ return;
+ }
+ IJavaElementDelta sameChild = null;
+ if (fAffectedChildren != null) {
+ for (int i = 0; i < fAffectedChildren.length; i++) {
+ if (this
+ .equalsAndSameParent(
+ fAffectedChildren[i].getElement(),
+ child.getElement())) {
+ // handle case of two jars that can be equals but not in the same project
+ sameChild = fAffectedChildren[i];
+ break;
+ }
+ }
+ }
+ if (sameChild == null) { //new affected child
+
+ fAffectedChildren = growAndAddToArray(fAffectedChildren, child);
+ } else {
+ IJavaElementDelta[] children = child.getAffectedChildren();
+ for (int i = 0; i < children.length; i++) {
+ JavaElementDelta childsChild = (JavaElementDelta) children[i];
+ ((JavaElementDelta) sameChild).addAffectedChild(childsChild);
+ }
+ }
+ }
+
+ /**
+ * Creates the nested deltas resulting from an add operation.
+ * Convenience method for creating add deltas.
+ * The constructor should be used to create the root delta
+ * and then an add operation should call this method.
+ */
+ public void added(IJavaElement element) {
+ JavaElementDelta addedDelta = new JavaElementDelta(element);
+ addedDelta.fKind = ADDED;
+ addedDelta.fChangeFlags = 0;
+ insertDeltaTree(element, addedDelta);
+ }
+
+ /**
+ * Adds the child delta to the collection of affected children. If the
+ * child is already in the collection, walk down the hierarchy.
+ */
+ protected void addResourceDelta(IResourceDelta child) {
+ if (resourceDeltas == null) {
+ resourceDeltas = new IResourceDelta[5];
+ resourceDeltas[resourceDeltasCounter++] = child;
+ return;
+ }
+ if (resourceDeltas.length == resourceDeltasCounter) {
+ // need a resize
+ System.arraycopy(
+ resourceDeltas,
+ 0,
+ (resourceDeltas = new IResourceDelta[resourceDeltasCounter * 2]),
+ 0,
+ resourceDeltasCounter);
+ }
+ resourceDeltas[resourceDeltasCounter++] = child;
+ }
+
+ /**
+ * Creates the nested deltas resulting from a change operation.
+ * Convenience method for creating change deltas.
+ * The constructor should be used to create the root delta
+ * and then a change operation should call this method.
+ */
+ public void changed(IJavaElement element, int changeFlag) {
+ JavaElementDelta changedDelta = new JavaElementDelta(element);
+ changedDelta.fKind = CHANGED;
+ changedDelta.fChangeFlags = changeFlag;
+ insertDeltaTree(element, changedDelta);
+ }
+
+ /**
+ * Creates the nested deltas for a closed element.
+ */
+ public void closed(IJavaElement element) {
+ JavaElementDelta delta = new JavaElementDelta(element);
+ delta.fKind = CHANGED;
+ delta.fChangeFlags = F_CLOSED;
+ insertDeltaTree(element, delta);
+ }
+
+ /**
+ * Creates the nested delta deltas based on the affected element
+ * its delta, and the root of this delta tree. Returns the root
+ * of the created delta tree.
+ */
+ protected JavaElementDelta createDeltaTree(
+ IJavaElement element,
+ JavaElementDelta delta) {
+ JavaElementDelta childDelta = delta;
+ Vector ancestors = getAncestors(element);
+ if (ancestors == null) {
+ if (this.equalsAndSameParent(delta.getElement(), getElement())) {
+ // handle case of two jars that can be equals but not in the same project
+ // the element being changed is the root element
+ fKind = delta.fKind;
+ fChangeFlags = delta.fChangeFlags;
+ fMovedToHandle = delta.fMovedToHandle;
+ fMovedFromHandle = delta.fMovedFromHandle;
+ } else {
+ // the given delta is not the root or a child - illegal
+ Assert.isTrue(false);
+ }
+ } else {
+ for (int i = 0, size = ancestors.size(); i < size; i++) {
+ IJavaElement ancestor = (IJavaElement) ancestors.elementAt(i);
+ JavaElementDelta ancestorDelta = new JavaElementDelta(ancestor);
+ ancestorDelta.addAffectedChild(childDelta);
+ ancestorDelta.fKind = CHANGED;
+ ancestorDelta.fChangeFlags = F_CHILDREN;
+ childDelta = ancestorDelta;
+ }
+ }
+ return childDelta;
+ }
+
+ /**
+ * Returns whether the two java elements are equals and have the same parent.
+ */
+ protected boolean equalsAndSameParent(IJavaElement e1, IJavaElement e2) {
+ IJavaElement parent1;
+ return e1.equals(e2)
+ && ((parent1 = e1.getParent()) != null)
+ && parent1.equals(e2.getParent());
+ }
+
+ /**
+ * Returns the <code>JavaElementDelta</code> for the given element
+ * in the delta tree, or null, if no delta for the given element is found.
+ */
+ protected JavaElementDelta find(IJavaElement e) {
+ if (this.equalsAndSameParent(fChangedElement, e)) {
+ // handle case of two jars that can be equals but not in the same project
+ return this;
+ } else {
+ for (int i = 0; i < fAffectedChildren.length; i++) {
+ JavaElementDelta delta = ((JavaElementDelta) fAffectedChildren[i]).find(e);
+ if (delta != null) {
+ return delta;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @see IJavaElementDelta
+ */
+ public IJavaElementDelta[] getAddedChildren() {
+ return getChildrenOfType(ADDED);
+ }
+
+ /**
+ * @see IJavaElementDelta
+ */
+ public IJavaElementDelta[] getAffectedChildren() {
+ return fAffectedChildren;
+ }
+
+ /**
+ * Returns a collection of all the parents of this element up to (but
+ * not including) the root of this tree in bottom-up order. If the given
+ * element is not a descendant of the root of this tree, <code>null</code>
+ * is returned.
+ */
+ private Vector getAncestors(IJavaElement element) {
+ IJavaElement parent = element.getParent();
+ if (parent == null) {
+ return null;
+ }
+ Vector parents = new Vector();
+ while (!parent.equals(fChangedElement)) {
+ parents.addElement(parent);
+ parent = parent.getParent();
+ if (parent == null) {
+ return null;
+ }
+ }
+ parents.trimToSize();
+ return parents;
+ }
+
+ /**
+ * @see IJavaElementDelta
+ */
+ public IJavaElementDelta[] getChangedChildren() {
+ return getChildrenOfType(CHANGED);
+ }
+
+ /**
+ * @see IJavaElementDelta
+ */
+ protected IJavaElementDelta[] getChildrenOfType(int type) {
+ int length = fAffectedChildren.length;
+ if (length == 0) {
+ return new IJavaElementDelta[] {
+ };
+ }
+ Vector children = new Vector(length);
+ for (int i = 0; i < length; i++) {
+ if (fAffectedChildren[i].getKind() == type) {
+ children.addElement(fAffectedChildren[i]);
+ }
+ }
+
+ IJavaElementDelta[] childrenOfType = new IJavaElementDelta[children.size()];
+ children.copyInto(childrenOfType);
+
+ return childrenOfType;
+ }
+
+ /**
+ * Returns the delta for a given element. Only looks below this
+ * delta.
+ */
+ protected JavaElementDelta getDeltaFor(IJavaElement element) {
+ if (this.equalsAndSameParent(getElement(), element))
+ // handle case of two jars that can be equals but not in the same project
+ return this;
+ if (fAffectedChildren.length == 0)
+ return null;
+ int childrenCount = fAffectedChildren.length;
+ for (int i = 0; i < childrenCount; i++) {
+ JavaElementDelta delta = (JavaElementDelta) fAffectedChildren[i];
+ if (this.equalsAndSameParent(delta.getElement(), element)) {
+ // handle case of two jars that can be equals but not in the same project
+ return delta;
+ } else {
+ delta = ((JavaElementDelta) delta).getDeltaFor(element);
+ if (delta != null)
+ return delta;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @see IJavaElementDelta
+ */
+ public IJavaElement getElement() {
+ return fChangedElement;
+ }
+
+ /**
+ * @see IJavaElementDelta
+ */
+ public int getFlags() {
+ return fChangeFlags;
+ }
+
+ /**
+ * @see IJavaElementDelta
+ */
+ public int getKind() {
+ return fKind;
+ }
+
+ /**
+ * @see IJavaElementDelta
+ */
+ public IJavaElement getMovedFromElement() {
+ return fMovedFromHandle;
+ }
+
+ /**
+ * @see IJavaElementDelta
+ */
+ public IJavaElement getMovedToElement() {
+ return fMovedToHandle;
+ }
+
+ /**
+ * @see IJavaElementDelta
+ */
+ public IJavaElementDelta[] getRemovedChildren() {
+ return getChildrenOfType(REMOVED);
+ }
+
+ /**
+ * Return the collection of resource deltas. Return null if none.
+ */
+ public IResourceDelta[] getResourceDeltas() {
+ if (resourceDeltas == null)
+ return null;
+ if (resourceDeltas.length != resourceDeltasCounter) {
+ System.arraycopy(
+ resourceDeltas,
+ 0,
+ resourceDeltas = new IResourceDelta[resourceDeltasCounter],
+ 0,
+ resourceDeltasCounter);
+ }
+ return resourceDeltas;
+ }
+
+ /**
+ * Adds the new element to a new array that contains all of the elements of the old array.
+ * Returns the new array.
+ */
+ protected IJavaElementDelta[] growAndAddToArray(
+ IJavaElementDelta[] array,
+ IJavaElementDelta addition) {
+ IJavaElementDelta[] old = array;
+ array = new IJavaElementDelta[old.length + 1];
+ System.arraycopy(old, 0, array, 0, old.length);
+ array[old.length] = addition;
+ return array;
+ }
+
+ /**
+ * Creates the delta tree for the given element and delta, and then
+ * inserts the tree as an affected child of this node.
+ */
+ protected void insertDeltaTree(IJavaElement element, JavaElementDelta delta) {
+ JavaElementDelta childDelta = createDeltaTree(element, delta);
+ if (!this.equalsAndSameParent(element, getElement())) {
+ // handle case of two jars that can be equals but not in the same project
+ addAffectedChild(childDelta);
+ }
+ }
+
+ /**
+ * Creates the nested deltas resulting from an move operation.
+ * Convenience method for creating the "move from" delta.
+ * The constructor should be used to create the root delta
+ * and then the move operation should call this method.
+ */
+ public void movedFrom(
+ IJavaElement movedFromElement,
+ IJavaElement movedToElement) {
+ JavaElementDelta removedDelta = new JavaElementDelta(movedFromElement);
+ removedDelta.fKind = REMOVED;
+ removedDelta.fChangeFlags = F_MOVED_TO;
+ removedDelta.fMovedToHandle = movedToElement;
+ insertDeltaTree(movedFromElement, removedDelta);
+ }
+
+ /**
+ * Creates the nested deltas resulting from an move operation.
+ * Convenience method for creating the "move to" delta.
+ * The constructor should be used to create the root delta
+ * and then the move operation should call this method.
+ */
+ public void movedTo(
+ IJavaElement movedToElement,
+ IJavaElement movedFromElement) {
+ JavaElementDelta addedDelta = new JavaElementDelta(movedToElement);
+ addedDelta.fKind = ADDED;
+ addedDelta.fChangeFlags = F_MOVED_FROM;
+ addedDelta.fMovedFromHandle = movedFromElement;
+ insertDeltaTree(movedToElement, addedDelta);
+ }
+
+ /**
+ * Creates the nested deltas for an opened element.
+ */
+ public void opened(IJavaElement element) {
+ JavaElementDelta delta = new JavaElementDelta(element);
+ delta.fKind = CHANGED;
+ delta.fChangeFlags = F_OPENED;
+ insertDeltaTree(element, delta);
+ }
+
+ /**
+ * Removes the child delta from the collection of affected children.
+ */
+ protected void removeAffectedChild(JavaElementDelta child) {
+ int index = -1;
+ if (fAffectedChildren != null) {
+ for (int i = 0; i < fAffectedChildren.length; i++) {
+ if (this
+ .equalsAndSameParent(
+ fAffectedChildren[i].getElement(),
+ child.getElement())) {
+ // handle case of two jars that can be equals but not in the same project
+ index = i;
+ break;
+ }
+ }
+ }
+ if (index >= 0) {
+ fAffectedChildren = removeAndShrinkArray(fAffectedChildren, index);
+ }
+ }
+
+ /**
+ * Removes the element from the array.
+ * Returns the a new array which has shrunk.
+ */
+ protected IJavaElementDelta[] removeAndShrinkArray(
+ IJavaElementDelta[] old,
+ int index) {
+ IJavaElementDelta[] array = new IJavaElementDelta[old.length - 1];
+ if (index > 0)
+ System.arraycopy(old, 0, array, 0, index);
+ int rest = old.length - index - 1;
+ if (rest > 0)
+ System.arraycopy(old, index + 1, array, index, rest);
+ return array;
+ }
+
+ /**
+ * Creates the nested deltas resulting from an delete operation.
+ * Convenience method for creating removed deltas.
+ * The constructor should be used to create the root delta
+ * and then the delete operation should call this method.
+ */
+ public void removed(IJavaElement element) {
+ JavaElementDelta removedDelta = new JavaElementDelta(element);
+ insertDeltaTree(element, removedDelta);
+ JavaElementDelta actualDelta = getDeltaFor(element);
+ if (actualDelta != null) {
+ actualDelta.fKind = REMOVED;
+ actualDelta.fChangeFlags = 0;
+ actualDelta.fAffectedChildren = fgEmptyDelta;
+ }
+ }
+
+ /**
+ * Sets the change flags of this delta.
+ */
+ protected void setFlags(int flags) {
+ fChangeFlags = flags;
+ }
+
+ /**
+ * Creates the nested deltas resulting from a change operation.
+ * Convenience method for creating change deltas.
+ * The constructor should be used to create the root delta
+ * and then a change operation should call this method.
+ */
+ public void sourceAttached(IJavaElement element) {
+ JavaElementDelta attachedDelta = new JavaElementDelta(element);
+ attachedDelta.fKind = CHANGED;
+ attachedDelta.fChangeFlags = F_SOURCEATTACHED;
+ insertDeltaTree(element, attachedDelta);
+ }
+
+ /**
+ * Creates the nested deltas resulting from a change operation.
+ * Convenience method for creating change deltas.
+ * The constructor should be used to create the root delta
+ * and then a change operation should call this method.
+ */
+ public void sourceDetached(IJavaElement element) {
+ JavaElementDelta detachedDelta = new JavaElementDelta(element);
+ detachedDelta.fKind = CHANGED;
+ detachedDelta.fChangeFlags = F_SOURCEDETACHED;
+ insertDeltaTree(element, detachedDelta);
+ }
+
+ /**
+ * Returns a string representation of this delta's
+ * structure suitable for debug purposes.
+ *
+ * @see toString
+ */
+ public String toDebugString(int depth) {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < depth; i++) {
+ buffer.append('\t');
+ }
+ buffer.append(((JavaElement) getElement()).toDebugString());
+ buffer.append("[");
+ switch (getKind()) {
+ case IJavaElementDelta.ADDED :
+ buffer.append('+');
+ break;
+ case IJavaElementDelta.REMOVED :
+ buffer.append('-');
+ break;
+ case IJavaElementDelta.CHANGED :
+ buffer.append('*');
+ break;
+ default :
+ buffer.append('?');
+ break;
+ }
+ buffer.append("]: {");
+ int changeFlags = getFlags();
+ boolean prev = false;
+ if ((changeFlags & IJavaElementDelta.F_CHILDREN) != 0) {
+ if (prev)
+ buffer.append(" | ");
+ buffer.append("CHILDREN");
+ prev = true;
+ }
+ if ((changeFlags & IJavaElementDelta.F_CONTENT) != 0) {
+ if (prev)
+ buffer.append(" | ");
+ buffer.append("CONTENT");
+ prev = true;
+ }
+ if ((changeFlags & IJavaElementDelta.F_MOVED_FROM) != 0) {
+ if (prev)
+ buffer.append(" | ");
+ buffer.append(
+ "MOVED_FROM(" + ((JavaElement) getMovedFromElement()).toDebugString() + ")");
+ prev = true;
+ }
+ if ((changeFlags & IJavaElementDelta.F_MOVED_TO) != 0) {
+ if (prev)
+ buffer.append(" | ");
+ buffer.append(
+ "MOVED_TO(" + ((JavaElement) getMovedToElement()).toDebugString() + ")");
+ prev = true;
+ }
+ if ((changeFlags & IJavaElementDelta.F_ADDED_TO_CLASSPATH) != 0) {
+ if (prev)
+ buffer.append(" | ");
+ buffer.append("ADDED TO CLASSPATH");
+ prev = true;
+ }
+ if ((changeFlags & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) != 0) {
+ if (prev)
+ buffer.append(" | ");
+ buffer.append("REMOVED FROM CLASSPATH");
+ prev = true;
+ }
+ if ((changeFlags & IJavaElementDelta.F_CLASSPATH_REORDER) != 0) {
+ if (prev)
+ buffer.append(" | ");
+ buffer.append("REORDERED IN CLASSPATH");
+ prev = true;
+ }
+ if ((changeFlags & IJavaElementDelta.F_MODIFIERS) != 0) {
+ if (prev)
+ buffer.append(" | ");
+ buffer.append("MODIFIERS CHANGED");
+ prev = true;
+ }
+ if ((changeFlags & IJavaElementDelta.F_SUPER_TYPES) != 0) {
+ if (prev)
+ buffer.append(" | ");
+ buffer.append("SUPER TYPES CHANGED");
+ prev = true;
+ }
+ buffer.append("}");
+ IJavaElementDelta[] children = getAffectedChildren();
+ if (children != null) {
+ for (int i = 0; i < children.length; ++i) {
+ buffer.append("\n");
+ buffer.append(((JavaElementDelta) children[i]).toDebugString(depth + 1));
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Returns a string representation of this delta's
+ * structure suitable for debug purposes.
+ */
+ public String toString() {
+ return toDebugString(0);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDeltaBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDeltaBuilder.java
new file mode 100644
index 0000000000..55ff78c486
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDeltaBuilder.java
@@ -0,0 +1,499 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+
+import java.util.*;
+
+/**
+ * A java element delta biulder creates a java element delta on
+ * a java element between the version of the java element
+ * at the time the comparator was created and the current version
+ * of the java element.
+ *
+ * It performs this operation by locally caching the contents of
+ * the java element when it is created. When the method
+ * createDeltas() is called, it creates a delta over the cached
+ * contents and the new contents.
+ */
+public class JavaElementDeltaBuilder {
+ /**
+ * The java element handle
+ */
+ IJavaElement javaElement;
+
+ /**
+ * The maximum depth in the java element children we should look into
+ */
+ int maxDepth = Integer.MAX_VALUE;
+
+ /**
+ * The old handle to info relationships
+ */
+ Hashtable infos;
+
+ /**
+ * The old position info
+ */
+ Hashtable oldPositions;
+
+ /**
+ * The new position info
+ */
+ Hashtable newPositions;
+
+ /**
+ * Change delta
+ */
+ JavaElementDelta delta;
+
+ /**
+ * List of added elements
+ */
+ Vector added;
+
+ /**
+ * List of removed elements
+ */
+ Vector removed;
+
+ /**
+ * Doubly linked list item
+ */
+ class ListItem {
+ public IJavaElement previous;
+ public IJavaElement next;
+
+ public ListItem(IJavaElement previous, IJavaElement next) {
+ this.previous = previous;
+ this.next = next;
+ }
+ }
+
+ /**
+ * Creates a java element comparator on a java element
+ * looking as deep as necessary.
+ */
+ public JavaElementDeltaBuilder(IJavaElement javaElement) {
+ this.javaElement = javaElement;
+ this.initialize();
+ this.recordElementInfo(
+ javaElement,
+ (JavaModel) this.javaElement.getJavaModel(),
+ 0);
+ }
+
+ /**
+ * Creates a java element comparator on a java element
+ * looking only 'maxDepth' levels deep.
+ */
+ public JavaElementDeltaBuilder(IJavaElement javaElement, int maxDepth) {
+ this.javaElement = javaElement;
+ this.maxDepth = maxDepth;
+ this.initialize();
+ this.recordElementInfo(
+ javaElement,
+ (JavaModel) this.javaElement.getJavaModel(),
+ 0);
+ }
+
+ /**
+ * Repairs the positioning information
+ * after an element has been added
+ */
+ private void added(IJavaElement element) {
+ this.added.addElement(element);
+ ListItem current = this.getNewPosition(element);
+ ListItem previous = null, next = null;
+ if (current.previous != null)
+ previous = this.getNewPosition(current.previous);
+ if (current.next != null)
+ next = this.getNewPosition(current.next);
+ if (previous != null)
+ previous.next = current.next;
+ if (next != null)
+ next.previous = current.previous;
+ }
+
+ /**
+ * Builds the java element deltas between the old content of the compilation
+ * unit and its new content.
+ */
+ public void buildDeltas() {
+ this.recordNewPositions(this.javaElement, 0);
+ this.findAdditions(this.javaElement, 0);
+ this.findDeletions();
+ this.findChangesInPositioning(this.javaElement, 0);
+ this.trimDelta(this.delta);
+ }
+
+ /**
+ * Finds elements which have been added or changed.
+ */
+ private void findAdditions(IJavaElement newElement, int depth) {
+ JavaElementInfo oldInfo = this.getElementInfo(newElement);
+ if (oldInfo == null && depth < this.maxDepth) {
+ this.delta.added(newElement);
+ added(newElement);
+ } else {
+ this.removeElementInfo(newElement);
+ }
+
+ if (depth >= this.maxDepth) {
+ // mark element as changed
+ this.delta.changed(newElement, IJavaElementDelta.F_CONTENT);
+ return;
+ }
+
+ JavaElementInfo newInfo = null;
+ try {
+ newInfo = ((JavaElement) newElement).getElementInfo();
+ } catch (JavaModelException npe) {
+ return;
+ }
+
+ this.findContentChange(oldInfo, newInfo, newElement);
+
+ if (oldInfo != null && newElement instanceof IParent) {
+
+ IJavaElement[] children = newInfo.getChildren();
+ if (children != null) {
+ int length = children.length;
+ for (int i = 0; i < length; i++) {
+ this.findAdditions(children[i], depth + 1);
+ }
+ }
+ }
+ }
+
+ /**
+ * Looks for changed positioning of elements.
+ */
+ private void findChangesInPositioning(IJavaElement element, int depth) {
+ if (depth >= this.maxDepth
+ || this.added.contains(element)
+ || this.removed.contains(element))
+ return;
+
+ if (!isPositionedCorrectly(element)) {
+ this.delta.removed(element);
+ this.delta.added(element);
+ }
+
+ if (element instanceof IParent) {
+ JavaElementInfo info = null;
+ try {
+ info = ((JavaElement) element).getElementInfo();
+ } catch (JavaModelException npe) {
+ return;
+ }
+
+ IJavaElement[] children = info.getChildren();
+ if (children != null) {
+ int length = children.length;
+ for (int i = 0; i < length; i++) {
+ this.findChangesInPositioning(children[i], depth + 1);
+ }
+ }
+ }
+ }
+
+ /**
+ * The elements are equivalent, but might have content changes.
+ */
+ private void findContentChange(
+ JavaElementInfo oldInfo,
+ JavaElementInfo newInfo,
+ IJavaElement newElement) {
+ if (oldInfo instanceof MemberElementInfo
+ && newInfo instanceof MemberElementInfo) {
+ if (((MemberElementInfo) oldInfo).getModifiers()
+ != ((MemberElementInfo) newInfo).getModifiers()) {
+ this.delta.changed(newElement, IJavaElementDelta.F_MODIFIERS);
+ } else
+ if (oldInfo instanceof SourceMethodElementInfo
+ && newInfo instanceof SourceMethodElementInfo) {
+ if (!CharOperation
+ .equals(
+ ((SourceMethodElementInfo) oldInfo).getReturnTypeName(),
+ ((SourceMethodElementInfo) newInfo).getReturnTypeName())) {
+ this.delta.changed(newElement, IJavaElementDelta.F_CONTENT);
+ }
+ } else
+ if (oldInfo instanceof SourceFieldElementInfo
+ && newInfo instanceof SourceFieldElementInfo) {
+ if (!CharOperation
+ .equals(
+ ((SourceFieldElementInfo) oldInfo).getTypeName(),
+ ((SourceFieldElementInfo) newInfo).getTypeName())) {
+ this.delta.changed(newElement, IJavaElementDelta.F_CONTENT);
+ }
+ }
+ }
+ if (oldInfo instanceof SourceTypeElementInfo
+ && newInfo instanceof SourceTypeElementInfo) {
+ SourceTypeElementInfo oldSourceTypeInfo = (SourceTypeElementInfo) oldInfo;
+ SourceTypeElementInfo newSourceTypeInfo = (SourceTypeElementInfo) newInfo;
+ if (!CharOperation
+ .equals(
+ oldSourceTypeInfo.getSuperclassName(),
+ newSourceTypeInfo.getSuperclassName())
+ || !CharOperation.equals(
+ oldSourceTypeInfo.getInterfaceNames(),
+ newSourceTypeInfo.getInterfaceNames())) {
+ this.delta.changed(newElement, IJavaElementDelta.F_SUPER_TYPES);
+ }
+ }
+ }
+
+ /**
+ * Adds removed deltas for any handles left in the table
+ */
+ private void findDeletions() {
+ Enumeration keys = this.infos.keys();
+ while (keys.hasMoreElements()) {
+ IJavaElement element = (IJavaElement) keys.nextElement();
+ this.delta.removed(element);
+ this.removed(element);
+ }
+ }
+
+ private JavaElementInfo getElementInfo(IJavaElement element) {
+ return (JavaElementInfo) this.infos.get(element);
+ }
+
+ private ListItem getNewPosition(IJavaElement element) {
+ return (ListItem) this.newPositions.get(element);
+ }
+
+ private ListItem getOldPosition(IJavaElement element) {
+ return (ListItem) this.oldPositions.get(element);
+ }
+
+ private void initialize() {
+ this.infos = new Hashtable(20);
+ this.oldPositions = new Hashtable(20);
+ this.newPositions = new Hashtable(20);
+ this.putOldPosition(this.javaElement, new ListItem(null, null));
+ this.putNewPosition(this.javaElement, new ListItem(null, null));
+ this.delta = new JavaElementDelta(javaElement);
+ this.added = new Vector(5);
+ this.removed = new Vector(5);
+ }
+
+ /**
+ * Inserts position information for the elements into the new or old positions table
+ */
+ private void insertPositions(IJavaElement[] elements, boolean isNew) {
+ int length = elements.length;
+ IJavaElement previous = null,
+ current = null,
+ next = (length > 0) ? elements[0] : null;
+ for (int i = 0; i < length; i++) {
+ previous = current;
+ current = next;
+ next = (i + 1 < length) ? elements[i + 1] : null;
+ if (isNew) {
+ this.putNewPosition(current, new ListItem(previous, next));
+ } else {
+ this.putOldPosition(current, new ListItem(previous, next));
+ }
+ }
+ }
+
+ /**
+ * Returns true if the given elements represent the an equivalent declaration.
+ *
+ * <p>NOTE: Since this comparison can be done with handle info only,
+ * none of the internal calls need to use the locally cached contents
+ * of the old compilation unit.
+ */
+ private boolean isIdentical(JavaElement e1, JavaElement e2) {
+ if (e1 == null ^ e2 == null)
+ return false;
+ if (e1 == null)
+ return true;
+
+ if (e1.fLEType == e2.fLEType) {
+ if (e1.getOccurrenceCount() != e2.getOccurrenceCount())
+ return false;
+ switch (e1.fLEType) {
+ case IJavaElement.FIELD :
+ case IJavaElement.IMPORT_DECLARATION :
+ case IJavaElement.PACKAGE_DECLARATION :
+ case IJavaElement.COMPILATION_UNIT :
+ return e1.getElementName().equals(e2.getElementName());
+ case IJavaElement.TYPE :
+ IType t1 = (IType) e1;
+ IType t2 = (IType) e2;
+ try {
+ return (
+ !(t1.isClass() ^ t2.isClass())
+ && t1.getElementName().equals(t2.getElementName()));
+ } catch (JavaModelException e) {
+ return false;
+ }
+ case IJavaElement.METHOD :
+ IMethod m1 = (IMethod) e1;
+ IMethod m2 = (IMethod) e2;
+ try {
+ return m1.getElementName().equals(m2.getElementName())
+ && m1.getSignature().equals(m2.getSignature());
+ } catch (JavaModelException e) {
+ return false;
+ }
+ case IJavaElement.INITIALIZER :
+ case IJavaElement.IMPORT_CONTAINER :
+ return true;
+ default :
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Answers true if the elements position has not changed.
+ * Takes into account additions so that elements following
+ * new elements will not appear out of place.
+ */
+ private boolean isPositionedCorrectly(IJavaElement element) {
+ ListItem oldListItem = this.getOldPosition(element);
+ if (oldListItem == null)
+ return false;
+ IJavaElement oldPrevious = oldListItem.previous;
+ ListItem newListItem = this.getNewPosition(element);
+ if (newListItem == null)
+ return false;
+ IJavaElement newPrevious = newListItem.previous;
+ if (oldPrevious == newPrevious)
+ return true;
+ IJavaElement lastNewPrevious = null;
+ while (lastNewPrevious != newPrevious) {
+ if (isIdentical((JavaElement) oldPrevious, (JavaElement) newPrevious))
+ return true;
+ lastNewPrevious = newPrevious;
+ // if newPrevious is null at this time we should exit the loop.
+ if (newPrevious == null)
+ break;
+ newPrevious = (this.getNewPosition(newPrevious)).previous;
+ }
+ return false;
+ }
+
+ private void putElementInfo(IJavaElement element, JavaElementInfo info) {
+ this.infos.put(element, info);
+ }
+
+ private void putNewPosition(IJavaElement element, ListItem position) {
+ this.newPositions.put(element, position);
+ }
+
+ private void putOldPosition(IJavaElement element, ListItem position) {
+ this.oldPositions.put(element, position);
+ }
+
+ /**
+ * Records this elements info, and attempts
+ * to record the info for the children.
+ */
+ private void recordElementInfo(
+ IJavaElement element,
+ JavaModel model,
+ int depth) {
+ if (depth >= this.maxDepth) {
+ return;
+ }
+ JavaElementInfo info =
+ (JavaElementInfo) model.fgJavaModelManager.getInfo(element);
+ if (info == null) // no longer in the java model.
+ return;
+ this.putElementInfo(element, info);
+
+ if (element instanceof IParent) {
+ IJavaElement[] children = info.getChildren();
+ if (children != null) {
+ insertPositions(children, false);
+ for (int i = 0, length = children.length; i < length; i++)
+ recordElementInfo(children[i], model, depth + 1);
+ }
+ }
+ }
+
+ /**
+ * Fills the newPositions hashtable with the new position information
+ */
+ private void recordNewPositions(IJavaElement newElement, int depth) {
+ if (depth < this.maxDepth && newElement instanceof IParent) {
+ JavaElementInfo info = null;
+ try {
+ info = ((JavaElement) newElement).getElementInfo();
+ } catch (JavaModelException npe) {
+ return;
+ }
+
+ IJavaElement[] children = info.getChildren();
+ if (children != null) {
+ insertPositions(children, true);
+ for (int i = 0, length = children.length; i < length; i++) {
+ recordNewPositions(children[i], depth + 1);
+ }
+ }
+ }
+ }
+
+ /**
+ * Repairs the positioning information
+ * after an element has been removed
+ */
+ private void removed(IJavaElement element) {
+ this.removed.addElement(element);
+ ListItem current = this.getOldPosition(element);
+ ListItem previous = null, next = null;
+ if (current.previous != null)
+ previous = this.getOldPosition(current.previous);
+ if (current.next != null)
+ next = this.getOldPosition(current.next);
+ if (previous != null)
+ previous.next = current.next;
+ if (next != null)
+ next.previous = current.previous;
+
+ }
+
+ private void removeElementInfo(IJavaElement element) {
+ this.infos.remove(element);
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("Built delta:\n");
+ buffer.append(this.delta.toString());
+ return buffer.toString();
+ }
+
+ /**
+ * Trims deletion deltas to only report the highest level of deletion
+ */
+ private void trimDelta(JavaElementDelta delta) {
+ if (delta.getKind() == IJavaElementDelta.REMOVED) {
+ IJavaElementDelta[] children = delta.getAffectedChildren();
+ for (int i = 0, length = children.length; i < length; i++) {
+ delta.removeAffectedChild((JavaElementDelta) children[i]);
+ }
+ } else {
+ IJavaElementDelta[] children = delta.getAffectedChildren();
+ for (int i = 0, length = children.length; i < length; i++) {
+ trimDelta((JavaElementDelta) children[i]);
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementInfo.java
new file mode 100644
index 0000000000..d065723c4d
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementInfo.java
@@ -0,0 +1,146 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.IAdaptable;
+
+import org.eclipse.jdt.core.*;
+
+import java.util.Vector;
+
+/**
+ * Holds cached structure and properties for a Java element.
+ * Subclassed to carry properties for specific kinds of elements.
+ */
+/* package */
+class JavaElementInfo {
+
+ /**
+ * Collection of handles of immediate children of this
+ * object. This is an empty array if this element has
+ * no children.
+ */
+ protected IJavaElement[] fChildren;
+
+ /**
+ * Shared empty collection used for efficiency.
+ */
+ protected static IJavaElement[] fgEmptyChildren = new IJavaElement[] {
+ };
+
+ /**
+ * Is the structure of this element known
+ * @see IJavaElement.isStructureKnown()
+ */
+ protected boolean fIsStructureKnown = false;
+
+ /**
+ * Shared empty collection used for efficiency.
+ */
+ static Object[] NO_NON_JAVA_RESOURCES = new Object[] {
+ };
+
+ protected JavaElementInfo() {
+ fChildren = fgEmptyChildren;
+ }
+
+ public void addChild(IJavaElement child) {
+ if (fChildren == fgEmptyChildren) {
+ setChildren(new IJavaElement[] { child });
+ } else {
+ if (!includesChild(child)) {
+ setChildren(growAndAddToArray(fChildren, child));
+ }
+ }
+ }
+
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new Error();
+ }
+ }
+
+ public IJavaElement[] getChildren() {
+ return fChildren;
+ }
+
+ /**
+ * Adds the new element to a new array that contains all of the elements of the old array.
+ * Returns the new array.
+ */
+ protected IJavaElement[] growAndAddToArray(
+ IJavaElement[] array,
+ IJavaElement addition) {
+ IJavaElement[] old = array;
+ array = new IJavaElement[old.length + 1];
+ System.arraycopy(old, 0, array, 0, old.length);
+ array[old.length] = addition;
+ return array;
+ }
+
+ /**
+ * Returns <code>true</code> if this child is in my children collection
+ */
+ protected boolean includesChild(IJavaElement child) {
+
+ for (int i = 0; i < fChildren.length; i++) {
+ if (fChildren[i].equals(child)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @see IJavaElement.isStructureKnown()
+ */
+ public boolean isStructureKnown() {
+ return fIsStructureKnown;
+ }
+
+ /**
+ * Returns an array with all the same elements as the specified array except for
+ * the element to remove. Assumes that the deletion is contained in the array.
+ */
+ protected IJavaElement[] removeAndShrinkArray(
+ IJavaElement[] array,
+ IJavaElement deletion) {
+ IJavaElement[] old = array;
+ array = new IJavaElement[old.length - 1];
+ int j = 0;
+ for (int i = 0; i < old.length; i++) {
+ if (!old[i].equals(deletion)) {
+ array[j] = old[i];
+ } else {
+ System.arraycopy(old, i + 1, array, j, old.length - (i + 1));
+ return array;
+ }
+ j++;
+ }
+ return array;
+ }
+
+ public void removeChild(IJavaElement child) {
+ if (includesChild(child)) {
+ setChildren(removeAndShrinkArray(fChildren, child));
+ }
+ }
+
+ public void setChildren(IJavaElement[] children) {
+ fChildren = children;
+ }
+
+ /**
+ * Sets whether the structure of this element known
+ * @see IJavaElement.isStructureKnown()
+ */
+ public void setIsStructureKnown(boolean newIsStructureKnown) {
+ fIsStructureKnown = newIsStructureKnown;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementRequestor.java
new file mode 100644
index 0000000000..f54a7db183
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementRequestor.java
@@ -0,0 +1,234 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+
+import java.util.Vector;
+
+/**
+ * @see IJavaElementRequestor
+ */
+
+public class JavaElementRequestor implements IJavaElementRequestor {
+ /**
+ * True if this requestor no longer wants to receive
+ * results from its <code>IRequestorNameLookup</code>.
+ */
+ protected boolean fCanceled = false;
+
+ /**
+ * A collection of the resulting fields, or <code>null</code>
+ * if no field results have been received.
+ */
+ protected Vector fFields = null;
+
+ /**
+ * A collection of the resulting initializers, or <code>null</code>
+ * if no initializer results have been received.
+ */
+ protected Vector fInitializers = null;
+
+ /**
+ * A collection of the resulting member types, or <code>null</code>
+ * if no member type results have been received.
+ */
+ protected Vector fMemberTypes = null;
+
+ /**
+ * A collection of the resulting methods, or <code>null</code>
+ * if no method results have been received.
+ */
+ protected Vector fMethods = null;
+
+ /**
+ * A collection of the resulting package fragments, or <code>null</code>
+ * if no package fragment results have been received.
+ */
+ protected Vector fPackageFragments = null;
+
+ /**
+ * A collection of the resulting types, or <code>null</code>
+ * if no type results have been received.
+ */
+ protected Vector fTypes = null;
+
+ /**
+ * Empty arrays used for efficiency
+ */
+ protected static IField[] fgEmptyFieldArray = new IField[0];
+ protected static IInitializer[] fgEmptyInitializerArray = new IInitializer[0];
+ protected static IType[] fgEmptyTypeArray = new IType[0];
+ protected static IPackageFragment[] fgEmptyPackageFragmentArray =
+ new IPackageFragment[0];
+ protected static IMethod[] fgEmptyMethodArray = new IMethod[0];
+ /**
+ * @see IJavaElementRequestor
+ */
+ public void acceptField(IField field) {
+ if (fFields == null) {
+ fFields = new Vector();
+ }
+ fFields.addElement(field);
+ }
+
+ /**
+ * @see IJavaElementRequestor
+ */
+ public void acceptInitializer(IInitializer initializer) {
+ if (fInitializers == null) {
+ fInitializers = new Vector();
+ }
+ fInitializers.addElement(initializer);
+ }
+
+ /**
+ * @see IJavaElementRequestor
+ */
+ public void acceptMemberType(IType type) {
+ if (fMemberTypes == null) {
+ fMemberTypes = new Vector();
+ }
+ fMemberTypes.addElement(type);
+ }
+
+ /**
+ * @see IJavaElementRequestor
+ */
+ public void acceptMethod(IMethod method) {
+ if (fMethods == null) {
+ fMethods = new Vector();
+ }
+ fMethods.addElement(method);
+ }
+
+ /**
+ * @see IJavaElementRequestor
+ */
+ public void acceptPackageFragment(IPackageFragment packageFragment) {
+ if (fPackageFragments == null) {
+ fPackageFragments = new Vector();
+ }
+ fPackageFragments.addElement(packageFragment);
+ }
+
+ /**
+ * @see IJavaElementRequestor
+ */
+ public void acceptType(IType type) {
+ if (fTypes == null) {
+ fTypes = new Vector();
+ }
+ fTypes.addElement(type);
+ }
+
+ /**
+ * @see IJavaElementRequestor
+ */
+ public IField[] getFields() {
+ if (fFields == null) {
+ return fgEmptyFieldArray;
+ }
+ int size = fFields.size();
+ IField[] results = new IField[size];
+ fFields.copyInto(results);
+ return results;
+ }
+
+ /**
+ * @see IJavaElementRequestor
+ */
+ public IInitializer[] getInitializers() {
+ if (fInitializers == null) {
+ return fgEmptyInitializerArray;
+ }
+ int size = fInitializers.size();
+ IInitializer[] results = new IInitializer[size];
+ fInitializers.copyInto(results);
+ return results;
+ }
+
+ /**
+ * @see IJavaElementRequestor
+ */
+ public IType[] getMemberTypes() {
+ if (fMemberTypes == null) {
+ return fgEmptyTypeArray;
+ }
+ int size = fMemberTypes.size();
+ IType[] results = new IType[size];
+ fMemberTypes.copyInto(results);
+ return results;
+ }
+
+ /**
+ * @see IJavaElementRequestor
+ */
+ public IMethod[] getMethods() {
+ if (fMethods == null) {
+ return fgEmptyMethodArray;
+ }
+ int size = fMethods.size();
+ IMethod[] results = new IMethod[size];
+ fMethods.copyInto(results);
+ return results;
+ }
+
+ /**
+ * @see IJavaElementRequestor
+ */
+ public IPackageFragment[] getPackageFragments() {
+ if (fPackageFragments == null) {
+ return fgEmptyPackageFragmentArray;
+ }
+ int size = fPackageFragments.size();
+ IPackageFragment[] results = new IPackageFragment[size];
+ fPackageFragments.copyInto(results);
+ return results;
+ }
+
+ /**
+ * @see IJavaElementRequestor
+ */
+ public IType[] getTypes() {
+ if (fTypes == null) {
+ return fgEmptyTypeArray;
+ }
+ int size = fTypes.size();
+ IType[] results = new IType[size];
+ fTypes.copyInto(results);
+ return results;
+ }
+
+ /**
+ * @see IJavaElementRequestor
+ */
+ public boolean isCanceled() {
+ return fCanceled;
+ }
+
+ /**
+ * Reset the state of this requestor.
+ */
+ public void reset() {
+ fCanceled = false;
+ fFields = null;
+ fInitializers = null;
+ fMemberTypes = null;
+ fMethods = null;
+ fPackageFragments = null;
+ fTypes = null;
+ }
+
+ /**
+ * Sets the #isCanceled state of this requestor to true or false.
+ */
+ public void setCanceled(boolean b) {
+ fCanceled = b;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModel.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModel.java
new file mode 100644
index 0000000000..4a194fb330
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModel.java
@@ -0,0 +1,647 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.internal.compiler.ConfigurableOption;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.core.util.*;
+
+import java.io.File;
+import java.util.*;
+
+/**
+ * Implementation of <code>IJavaModel<code>. The Java Model maintains a cache of
+ * active <code>IJavaProject</code>s in a workspace. A Java Model is specific to a
+ * workspace. To retrieve a workspace's model, use the
+ * <code>#getJavaModel(IWorkspace)</code> method.
+ *
+ * @see IJavaModel
+ */
+public class JavaModel extends Openable implements IJavaModel {
+ /**
+ * The workspace this Java Model represents
+ */
+ protected IWorkspace workspace = null;
+
+ /**
+ * Constructs a new Java Model on the given workspace.
+ *
+ * @exception Error if called more than once
+ */
+ protected JavaModel(IWorkspace workspace) throws Error {
+ super(JAVA_MODEL, null, "" /*workspace has empty name*/);
+ this.workspace = workspace;
+ }
+
+ private void cleanupCycleMarkers() {
+ try {
+ IMarker[] markers =
+ workspace.getRoot().findMarkers(
+ IJavaModelMarker.TRANSIENT_PROBLEM,
+ true,
+ IResource.DEPTH_ONE);
+ for (int i = 0, length = markers.length; i < length; i++) {
+ IMarker marker = markers[i];
+ if (marker.getAttribute(IJavaModelMarker.CYCLE_DETECTED) != null) {
+ workspace.deleteMarkers(new IMarker[] { marker });
+ }
+ }
+ } catch (CoreException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Remove the Java Model from the cache
+ */
+ protected void closing(Object info) throws JavaModelException {
+ JavaModelManager.fgManager.fModelInfo.close();
+ JavaModelManager.fgManager.fModelInfo = null;
+ }
+
+ /**
+ * Computes the build order of the Java Projects in this Java Model.
+ * The order is computed by following the class path of the projects.
+ * Prerequesite projects appear first in the list, dependent projects
+ * appear last.
+ * If specified, reports an error against a project using a marker if a cycle
+ * is detected. Otherwise throws a JavaModelException.
+ */
+ public String[] computeBuildOrder(boolean generateMarkerOnError)
+ throws JavaModelException {
+ // Remove markers indicating cycle
+ if (generateMarkerOnError) {
+ this.cleanupCycleMarkers();
+ }
+
+ // Compute depth of each project and detect cycle
+ StringHashtableOfInt depthTable = new StringHashtableOfInt();
+ IJavaProject[] projects = getJavaProjects();
+ int length = projects.length;
+ int maxDepth = -1;
+ for (int i = 0; i < length; i++) {
+ String projectName = projects[i].getElementName();
+ maxDepth =
+ Math.max(
+ maxDepth,
+ this.computeDepth(projectName, depthTable, projectName, generateMarkerOnError));
+ }
+
+ // Sort projects by depth
+ return depthTable.sortedKeys(maxDepth);
+ }
+
+ /**
+ * Computes the depth of the given java project following its classpath.
+ * Only projects are taken into consideration. Store the depth in the given table.
+ * Returns the depth.
+ * Note that a project with no prerequisites has a depth of 0.
+ * Returns -1 if a cycle is detected
+ */
+ protected int computeDepth(
+ String projectName,
+ StringHashtableOfInt depthTable,
+ String dependentProjectName,
+ boolean generateMarkerOnError)
+ throws JavaModelException {
+ int depth = depthTable.get(projectName);
+ switch (depth) {
+ case -2 : // project already visited -> it's a cycle
+ if (generateMarkerOnError) {
+ try {
+ IMarker marker =
+ this.workspace.getRoot().getProject(dependentProjectName).createMarker(
+ IJavaModelMarker.TRANSIENT_PROBLEM);
+ marker.setAttribute(
+ IMarker.MESSAGE,
+ "A cycle was detected in the project's classpath");
+ marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH);
+ marker.setAttribute(IMarker.LOCATION, dependentProjectName);
+ marker.setAttribute(IJavaModelMarker.CYCLE_DETECTED, dependentProjectName);
+ } catch (CoreException e) {
+ e.printStackTrace();
+ }
+ } else {
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION));
+ }
+ return -1;
+ case -1 :
+ depthTable.put(projectName, -2); // mark we're visiting the project
+ int prereqDepth = -1;
+ JavaProject project = (JavaProject) this.getJavaProject(projectName);
+ String[] prerequisites = null;
+ try {
+ prerequisites = project.getRequiredProjectNames();
+ } catch (JavaModelException e) {
+ prerequisites = JavaProject.NO_PREREQUISITES;
+ }
+ for (int i = 0, length = prerequisites.length; i < length; i++) {
+ String prerequisite = prerequisites[i];
+ prereqDepth =
+ Math.max(
+ prereqDepth,
+ this.computeDepth(
+ prerequisite,
+ depthTable,
+ projectName,
+ generateMarkerOnError));
+ }
+ depth = 1 + prereqDepth;
+ depthTable.put(projectName, depth);
+ return depth;
+ default :
+ return depth;
+ }
+ }
+
+ /**
+ * @see IJavaModel
+ */
+ public void copy(
+ IJavaElement[] elements,
+ IJavaElement[] containers,
+ IJavaElement[] siblings,
+ String[] renamings,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ if (elements != null
+ && elements[0] != null
+ && elements[0].getElementType() < IJavaElement.TYPE) {
+ runOperation(
+ new CopyResourceElementsOperation(elements, containers, force),
+ elements,
+ siblings,
+ renamings,
+ monitor);
+ } else {
+ runOperation(
+ new CopyElementsOperation(elements, containers, force),
+ elements,
+ siblings,
+ renamings,
+ monitor);
+ }
+ }
+
+ /**
+ * Returns a new element info for this element.
+ */
+ protected OpenableElementInfo createElementInfo() {
+ return new JavaModelInfo(this, this.workspace);
+ }
+
+ /**
+ * @see IJavaModel
+ */
+ public void delete(
+ IJavaElement[] elements,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ if (elements != null
+ && elements[0] != null
+ && elements[0].getElementType() < IJavaElement.TYPE) {
+ runOperation(new DeleteResourceElementsOperation(elements, force), monitor);
+ } else {
+ runOperation(new DeleteElementsOperation(elements, force), monitor);
+ }
+ }
+
+ /**
+ * Java Models are equal if their workspaces are equal
+ *
+ * @see Object#equals
+ */
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o instanceof JavaModel) {
+ JavaModel other = (JavaModel) o;
+ return this.workspace.equals(other.workspace);
+ }
+ return false;
+ }
+
+ /**
+ */
+ protected boolean generateInfos(
+ OpenableElementInfo info,
+ IProgressMonitor pm,
+ Hashtable newElements,
+ IResource underlyingResource)
+ throws JavaModelException {
+
+ fgJavaModelManager.fModelInfo = (JavaModelInfo) info;
+ // determine my children
+ try {
+ IProject[] projects = workspace.getRoot().getProjects();
+ for (int i = 0, max = projects.length; i < max; i++) {
+ IProject project = projects[i];
+ if (project.isOpen() && project.hasNature(JavaCore.NATURE_ID)) {
+ info.addChild(getJavaProject(project));
+ }
+ }
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ }
+ return true;
+ }
+
+ /**
+ * Returns the <code>IJavaElement</code> represented by the <code>String</code>
+ * memento.
+ * @see getHandleMemento()
+ */
+ protected IJavaElement getHandleFromMementoForBinaryMembers(
+ String memento,
+ IPackageFragmentRoot root,
+ int rootEnd,
+ int end)
+ throws JavaModelException {
+
+ //deal with class file and binary members
+ IPackageFragment frag = null;
+ if (rootEnd == end - 1) {
+ //default package
+ frag = root.getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME);
+ } else {
+ frag = root.getPackageFragment(memento.substring(rootEnd + 1, end));
+ }
+ int oldEnd = end;
+ end = memento.indexOf(JavaElement.JEM_TYPE, oldEnd);
+ if (end == -1) {
+ //we ended with a class file
+ return frag.getClassFile(memento.substring(oldEnd + 1));
+ }
+ IClassFile cf = frag.getClassFile(memento.substring(oldEnd + 1, end));
+ oldEnd = end;
+ end = memento.indexOf(JavaElement.JEM_TYPE, oldEnd);
+ oldEnd = end;
+ end = memento.indexOf(JavaElement.JEM_FIELD, end);
+ if (end != -1) {
+ //binary field
+ IType type = cf.getType();
+ return type.getField(memento.substring(end + 1));
+ }
+ end = memento.indexOf(JavaElement.JEM_METHOD, oldEnd);
+ if (end != -1) {
+ //binary method
+ oldEnd = end;
+ IType type = cf.getType();
+ String methodName;
+ end = memento.lastIndexOf(JavaElement.JEM_METHOD);
+ String[] parameterTypes = null;
+ if (end == oldEnd) {
+ methodName = memento.substring(end + 1);
+ //no parameter types
+ parameterTypes = new String[] {
+ };
+ } else {
+ String parameters = memento.substring(oldEnd + 1);
+ StringTokenizer tokenizer =
+ new StringTokenizer(
+ parameters,
+ new String(new char[] { JavaElement.JEM_METHOD }));
+ parameterTypes = new String[tokenizer.countTokens() - 1];
+ methodName = tokenizer.nextToken();
+ int i = 0;
+ while (tokenizer.hasMoreTokens()) {
+ parameterTypes[i] = tokenizer.nextToken();
+ i++;
+ }
+ }
+ return type.getMethod(methodName, parameterTypes);
+ }
+
+ //binary type
+ return cf.getType();
+ }
+
+ /**
+ * Returns the <code>IJavaElement</code> represented by the <code>String</code>
+ * memento.
+ * @see getHandleMemento()
+ */
+ protected IJavaElement getHandleFromMementoForSourceMembers(
+ String memento,
+ IPackageFragmentRoot root,
+ int rootEnd,
+ int end)
+ throws JavaModelException {
+
+ //deal with compilation units and source members
+ IPackageFragment frag = null;
+ if (rootEnd == end - 1) {
+ //default package
+ frag = root.getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME);
+ } else {
+ frag = root.getPackageFragment(memento.substring(rootEnd + 1, end));
+ }
+ int oldEnd = end;
+ end = memento.indexOf(JavaElement.JEM_PACKAGEDECLARATION, end);
+ if (end != -1) {
+ //package declaration
+ ICompilationUnit cu =
+ frag.getCompilationUnit(memento.substring(oldEnd + 1, end));
+ return cu.getPackageDeclaration(memento.substring(end + 1));
+ }
+ end = memento.indexOf(JavaElement.JEM_IMPORTDECLARATION, oldEnd);
+ if (end != -1) {
+ //import declaration
+ ICompilationUnit cu =
+ frag.getCompilationUnit(memento.substring(oldEnd + 1, end));
+ return cu.getImport(memento.substring(end + 1));
+ }
+ int typeStart = memento.indexOf(JavaElement.JEM_TYPE, oldEnd);
+ if (typeStart == -1) {
+ //we ended with a compilation unit
+ return frag.getCompilationUnit(memento.substring(oldEnd + 1));
+ }
+
+ //source members
+ ICompilationUnit cu =
+ frag.getCompilationUnit(memento.substring(oldEnd + 1, typeStart));
+ end = memento.indexOf(JavaElement.JEM_FIELD, oldEnd);
+ if (end != -1) {
+ //source field
+ IType type = getHandleFromMementoForSourceType(memento, cu, typeStart, end);
+ return type.getField(memento.substring(end + 1));
+ }
+ end = memento.indexOf(JavaElement.JEM_METHOD, oldEnd);
+ if (end != -1) {
+ //source method
+ IType type = getHandleFromMementoForSourceType(memento, cu, typeStart, end);
+ oldEnd = end;
+ String methodName;
+ end = memento.lastIndexOf(JavaElement.JEM_METHOD);
+ String[] parameterTypes = null;
+ if (end == oldEnd) {
+ methodName = memento.substring(end + 1);
+ //no parameter types
+ parameterTypes = new String[] {
+ };
+ } else {
+ String parameters = memento.substring(oldEnd + 1);
+ StringTokenizer mTokenizer =
+ new StringTokenizer(
+ parameters,
+ new String(new char[] { JavaElement.JEM_METHOD }));
+ parameterTypes = new String[mTokenizer.countTokens() - 1];
+ methodName = mTokenizer.nextToken();
+ int i = 0;
+ while (mTokenizer.hasMoreTokens()) {
+ parameterTypes[i] = mTokenizer.nextToken();
+ i++;
+ }
+ }
+ return type.getMethod(methodName, parameterTypes);
+ }
+
+ end = memento.indexOf(JavaElement.JEM_INITIALIZER, oldEnd);
+ if (end != -1) {
+ //initializer
+ IType type = getHandleFromMementoForSourceType(memento, cu, typeStart, end);
+ return type.getInitializer(Integer.parseInt(memento.substring(end + 1)));
+ }
+ //source type
+ return getHandleFromMementoForSourceType(
+ memento,
+ cu,
+ typeStart,
+ memento.length());
+ ;
+ }
+
+ /**
+ * Returns the <code>IJavaElement</code> represented by the <code>String</code>
+ * memento.
+ * @see getHandleMemento()
+ */
+ protected IType getHandleFromMementoForSourceType(
+ String memento,
+ ICompilationUnit cu,
+ int typeStart,
+ int typeEnd)
+ throws JavaModelException {
+ int end = memento.lastIndexOf(JavaElement.JEM_TYPE);
+ IType type = null;
+ if (end == typeStart) {
+ String typeName = memento.substring(typeStart + 1, typeEnd);
+ type = cu.getType(typeName);
+
+ } else {
+ String typeNames = memento.substring(typeStart + 1, typeEnd);
+ StringTokenizer tokenizer =
+ new StringTokenizer(typeNames, new String(new char[] { JavaElement.JEM_TYPE }));
+ type = cu.getType(tokenizer.nextToken());
+ while (tokenizer.hasMoreTokens()) {
+ //deal with inner types
+ type = type.getType(tokenizer.nextToken());
+ }
+ }
+ return type;
+ }
+
+ /**
+ * @see JavaElement#getHandleMemento()
+ */
+ public String getHandleMemento() {
+ return getElementName();
+ }
+
+ /**
+ * Returns the <code>char</code> that marks the start of this handles
+ * contribution to a memento.
+ */
+ protected char getHandleMementoDelimiter() {
+ throw new Error("should not be called");
+ }
+
+ /**
+ * @see IJavaElement
+ */
+ public IJavaModel getJavaModel() {
+ return this;
+ }
+
+ /**
+ * @see IJavaElement
+ */
+ public IJavaProject getJavaProject() {
+ return null;
+ }
+
+ /**
+ * @see IJavaModel
+ */
+ public IJavaProject getJavaProject(String name) {
+ return new JavaProject(this.workspace.getRoot().getProject(name), this);
+ }
+
+ /**
+ * Returns the active Java project associated with the specified
+ * resource, or <code>null</code> if no Java project yet exists
+ * for the resource.
+ *
+ * @exception IllegalArgumentException if the given resource
+ * is not one of an IProject, IFolder, or IFile.
+ */
+ public IJavaProject getJavaProject(IResource resource) {
+ if (resource.getType() == IResource.FOLDER) {
+ return new JavaProject(((IFolder) resource).getProject(), this);
+ } else
+ if (resource.getType() == IResource.FILE) {
+ return new JavaProject(((IFile) resource).getProject(), this);
+ } else
+ if (resource.getType() == IResource.PROJECT) {
+ return new JavaProject((IProject) resource, this);
+ } else {
+ throw new IllegalArgumentException("Illegal argument - must be one of IProject, IFolder, or IFile");
+ }
+ }
+
+ /**
+ * @see IJavaModel
+ */
+ public IJavaProject[] getJavaProjects() throws JavaModelException {
+ Vector v = getChildrenOfType(JAVA_PROJECT);
+ IJavaProject[] array = new IJavaProject[v.size()];
+ v.copyInto(array);
+ return array;
+
+ }
+
+ /**
+ * Helper method - returns the targeted item (IResource if internal or java.io.File if external),
+ * or null if unbound
+ * Internal items must be referred to using container relative paths.
+ */
+ public static Object getTarget(IContainer container, IPath path) {
+
+ if (path == null)
+ return null;
+
+ // lookup - inside the container
+ IResource resource = container.findMember(path);
+ if (resource != null)
+ return resource;
+
+ // lookup - outside the container
+ File externalFile = new File(path.toOSString());
+ if (externalFile.exists())
+ return externalFile;
+ return null;
+ }
+
+ /**
+ * @see IOpenable
+ */
+ public IResource getUnderlyingResource() throws JavaModelException {
+ return null;
+ }
+
+ /**
+ * Returns the workbench associated with this object.
+ */
+ public IWorkspace getWorkspace() {
+ return this.workspace;
+ }
+
+ /**
+ * The hashcode of a Java Model is that of its workspace.
+ */
+ public int hashCode() {
+ return this.workspace.hashCode();
+ }
+
+ /**
+ * @see IJavaModel
+ */
+ public void move(
+ IJavaElement[] elements,
+ IJavaElement[] containers,
+ IJavaElement[] siblings,
+ String[] renamings,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ if (elements != null
+ && elements[0] != null
+ && elements[0].getElementType() < IJavaElement.TYPE) {
+ runOperation(
+ new MoveResourceElementsOperation(elements, containers, force),
+ elements,
+ siblings,
+ renamings,
+ monitor);
+ } else {
+ runOperation(
+ new MoveElementsOperation(elements, containers, force),
+ elements,
+ siblings,
+ renamings,
+ monitor);
+ }
+ }
+
+ /**
+ * @see IJavaModel
+ */
+ public void rename(
+ IJavaElement[] elements,
+ IJavaElement[] destinations,
+ String[] renamings,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ MultiOperation op;
+ if (elements != null
+ && elements[0] != null
+ && elements[0].getElementType() < IJavaElement.TYPE) {
+ op =
+ new RenameResourceElementsOperation(elements, destinations, renamings, force);
+ } else {
+ op = new RenameElementsOperation(elements, destinations, renamings, force);
+ }
+
+ runOperation(op, monitor);
+ }
+
+ /**
+ * Configures and runs the <code>MultiOperation</code>.
+ */
+ protected void runOperation(
+ MultiOperation op,
+ IJavaElement[] elements,
+ IJavaElement[] siblings,
+ String[] renamings,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ op.setRenamings(renamings);
+ if (siblings != null) {
+ for (int i = 0; i < elements.length; i++) {
+ op.setInsertBefore(elements[i], siblings[i]);
+ }
+ }
+ runOperation(op, monitor);
+ }
+
+ /**
+ * @private Debugging purposes
+ */
+ protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+ buffer.append("Java Model");
+ if (info == null) {
+ buffer.append(" (not open)");
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelInfo.java
new file mode 100644
index 0000000000..c29f5fd441
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelInfo.java
@@ -0,0 +1,88 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.IJavaModelStatusConstants;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IOpenable;
+import org.eclipse.jdt.core.IJavaModel;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.zip.ZipFile;
+
+/**
+ * Implementation of IJavaModel. The Java Model maintains a cache of
+ * active IJavaProjects in a workspace. A Java Model is specific to a
+ * workspace. To retrieve a workspace's model, use the
+ * <code>#getJavaModel(IWorkspace)</code> method.
+ *
+ * @see IJavaModel
+ */
+public class JavaModelInfo extends OpenableElementInfo {
+
+ /**
+ * Cache of open openable Java Model Java elements
+ */
+ protected OverflowingLRUCache fLRUCache = null;
+
+ /**
+ * Cache of open children of openable Java Model Java elements
+ */
+ protected Hashtable fChildrenCache = null;
+
+ /**
+ * Set of elements which are out of sync with their buffers.
+ */
+ protected Hashtable fElementsOutOfSynchWithBuffers = new Hashtable(11);
+
+ /**
+ * Backpointer to my Java Model handle
+ */
+ protected IJavaModel fJavaModel = null;
+
+ /**
+ * The workspace this Java Model Info corresponds to
+ */
+ protected IWorkspace workspace;
+
+ /**
+ * Constructs a new Java Model Info
+ */
+ protected JavaModelInfo(IJavaModel javaModel, IWorkspace workspace) {
+ this.workspace = workspace;
+ this.fJavaModel = javaModel;
+ this.fLRUCache = new ElementCache(5000);
+ this.fChildrenCache = new Hashtable(30000);
+ }
+
+ /**
+ * @see IJavaModel#close()
+ */
+ public void close() throws JavaModelException {
+ //close any remaining "parent-less" handles in the LRUCache
+ Enumeration handles = fLRUCache.keys();
+ while (handles.hasMoreElements()) {
+ IJavaElement handle = (IJavaElement) handles.nextElement();
+ // can't close myself - (am in the process of that now)
+ if (!handle.equals(fJavaModel)) {
+ ((IOpenable) handle).close();
+ }
+ }
+ }
+
+ /**
+ * Returns the Java Model for this info.
+ */
+ protected IJavaModel getJavaModel() {
+ return fJavaModel;
+ }
+
+}
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
new file mode 100644
index 0000000000..c12ff0f32a
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
@@ -0,0 +1,1211 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.core.resources.*;
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.core.builder.IDevelopmentContext;
+import org.eclipse.jdt.internal.core.builder.IPackage;
+import org.eclipse.jdt.internal.core.builder.IState;
+import org.eclipse.jdt.internal.core.builder.NotPresentException;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.core.builder.impl.*;
+import org.eclipse.jdt.internal.core.search.indexing.*;
+
+import java.io.*;
+import java.util.*;
+import java.util.zip.ZipFile;
+import javax.xml.parsers.*;
+import org.apache.xerces.dom.*;
+import org.apache.xml.serialize.*;
+import org.w3c.dom.*;
+import org.xml.sax.*;
+
+/**
+ * The <code>JavaModelManager</code> manages instances of <code>IJavaModel</code>.
+ * <code>IElementChangedListener</code>s register with the <code>JavaModelManager</code>,
+ * and receive <code>ElementChangedEvent</code>s for all <code>IJavaModel</code>s.
+ * <p>
+ * The single instance of <code>JavaModelManager</code> is available from
+ * the static method <code>JavaModelManager.getJavaModelManager()</code>.
+ */
+public class JavaModelManager implements IResourceChangeListener, ISaveParticipant {
+
+ /**
+ * The singleton manager
+ */
+ protected static JavaModelManager fgManager= null;
+
+ /**
+ * Active Java Model Info
+ */
+ protected JavaModelInfo fModelInfo= null;
+
+ /**
+ * Turns delta firing on/off. By default it is on.
+ */
+ protected boolean fFire= true;
+
+ /**
+ * Queue of deltas created explicily by the Java Model that
+ * have yet to be fired.
+ */
+ protected Vector fJavaModelDeltas= new Vector();
+
+ /**
+ * Queue of deltas created as translations of ResourceDeltas that
+ * have yet to be fired.
+ */
+ protected Vector fResourceDeltas= new Vector();
+
+ /**
+ * Collection of listeners for Java element deltas
+ */
+ protected Vector fElementChangedListeners= new Vector();
+
+ /**
+ * Collection of projects that are in the process of being deleted.
+ * Project reside in this cache from the time the plugin receives
+ * the #deleting message until they resource delta is received
+ * claiming the project has been deleted. The java model will not allow
+ * a project that is being deleted to be opened - since this can leave
+ * files open, causing the delete to fail.
+ *
+ * fix for 1FW67PA
+ */
+ protected Vector fProjectsBeingDeleted= new Vector();
+
+ /**
+ * Used to convert <code>IResourceDelta</code>s into <code>IJavaElementDelta</code>s.
+ */
+ protected DeltaProcessor fDeltaProcessor= new DeltaProcessor();
+
+ public static boolean ENABLE_INDEXING= true;
+ /**
+ * Local Java workspace properties file name (generated inside JavaCore plugin state location)
+ */
+ private static final String WKS_PROP_FILENAME= "workspace.properties";
+
+ /**
+ * Name of the handle id attribute in a Java marker
+ */
+ private static final String ATT_HANDLE_ID= "org.eclipse.jdt.internal.core.JavaModelManager.handleId";
+
+ /**
+ * Table from IProject to PerProjectInfo.
+ */
+ protected Hashtable perProjectInfo = new Hashtable(5);
+
+ static class PerProjectInfo {
+ IProject project;
+ IDevelopmentContext developmentContext = new JavaDevelopmentContextImpl();
+ byte[] savedStateFingerprint;
+ boolean triedRead = false;
+ PerProjectInfo(IProject project) {
+ this.project = project;
+ }
+ IState getLastBuiltState() {
+ try {
+ return developmentContext.getCurrentState();
+ } catch (NotPresentException e) {
+ return null;
+ }
+ }
+ void setLastBuiltState(IState state) {
+ developmentContext.setCurrentState(state);
+ }
+ };
+ public final static boolean VERBOSE = false;
+
+ /**
+ * Line separator to use throughout the JavaModel for any source edit operation
+ */
+ public static String LINE_SEPARATOR = System.getProperty("line.separator");
+ /**
+ * Constructs a new JavaModelManager
+ */
+ private JavaModelManager() {
+ }
+ /**
+ * addElementChangedListener method comment.
+ */
+ public void addElementChangedListener(IElementChangedListener listener) {
+ if (fElementChangedListeners.indexOf(listener) < 0) {
+ fElementChangedListeners.addElement(listener);
+ }
+ }
+/*
+ * Checks that the delta contains an added project. In this case,
+ * removes it from the list of projects being deleted.
+ */
+public void checkProjectBeingAdded(IResourceDelta delta) {
+ IResource resource = delta.getResource();
+ switch (resource.getType()) {
+ case IResource.ROOT :
+ IResourceDelta[] children = delta.getAffectedChildren();
+ for (int i = 0, length = children.length; i < length; i++) {
+ this.checkProjectBeingAdded(children[i]);
+ }
+ case IResource.PROJECT :
+ if (delta.getKind() == IResourceDelta.ADDED) {
+ fProjectsBeingDeleted.remove(delta.getResource());
+ }
+ }
+}
+/**
+ * Used when incrementally building, so as to force a partial refresh of the Java Model before it got a
+ * chance to update by itself.
+ */
+public void closeAffectedElements(IResourceDelta delta) {
+ fDeltaProcessor.closeAffectedElements(delta);
+}
+/**
+ * Convert options Map into ConfigurableOption understood by the infrastructure
+ *
+ * Should be revisited
+ */
+public static ConfigurableOption[] convertConfigurableOptions(Hashtable optionMap) {
+
+ Enumeration optionNames = optionMap.keys();
+ CompilerOptions compilerOptions = new CompilerOptions();
+ int index = 0;
+
+ while (optionNames.hasMoreElements()){
+
+ String optionName = (String)optionNames.nextElement();
+ String optionValue = (String)optionMap.get(optionName);
+
+ if (optionName.equals(JavaCore.COMPILER_LOCAL_VARIABLE_ATTR)){
+
+ if (optionValue.equals(JavaCore.GENERATE)){
+ compilerOptions.produceDebugAttributes(
+ compilerOptions.getDebugAttributesMask() | CompilerOptions.Vars);
+ continue;
+ }
+ if (optionValue.equals(JavaCore.DO_NOT_GENERATE)){
+ compilerOptions.produceDebugAttributes(
+ compilerOptions.getDebugAttributesMask() & ~CompilerOptions.Vars);
+ continue;
+ }
+ continue;
+ }
+ if (optionName.equals(JavaCore.COMPILER_LINE_NUMBER_ATTR)){
+
+ if (optionValue.equals(JavaCore.GENERATE)){
+ compilerOptions.produceDebugAttributes(
+ compilerOptions.getDebugAttributesMask() | CompilerOptions.Lines);
+ continue;
+ }
+ if (optionValue.equals(JavaCore.DO_NOT_GENERATE)){
+ compilerOptions.produceDebugAttributes(
+ compilerOptions.getDebugAttributesMask() & ~CompilerOptions.Lines);
+ continue;
+ }
+ continue;
+ }
+ if (optionName.equals(JavaCore.COMPILER_SOURCE_FILE_ATTR)){
+
+ if (optionValue.equals(JavaCore.GENERATE)){
+ compilerOptions.produceDebugAttributes(
+ compilerOptions.getDebugAttributesMask() | CompilerOptions.Source);
+ continue;
+ }
+ if (optionValue.equals(JavaCore.DO_NOT_GENERATE)){
+ compilerOptions.produceDebugAttributes(
+ compilerOptions.getDebugAttributesMask() & ~CompilerOptions.Source);
+ continue;
+ }
+ continue;
+ }
+ if (optionName.equals(JavaCore.COMPILER_CODEGEN_UNUSED_LOCAL)){
+
+ if (optionValue.equals(JavaCore.PRESERVE)){
+ compilerOptions.preserveAllLocalVariables(true);
+ continue;
+ }
+ if (optionValue.equals(JavaCore.OPTIMIZE_OUT)){
+ compilerOptions.preserveAllLocalVariables(false);
+ continue;
+ }
+ continue;
+ }
+ if (optionName.equals(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM)){
+
+ if (optionValue.equals(JavaCore.VERSION_1_1)){
+ compilerOptions.setTargetJDK(CompilerOptions.JDK1_1);
+ continue;
+ }
+ if (optionValue.equals(JavaCore.VERSION_1_2)){
+ compilerOptions.setTargetJDK(CompilerOptions.JDK1_2);
+ continue;
+ }
+ continue;
+ }
+ if (optionName.equals(JavaCore.COMPILER_PB_UNREACHABLE_CODE)){
+
+ if (optionValue.equals(JavaCore.ERROR)){
+ compilerOptions.handleUnreachableCodeAsError(true);
+ continue;
+ }
+ if (optionValue.equals(JavaCore.WARNING)){
+ compilerOptions.handleUnreachableCodeAsError(false);
+ continue;
+ }
+ continue;
+ }
+ if (optionName.equals(JavaCore.COMPILER_PB_INVALID_IMPORT)){
+
+ if (optionValue.equals(JavaCore.ERROR)){
+ compilerOptions.handleImportProblemAsError(true);
+ continue;
+ }
+ if (optionValue.equals(JavaCore.WARNING)){
+ compilerOptions.handleImportProblemAsError(false);
+ continue;
+ }
+ continue;
+ }
+
+ if (optionName.equals(JavaCore.COMPILER_PB_OVERRIDING_PACKAGE_DEFAULT_METHOD)){
+
+ if (optionValue.equals(JavaCore.WARNING)){
+ compilerOptions.handleOverriddenPackageDefaultMethodAsWarning(true);
+ continue;
+ }
+ if (optionValue.equals(JavaCore.IGNORE)){
+ compilerOptions.handleOverriddenPackageDefaultMethodAsWarning(false);
+ continue;
+ }
+ continue;
+ }
+ if (optionName.equals(JavaCore.COMPILER_PB_METHOD_WITH_CONSTRUCTOR_NAME)){
+
+ if (optionValue.equals(JavaCore.WARNING)){
+ compilerOptions.handleMethodWithConstructorNameAsWarning(true);
+ continue;
+ }
+ if (optionValue.equals(JavaCore.IGNORE)){
+ compilerOptions.handleMethodWithConstructorNameAsWarning(false);
+ continue;
+ }
+ continue;
+ }
+ if (optionName.equals(JavaCore.COMPILER_PB_DEPRECATION)){
+
+ if (optionValue.equals(JavaCore.WARNING)){
+ compilerOptions.handleDeprecationUseAsWarning(true);
+ continue;
+ }
+ if (optionValue.equals(JavaCore.IGNORE)){
+ compilerOptions.handleDeprecationUseAsWarning(false);
+ continue;
+ }
+ continue;
+ }
+ if (optionName.equals(JavaCore.COMPILER_PB_HIDDEN_CATCH_BLOCK)){
+
+ if (optionValue.equals(JavaCore.WARNING)){
+ compilerOptions.handleMaskedCatchBlockAsWarning(true);
+ continue;
+ }
+ if (optionValue.equals(JavaCore.IGNORE)){
+ compilerOptions.handleMaskedCatchBlockAsWarning(false);
+ continue;
+ }
+ continue;
+ }
+ if (optionName.equals(JavaCore.COMPILER_PB_UNUSED_LOCAL)){
+
+ if (optionValue.equals(JavaCore.WARNING)){
+ compilerOptions.handleUnusedLocalVariableAsWarning(true);
+ continue;
+ }
+ if (optionValue.equals(JavaCore.IGNORE)){
+ compilerOptions.handleUnusedLocalVariableAsWarning(false);
+ continue;
+ }
+ continue;
+ }
+ if (optionName.equals(JavaCore.COMPILER_PB_UNUSED_PARAMETER)){
+
+ if (optionValue.equals(JavaCore.WARNING)){
+ compilerOptions.handleUnusedArgumentAsWarning(true);
+ continue;
+ }
+ if (optionValue.equals(JavaCore.IGNORE)){
+ compilerOptions.handleUnusedArgumentAsWarning(false);
+ continue;
+ }
+ continue;
+ }
+ if (optionName.equals(JavaCore.COMPILER_PB_SYNTHETIC_ACCESS_EMULATION)){
+
+ if (optionValue.equals(JavaCore.WARNING)){
+ compilerOptions.handleAccessEmulationAsWarning(true);
+ continue;
+ }
+ if (optionValue.equals(JavaCore.IGNORE)){
+ compilerOptions.handleAccessEmulationAsWarning(false);
+ continue;
+ }
+ continue;
+ }
+ }
+ return compilerOptions.getConfigurableOptions(Locale.getDefault());
+}
+ /**
+ * Note that the project is now deleted.
+ *
+ * fix for 1FW67PA
+ */
+ public void deleted(IProject project) {
+ fProjectsBeingDeleted.removeElement(project);
+ }
+ /**
+ * Note that the project is about to be deleted.
+ *
+ * fix for 1FW67PA
+ */
+ public void deleting(IProject project) {
+
+ IndexManager indexManager= getIndexManager();
+ if (indexManager != null) indexManager.deleting(project);
+
+ if (!fProjectsBeingDeleted.contains(project)) {
+ fProjectsBeingDeleted.addElement(project);
+ }
+ }
+/**
+ * @see ISaveParticipant
+ */
+public void doneSaving(ISaveContext context){
+}
+ /**
+ * Make sure the resource content is available locally
+ */
+ public void ensureLocal(IResource resource) throws CoreException {
+
+ // need to be tuned once having VCM support
+ // resource.ensureLocal(IResource.DEPTH_ZERO, null);
+
+ if (!resource.isLocal(IResource.DEPTH_ZERO) || !resource.exists()) { // project is always local but might not exist
+ throw new CoreException(new JavaModelStatus(IJavaModelStatusConstants.NO_LOCAL_CONTENTS, resource.getFullPath()));
+ }
+ }
+ /**
+ * Merges resource deltas and Java Model deltas, and fires the
+ * result, flushing all deltas. If the firing mode has been
+ * turned off, this has no effect.
+ */
+ public void fire() {
+ if (fFire) {
+ Enumeration deltas= null;
+ if (fJavaModelDeltas.isEmpty()) {
+ deltas= fResourceDeltas.elements();
+ } else {
+ deltas= fJavaModelDeltas.elements();
+ }
+ try {
+ while (deltas.hasMoreElements()) {
+ IJavaElementDelta delta= (IJavaElementDelta) deltas.nextElement();
+ ElementChangedEvent event= new ElementChangedEvent(delta);
+ // Clone the listeners since they could remove themselves when told about the event
+ // (eg. a type hierarchy becomes invalid (and thus it removes itself) when the type is removed
+ Vector listeners= (Vector) fElementChangedListeners.clone();
+ for (int i= 0; i < listeners.size(); i++) {
+ IElementChangedListener listener= (IElementChangedListener) listeners.elementAt(i);
+ listener.elementChanged(event);
+ }
+ }
+ } finally {
+ // empty the queues
+ flush();
+ }
+ }
+ }
+ /**
+ * Flushes all deltas without firing them.
+ */
+ protected void flush() {
+ fJavaModelDeltas= new Vector();
+ fResourceDeltas= new Vector();
+ }
+ /**
+ * Returns the development context to use for the given project.
+ *
+ * @private for use by image builder only
+ */
+ public IDevelopmentContext getDevelopmentContext(IProject project) {
+ return getPerProjectInfo(project).developmentContext;
+ }
+ /**
+ * Returns the set of elements which are out of synch with their buffers.
+ */
+ protected Hashtable getElementsOutOfSynchWithBuffers() {
+ if (fModelInfo == null) {
+ return new Hashtable(1);
+ } else {
+ return fModelInfo.fElementsOutOfSynchWithBuffers;
+ }
+ }
+ /**
+ * Returns the <code>IJavaElement</code> represented by the <code>String</code>
+ * memento.
+ * @see getHandleMemento()
+ */
+ public IJavaElement getHandleFromMemento(String memento) throws JavaModelException {
+ if (memento == null) {
+ return null;
+ }
+ IWorkspace workspace= ResourcesPlugin.getWorkspace();
+ if (workspace == null) {
+ return null;
+ }
+ JavaModel model= (JavaModel) getJavaModel(workspace);
+ if (memento.equals("")){ // workspace memento
+ return model;
+ }
+ int modelEnd= memento.indexOf(JavaElement.JEM_JAVAPROJECT);
+ if (modelEnd == -1) {
+ return null;
+ }
+ boolean returnProject= false;
+ int projectEnd= memento.indexOf(JavaElement.JEM_PACKAGEFRAGMENTROOT, modelEnd);
+ if (projectEnd == -1) {
+ projectEnd= memento.length();
+ returnProject= true;
+ }
+ String projectName= memento.substring(modelEnd + 1, projectEnd);
+ JavaProject proj= (JavaProject) model.getJavaProject(projectName);
+ if (returnProject) {
+ return proj;
+ }
+ int rootEnd= memento.indexOf(JavaElement.JEM_PACKAGEFRAGMENT, projectEnd + 1);
+ if (rootEnd == -1) {
+ return proj.getPackageFragmentRoot(new Path(Path.SEPARATOR + memento.substring(modelEnd + 1)));
+ }
+ String rootName= null;
+ if (rootEnd == projectEnd - 1) {
+ //default root
+ rootName= IPackageFragmentRoot.DEFAULT_PACKAGEROOT_PATH;
+ } else {
+ rootName= memento.substring(projectEnd + 1, rootEnd);
+ }
+ IPath rootPath= new Path(rootName);
+ IPackageFragmentRoot root= null;
+ if (rootPath.isAbsolute()) {
+ root= proj.getPackageFragmentRoot(rootName);
+ } else {
+ root= proj.getPackageFragmentRoot(proj.getProject().getFullPath().append(rootName));
+ }
+ if (root == null)
+ return null;
+
+ int end= memento.indexOf(JavaElement.JEM_COMPILATIONUNIT, rootEnd);
+ if (end == -1) {
+ end= memento.indexOf(JavaElement.JEM_CLASSFILE, rootEnd);
+ if (end == -1) {
+ if (rootEnd + 1 == memento.length()) {
+ return root.getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME);
+ } else {
+ return root.getPackageFragment(memento.substring(rootEnd + 1));
+ }
+ }
+ //deal with class file and binary members
+ return model.getHandleFromMementoForBinaryMembers(memento, root, rootEnd, end);
+ }
+
+ //deal with compilation units and source members
+ return model.getHandleFromMementoForSourceMembers(memento, root, rootEnd, end);
+ }
+ public IndexManager getIndexManager() {
+ return fDeltaProcessor.indexManager;
+ }
+ /**
+ * Returns the info for the element.
+ */
+ protected Object getInfo(IJavaElement element) {
+ if (fModelInfo == null) {
+ return null;
+ }
+ int elementType= ((JavaElement) element).fLEType;
+ if (elementType == IJavaElement.JAVA_MODEL) {
+ return fModelInfo;
+ }
+ if (((JavaElement) element).fLEType <= IJavaElement.CLASS_FILE) {
+ return fModelInfo.fLRUCache.get(element);
+ } else {
+ return fModelInfo.fChildrenCache.get(element);
+ }
+ }
+ /**
+ * Returns the handle to the active Java Model, or <code>null</code> if there
+ * is no active Java Model.
+ */
+ public IJavaModel getJavaModel() {
+ if (fModelInfo == null) {
+ return null;
+ } else {
+ return fModelInfo.getJavaModel();
+ }
+ }
+ /**
+ * Returns the JavaModel for the given workspace, creating
+ * it if it does not yet exist.
+ */
+ public static JavaModel getJavaModel(IWorkspace workspace) {
+
+ JavaModelInfo modelInfo= getJavaModelManager().fModelInfo;
+ if (modelInfo != null) {
+ // if the current java model corresponds to a different workspace,
+ // try to close it
+ if (!modelInfo.workspace.equals(workspace)) {
+ try {
+ modelInfo.fJavaModel.close();
+ } catch (JavaModelException e) {
+ Assert.isTrue(false, "Cannot instantiate more than one Java Model");
+ return null;
+ }
+ }
+ }
+ if (modelInfo == null || modelInfo.workspace.equals(workspace)) {
+ return new JavaModel(workspace);
+ } else {
+ Assert.isTrue(false, "Cannot instantiate more than one Java Model");
+ return null;
+ }
+
+ }
+ /**
+ * Returns the singleton JavaModelManager
+ */
+ public static synchronized JavaModelManager getJavaModelManager() {
+ if (fgManager == null) {
+ fgManager= new JavaModelManager();
+ }
+ return fgManager;
+ }
+ /**
+ * Returns the last built state for the given project, or null if there is none.
+ * Deserializes the state if necessary.
+ *
+ * @private for use by image builder and evaluation support only
+ */
+ public IState getLastBuiltState(IProject project, IProgressMonitor monitor) {
+ PerProjectInfo info= getPerProjectInfo(project);
+ IState state= info.getLastBuiltState();
+ if (state == null && JavaBuilder.SAVE_ENABLED && !info.triedRead) {
+ info.triedRead= true;
+ try {
+ if (monitor != null) monitor.subTask("Reading saved built state of "+project.getName());
+ state= readState(info);
+ info.setLastBuiltState(state);
+ } catch (CoreException e) {
+ e.printStackTrace();
+ }
+ }
+ return state;
+ }
+ /**
+ * Returns the last built state for the given project, or null if there is none.
+ * Deserializes the state if necessary.
+ *
+ */
+ public INameEnvironment getNameEnvironment(IProject project) {
+ StateImpl state= (StateImpl) getLastBuiltState(project, null);
+ if (state == null)
+ return null;
+
+ BuilderEnvironment env = new BuilderEnvironment(new BatchImageBuilder(state));
+
+ // Fix for 1GB7PUI: ITPJCORE:WINNT - evaluation from type in default package
+ IPackage defaultPackage = state.getDevelopmentContext().getImage().getPackageHandle(PackageImpl.DEFAULT_PACKAGE_PREFIX + project.getName(), true);
+ env.setDefaultPackage(defaultPackage);
+
+ return env;
+ }
+ /**
+ * Returns the per-project info for the given project.
+ */
+ private PerProjectInfo getPerProjectInfo(IProject project) {
+ PerProjectInfo info= (PerProjectInfo) perProjectInfo.get(project);
+ if (info == null) {
+ info= new PerProjectInfo(project);
+ perProjectInfo.put(project, info);
+ }
+ return info;
+ }
+ /**
+ * Returns the File to use for saving and restoring the last built state for the given project.
+ */
+ private File getSerializationFile(IProject project) {
+ if (!project.exists()) return null;
+ IPluginDescriptor descr= JavaCore.getJavaCore().getDescriptor();
+ IPath workingLocation= project.getPluginWorkingLocation(descr);
+ return workingLocation.append("state.dat").toFile();
+ }
+ public String getVariablesAsXMLString() throws CoreException {
+
+ Document document = new DocumentImpl();
+ Element rootElement = document.createElement("variables");
+ document.appendChild(rootElement);
+
+ String[] variables = JavaCore.getClasspathVariableNames();
+
+ for (int i= 0; i < variables.length; ++i) {
+ String var = variables[i];
+ IPath varPath = JavaCore.getClasspathVariable(var);
+ Element varElement= document.createElement("variable");
+ varElement.setAttribute("name", var);
+ varElement.setAttribute("path", varPath.toString());
+ rootElement.appendChild(varElement);
+ }
+
+ // produce a String output
+ StringWriter writer = new StringWriter();
+ try {
+ OutputFormat format = new OutputFormat();
+ format.setIndenting(true);
+ Serializer serializer = SerializerFactory.getSerializerFactory(Method.XML).makeSerializer(writer, format);
+ serializer.asDOMSerializer().serialize(document);
+ } catch (IOException e) {
+ throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
+ }
+ return writer.toString();
+
+ }
+/**
+ * Returns the open ZipFile at the given location. If the ZipFile
+ * does not yet exist, it is created, opened, and added to the cache
+ * of open ZipFiles. The location must be a absolute path.
+ *
+ * @exception CoreException If unable to create/open the ZipFile.
+ */
+ public ZipFile getZipFile(IPath path) throws CoreException {
+ if (fModelInfo == null) {
+ return null;
+ }
+
+ String fileSystemPath= null;
+ IWorkspaceRoot root = getJavaModel().getWorkspace().getRoot();
+ IResource file = root.findMember(path);
+ if (path.isAbsolute() && file != null) {
+ if (file == null || file.getType() != IResource.FILE) {
+ fileSystemPath= path.toOSString();
+ } else {
+ ensureLocal(file);
+ fileSystemPath= file.getLocation().toOSString();
+ }
+ } else if (!path.isAbsolute()) {
+ file= root.getFile(path);
+ if (file == null || file.getType() != IResource.FILE) {
+ throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, "file not found", null));
+ }
+ ensureLocal(file);
+ fileSystemPath= file.getLocation().toOSString();
+ } else {
+ fileSystemPath= path.toOSString();
+ }
+
+ try {
+ return new ZipFile(fileSystemPath);
+ } catch (IOException e) {
+ throw new CoreException(new Status(Status.ERROR, JavaCore.PLUGIN_ID, -1, "IOException", e));
+ }
+ }
+ /**
+ * Returns true if the given project is being deleted, otherwise false.
+ *
+ * fix for 1FW67PA
+ */
+ public boolean isBeingDeleted(IProject project) {
+ return fProjectsBeingDeleted.contains(project);
+ }
+ /**
+ * Returns true if the firing is enabled
+ */
+ public boolean isFiring() {
+ return this.fFire;
+ }
+ public void loadVariables() throws CoreException {
+
+ String xmlString = ResourcesPlugin.getWorkspace().getRoot().getPersistentProperty(
+ new QualifiedName(JavaCore.PLUGIN_ID, "variables"));
+ try {
+ if (xmlString != null) readVariables(xmlString);
+ } catch(IOException e){
+ return;
+ }
+ }
+/**
+ * Merged all awaiting deltas.
+ */
+public void mergeDeltas() {
+ Enumeration deltas = null;
+ if (fJavaModelDeltas.isEmpty()) {
+ //deltas = fResourceDeltas.elements();
+ return;
+ } else {
+ deltas = fJavaModelDeltas.elements();
+ }
+ if (deltas != null) {
+ JavaElementDelta rootDelta = new JavaElementDelta(getJavaModel());
+ boolean insertedTree = false;
+ while (deltas.hasMoreElements()) {
+ IJavaElementDelta delta = (IJavaElementDelta)deltas.nextElement();
+ IJavaElementDelta[] children = delta.getAffectedChildren();
+ for (int j = 0; j < children.length; j++) {
+ JavaElementDelta projectDelta = (JavaElementDelta) children[j];
+ rootDelta.insertDeltaTree(projectDelta.getElement(), projectDelta);
+ insertedTree = true;
+ }
+ }
+ if (insertedTree){
+ if (fJavaModelDeltas.isEmpty()) {
+ fResourceDeltas = new Vector(1);
+ fResourceDeltas.addElement(rootDelta);
+ } else {
+ fJavaModelDeltas = new Vector(1);
+ fJavaModelDeltas.addElement(rootDelta);
+ }
+ }
+ else {
+ if (fJavaModelDeltas.isEmpty()) {
+ fResourceDeltas = new Vector(0);
+ } else {
+ fJavaModelDeltas = new Vector(0);
+ }
+ }
+ }
+}
+ /**
+ * Returns the info for this element without
+ * disturbing the cache ordering.
+ */
+ protected Object peekAtInfo(IJavaElement element) {
+ if (fModelInfo == null) {
+ return null;
+ }
+ int type = ((JavaElement) element).fLEType;
+ if (type == IJavaElement.JAVA_MODEL) {
+ return fModelInfo;
+ } else if (type <= IJavaElement.CLASS_FILE) {
+ return fModelInfo.fLRUCache.peek(element);
+ } else {
+ return fModelInfo.fChildrenCache.get(element);
+ }
+ }
+/**
+ * @see ISaveParticipant
+ */
+public void prepareToSave(ISaveContext context) throws CoreException {
+}
+ protected void putInfo(IJavaElement element, Object info) {
+ int elementType= ((JavaElement) element).fLEType;
+ if (elementType == IJavaElement.JAVA_MODEL) {
+ fModelInfo= (JavaModelInfo) info;
+ return;
+ }
+
+ if (elementType <= IJavaElement.CLASS_FILE) {
+ fModelInfo.fLRUCache.put(element, info);
+ } else {
+ fModelInfo.fChildrenCache.put(element, info);
+ }
+ }
+ /**
+ * Reads the build state for the relevant project.
+ */
+ protected IState readState(PerProjectInfo info) throws CoreException {
+ File file= getSerializationFile(info.project);
+ if (file == null || !file.exists())
+ return null;
+ try {
+ DataInputStream in= new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
+ try {
+ String pluginID= in.readUTF();
+ if (!pluginID.equals(JavaCore.PLUGIN_ID))
+ throw new IOException("Wrong file format");
+ String kind= in.readUTF();
+ if (!kind.equals("STATE"))
+ throw new IOException("Wrong file format");
+ int version= in.readInt();
+ if (version != 0x0001)
+ throw new IOException("Unhandled version of file format");
+ boolean hasState= in.readBoolean();
+ IState state= null;
+ if (hasState) {
+ state= info.developmentContext.restoreState(info.project, in);
+ }
+ return state;
+ } finally {
+ in.close();
+ }
+ } catch (Exception e) {
+ //e.printStackTrace(); - silent failure
+ //throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, Platform.PLUGIN_ERROR, "Error reading last build state for project "+ info.project.getFullPath(), e));
+ }
+ return null;
+ }
+ public void readVariables(String xmlString) throws IOException {
+
+ StringReader reader = new StringReader(xmlString);
+ Element cpElement;
+ try {
+ DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ cpElement = parser.parse(new InputSource(reader)).getDocumentElement();
+ } catch(SAXException e) {
+ throw new IOException("bad format");
+ } catch(ParserConfigurationException e){
+ reader.close();
+ throw new IOException("bad format");
+ } finally {
+ reader.close();
+ }
+ if (!cpElement.getNodeName().equalsIgnoreCase("variables")) {
+ throw new IOException("bad format");
+ }
+ NodeList list= cpElement.getChildNodes();
+ Vector variables = new Vector();
+ int length= list.getLength();
+ for (int i= 0; i < length; ++i) {
+ Node node= list.item(i);
+ short type= node.getNodeType();
+ if (type == Node.ELEMENT_NODE) {
+ Element element= (Element) node;
+ if (element.getNodeName().equalsIgnoreCase("variable")) {
+ String varName = element.getAttribute("name");
+ String varPath = element.getAttribute("path");
+ try {
+ JavaCore.setClasspathVariable(varName, new Path(varPath));
+ } catch(JavaModelException e){
+ } catch(RuntimeException e){
+ }
+ }
+
+ }
+ }
+ }
+ /**
+ * Registers the given delta with this manager. This API is to be
+ * used to registerd deltas that are created explicitly by the Java
+ * Model. Deltas created as translations of <code>IResourceDeltas</code>
+ * are to be registered with <code>#registerResourceDelta</code>.
+ */
+ protected void registerJavaModelDelta(IJavaElementDelta delta) {
+ fJavaModelDeltas.addElement(delta);
+ }
+ /**
+ * Registers the given delta with this manager. This API is to be
+ * used to register deltas that are created as a side effect
+ * of an <code>IResourceDelta</code>. As <code>IResourceDelta</code>s
+ * are received by the Java Model, they are translated into
+ * <code>IJavaElementDelta</code>s. This is where the translations
+ * are registered.
+ */
+ public void registerResourceDelta(IJavaElementDelta delta) {
+ fResourceDeltas.addElement(delta);
+ }
+ /**
+ * removeElementChangedListener method comment.
+ */
+ public void removeElementChangedListener(IElementChangedListener listener) {
+ fElementChangedListeners.removeElement(listener);
+ }
+ protected void removeInfo(IJavaElement element) {
+ if (fModelInfo == null) {
+ return;
+ }
+ if (((JavaElement) element).fLEType <= IJavaElement.CLASS_FILE) {
+ fModelInfo.fLRUCache.remove(element);
+ } else {
+ fModelInfo.fChildrenCache.remove(element);
+ }
+ }
+ void removePerProjectInfo(JavaProject javaProject) {
+ IProject project = javaProject.getProject();
+ PerProjectInfo info= (PerProjectInfo) perProjectInfo.get(project);
+ if (info != null) {
+ perProjectInfo.remove(project);
+ }
+ }
+ /**
+ * Notifies this Java Model Manager that some resource changes have happened
+ * on the platform, and that the Java Model should update any required
+ * internal structures such that its elements remain consistent.
+ * Translates <code>IResourceDeltas</code> into <code>IJavaElementDeltas</code>.
+ *
+ * @see IResourceDelta
+ * @see IResource
+ */
+ public void resourceChanged(IResourceChangeEvent event) {
+
+ if (event.getSource() instanceof IWorkspace) {
+ IResource resource = event.getResource();
+ IResourceDelta delta = event.getDelta();
+ switch(event.getType()){
+ case IResourceChangeEvent.PRE_DELETE :
+ try {
+ if(resource.getType() == IResource.PROJECT
+ && ((IProject) resource).hasNature(JavaCore.NATURE_ID)) {
+ this.deleting((IProject)resource);
+ }
+ } catch(CoreException e){
+ }
+ break;
+ case IResourceChangeEvent.PRE_AUTO_BUILD :
+ if(delta != null) {
+ this.checkProjectBeingAdded(delta);
+ DeltaProcessor.checkProjectPropertyFileUpdate(delta, null); // will close project if affected by the property file change
+ }
+ break;
+ case IResourceChangeEvent.POST_CHANGE :
+ if (delta != null) {
+ try {
+ IJavaElementDelta[] translatedDeltas = fDeltaProcessor.processResourceDelta(delta);
+ if (translatedDeltas.length > 0) {
+ for (int i= 0; i < translatedDeltas.length; i++) {
+ registerResourceDelta(translatedDeltas[i]);
+ }
+ }
+ fire();
+ } finally {
+ // fix for 1FWIAEQ: ITPJCORE:ALL - CRITICAL - "projects being deleted" cache not cleaned up when solution deleted
+ if (!fProjectsBeingDeleted.isEmpty()) {
+ fProjectsBeingDeleted= new Vector(1);
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+/**
+ * @see ISaveParticipant
+ */
+public void rollback(ISaveContext context){
+}
+ /**
+ * Runs a Java Model Operation
+ */
+ public void runOperation(JavaModelOperation operation, IProgressMonitor monitor) throws JavaModelException {
+
+ boolean wasFiring = isFiring();
+ try {
+ if (wasFiring) stopDeltas();
+ if (operation.isReadOnly()) {
+ operation.run(monitor);
+ } else {
+ // use IWorkspace.run(...) to ensure that a build will be done in autobuild mode
+ this.getJavaModel().getWorkspace().run(operation, monitor);
+ }
+ } catch (CoreException ce) {
+ if (ce instanceof JavaModelException) {
+ throw (JavaModelException)ce;
+ } else {
+ if (ce.getStatus().getCode() == IResourceStatus.OPERATION_FAILED) {
+ Throwable e= ce.getStatus().getException();
+ if (e instanceof JavaModelException) {
+ throw (JavaModelException) e;
+ }
+ }
+ throw new JavaModelException(ce);
+ }
+ } finally {
+ // fire any registered deltas
+ if (wasFiring){
+ startDeltas();
+ fire();
+ }
+ }
+ }
+ private void saveBuildState() throws CoreException {
+ if (!JavaBuilder.SAVE_ENABLED)
+ return;
+ Vector vStats= null; // lazy initialized
+ for (Enumeration enum= perProjectInfo.elements(); enum.hasMoreElements();) {
+ PerProjectInfo info= (PerProjectInfo) enum.nextElement();
+ try {
+ saveStateIfNecessary(info);
+ } catch (CoreException e) {
+ if (vStats == null)
+ vStats= new Vector();
+ vStats.addElement(e.getStatus());
+ }
+ }
+ if (vStats != null) {
+ IStatus[] stats= new IStatus[vStats.size()];
+ vStats.copyInto(stats);
+ throw new CoreException(new MultiStatus(JavaCore.PLUGIN_ID, IStatus.ERROR, stats, "Error saving builder states", null));
+ }
+ }
+ /**
+ * Saves the built state for the project.
+ */
+ private void saveState(PerProjectInfo info) throws CoreException {
+
+ if (VERBOSE) System.out.println("Saving Java Image Builder state for project " + info.project.getName());
+ long t= System.currentTimeMillis();
+ File file= getSerializationFile(info.project);
+ if (file == null) return;
+ try {
+ DataOutputStream out= new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
+ try {
+ out.writeUTF(JavaCore.PLUGIN_ID);
+ out.writeUTF("STATE");
+ out.writeInt(0x0001);
+ IState state= info.getLastBuiltState();
+ if (state == null) {
+ out.writeBoolean(false);
+ } else {
+ out.writeBoolean(true);
+ info.developmentContext.saveState(state, out);
+ }
+ } finally {
+ out.close();
+ }
+ } catch (RuntimeException e) {
+ try {
+ file.delete();
+ } catch(SecurityException se){
+ }
+ throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, Platform.PLUGIN_ERROR, "Error saving last build state for project "+ info.project.getFullPath(), e));
+ } catch (IOException e) {
+ try {
+ file.delete();
+ } catch(SecurityException se){
+ }
+ throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, Platform.PLUGIN_ERROR, "Error saving last build state for project "+ info.project.getFullPath(), e));
+ }
+ t= System.currentTimeMillis() - t;
+ if (VERBOSE) System.out.println(" Saved in " + t + "ms");
+ }
+ /**
+ * Saves the built state for the project if it has been changed since last save.
+ */
+ private void saveStateIfNecessary(PerProjectInfo info) throws CoreException {
+ IState state= info.getLastBuiltState();
+ if (state == null) {
+ saveState(info);
+ info.savedStateFingerprint= null;
+ } else {
+ byte[] fingerprint= state.getFingerprint();
+ if (Util.compare(fingerprint, info.savedStateFingerprint) != 0) {
+ saveState(info);
+ info.savedStateFingerprint= fingerprint;
+ }
+ }
+ }
+ public void saveVariables() throws CoreException {
+ ResourcesPlugin.getWorkspace().getRoot().setPersistentProperty(
+ new QualifiedName(JavaCore.PLUGIN_ID, "variables"),
+ getVariablesAsXMLString());
+ }
+/**
+ * @see ISaveParticipant
+ */
+public void saving(ISaveContext context) throws CoreException {
+
+ this.saveVariables();
+
+ if (context.getKind() == ISaveContext.FULL_SAVE){
+ this.saveBuildState(); // build state
+ }
+}
+ /**
+ * Record the order in which to build the java projects (batch build). This order is based
+ * on the projects classpath settings.
+ */
+ protected void setBuildOrder(String[] javaBuildOrder) throws JavaModelException {
+
+ // optional behaviour
+ if (!JavaCore.COMPUTE.equals(JavaCore.getOptions().get(JavaCore.CORE_JAVA_BUILD_ORDER))) return;
+
+ if (javaBuildOrder == null || javaBuildOrder.length <= 1) return;
+
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ IWorkspaceDescription description = workspace.getDescription();
+ String[] wksBuildOrder = description.getBuildOrder();
+
+ String[] newOrder;
+ if (wksBuildOrder == null){
+ newOrder = javaBuildOrder;
+ } else {
+ // remove projects which are already mentionned in java builder order
+ int javaCount = javaBuildOrder.length;
+ Hashtable newSet = new Hashtable(javaCount); // create a set for fast check
+ for (int i = 0; i < javaCount; i++){
+ newSet.put(javaBuildOrder[i], javaBuildOrder[i]);
+ }
+ int removed = 0;
+ int oldCount = wksBuildOrder.length;
+ for (int i = 0; i < oldCount; i++){
+ if (newSet.containsKey(wksBuildOrder[i])){
+ wksBuildOrder[i] = null;
+ removed++;
+ }
+ }
+ // add Java ones first
+ newOrder = new String[oldCount - removed + javaCount];
+ System.arraycopy(javaBuildOrder, 0, newOrder, 0, javaCount); // java projects are built first
+
+ // copy previous items in their respective order
+ int index = javaCount;
+ for (int i = 0; i < oldCount; i++){
+ if (wksBuildOrder[i] != null){
+ newOrder[index++] = wksBuildOrder[i];
+ }
+ }
+ }
+ // commit the new build order out
+ description.setBuildOrder(newOrder);
+ try {
+ workspace.setDescription(description);
+ } catch(CoreException e){
+ throw new JavaModelException(e);
+ }
+ }
+ /**
+ * Sets the last built state for the given project, or null to reset it.
+ */
+ public void setLastBuiltState(IProject project, IState state) {
+ PerProjectInfo info= getPerProjectInfo(project);
+ info.triedRead= true; // no point trying to re-read once using setter
+ info.developmentContext.setCurrentState(state);
+ }
+ public void shutdown () {
+ if (fDeltaProcessor.indexManager != null){ // no more indexing
+ fDeltaProcessor.indexManager.shutdown();
+ fDeltaProcessor.indexManager = null;
+ }
+ try {
+ IJavaModel model = this.getJavaModel();
+ if (model != null) {
+ model.close();
+ }
+ } catch (JavaModelException e) {
+ }
+ }
+ /**
+ * Turns the firing mode to on. That is, deltas that are/have been
+ * registered will be fired.
+ */
+ public void startDeltas() {
+ fFire= true;
+ }
+ /**
+ * Turns the firing mode to off. That is, deltas that are/have been
+ * registered will not be fired until deltas are started again.
+ */
+ public void stopDeltas() {
+ fFire= false;
+ }
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelOperation.java
new file mode 100644
index 0000000000..8dae75ffc6
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelOperation.java
@@ -0,0 +1,605 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.core.*;
+
+import java.io.InputStream;
+
+/**
+ * Defines behavior common to all Java Model operations
+ */
+public abstract class JavaModelOperation
+ implements IWorkspaceRunnable, IProgressMonitor {
+ /**
+ * The elements this operation operates on,
+ * or <code>null</code> if this operation
+ * does not operate on specific elements.
+ */
+ protected IJavaElement[] fElementsToProcess;
+ /**
+ * The parent elements this operation operates with
+ * or <code>null</code> if this operation
+ * does not operate with specific parent elements.
+ */
+ protected IJavaElement[] fParentElements;
+ /**
+ * An empty collection of <code>IJavaElement</code>s - the common
+ * empty result if no elements are created, or if this
+ * operation is not actually executed.
+ */
+ protected static IJavaElement[] fgEmptyResult = new IJavaElement[] {
+ };
+
+ /**
+ * Collection of <code>IJavaElementDelta</code>s created by this operation.
+ * This collection starts out <code>null</code> and becomes an
+ * array of <code>IJavaElementDelta</code>s if the operation creates any
+ * deltas. This collection is registered with the Java Model notification
+ * manager if the operation completes successfully.
+ */
+ protected IJavaElementDelta[] fDeltas = null;
+ /**
+ * The elements created by this operation - empty
+ * until the operation actually creates elements.
+ */
+ protected IJavaElement[] fResultElements = fgEmptyResult;
+
+ /**
+ * The progress monitor passed into this operation
+ */
+ protected IProgressMonitor fMonitor = null;
+ /**
+ * A flag indicating whether this operation is nested.
+ */
+ protected boolean fNested = false;
+ /**
+ * Conflict resolution policy - by default do not force (fail on a conflict).
+ */
+ protected boolean fForce = false;
+ /**
+ * A common constructor for all Java Model operations.
+ */
+ protected JavaModelOperation(IJavaElement[] elements) {
+ fElementsToProcess = elements;
+ }
+
+ /**
+ * Common constructor for all Java Model operations.
+ */
+ protected JavaModelOperation(
+ IJavaElement[] elementsToProcess,
+ IJavaElement[] parentElements) {
+ fElementsToProcess = elementsToProcess;
+ fParentElements = parentElements;
+ }
+
+ /**
+ * A common constructor for all Java Model operations.
+ */
+ protected JavaModelOperation(
+ IJavaElement[] elementsToProcess,
+ IJavaElement[] parentElements,
+ boolean force) {
+ fElementsToProcess = elementsToProcess;
+ fParentElements = parentElements;
+ fForce = force;
+ }
+
+ /**
+ * A common constructor for all Java Model operations.
+ */
+ protected JavaModelOperation(IJavaElement[] elements, boolean force) {
+ fElementsToProcess = elements;
+ fForce = force;
+ }
+
+ /**
+ * Common constructor for all Java Model operations.
+ */
+ protected JavaModelOperation(IJavaElement element) {
+ fElementsToProcess = new IJavaElement[] { element };
+ }
+
+ /**
+ * A common constructor for all Java Model operations.
+ */
+ protected JavaModelOperation(IJavaElement element, boolean force) {
+ fElementsToProcess = new IJavaElement[] { element };
+ fForce = force;
+ }
+
+ /**
+ * Adds the given delta to the collection of deltas
+ * that this operation has created. These deltas are
+ * automatically registered with the Java Model Manager
+ * when the operation completes.
+ */
+ protected void addDelta(IJavaElementDelta delta) {
+ if (fDeltas == null) {
+ fDeltas = new IJavaElementDelta[] { delta };
+ } else {
+ IJavaElementDelta[] copy = new IJavaElementDelta[fDeltas.length + 1];
+ System.arraycopy(fDeltas, 0, copy, 0, fDeltas.length);
+ copy[fDeltas.length] = delta;
+ fDeltas = copy;
+ }
+ }
+
+ /**
+ * @see IProgressMonitor
+ */
+ public void beginTask(String name, int totalWork) {
+ if (fMonitor != null) {
+ fMonitor.beginTask(name, totalWork);
+ }
+ }
+
+ /**
+ * Checks with the progress monitor to see whether this operation
+ * should be canceled. An operation should regularly call this method
+ * during its operation so that the user can cancel it.
+ *
+ * @exception OperationCanceledException if cancelling the operation has been requested
+ * @see IProgressMonitor#isCanceled
+ */
+ protected void checkCanceled() {
+ if (isCanceled()) {
+ throw new OperationCanceledException("Operation cancelled");
+ }
+ }
+
+ /**
+ * Common code used to verify the elements this operation is processing.
+ * @see JavaModelOperation#verify()
+ */
+ protected IJavaModelStatus commonVerify() {
+ if (fElementsToProcess == null || fElementsToProcess.length == 0) {
+ return new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
+ }
+ for (int i = 0; i < fElementsToProcess.length; i++) {
+ if (fElementsToProcess[i] == null) {
+ return new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
+ }
+ }
+ return JavaModelStatus.VERIFIED_OK;
+ }
+
+ /**
+ * Convenience method to copy resources
+ */
+ protected void copyResources(IResource[] resources, IPath destinationPath)
+ throws JavaModelException {
+ IProgressMonitor subProgressMonitor = getSubProgressMonitor(resources.length);
+ IWorkspace workspace = resources[0].getWorkspace();
+ try {
+ workspace.copy(resources, destinationPath, false, subProgressMonitor);
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ }
+ }
+
+ /**
+ * Convenience method to create a file
+ */
+ protected void createFile(
+ IContainer folder,
+ String name,
+ InputStream contents,
+ boolean force)
+ throws JavaModelException {
+ IFile file = folder.getFile(new Path(name));
+ try {
+ file.create(contents, force, getSubProgressMonitor(1));
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ }
+ }
+
+ /**
+ * Convenience method to create a folder
+ */
+ protected void createFolder(
+ IContainer parentFolder,
+ String name,
+ boolean force)
+ throws JavaModelException {
+ IFolder folder = parentFolder.getFolder(new Path(name));
+ try {
+ // we should use true to create the file locally. Only VCM should use tru/false
+ folder.create(force, true, getSubProgressMonitor(1));
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ }
+ }
+
+ /**
+ * Convenience method to delete an empty package fragment
+ */
+ protected void deleteEmptyPackageFragment(
+ IPackageFragment fragment,
+ boolean force)
+ throws JavaModelException {
+
+ IContainer resource = (IContainer) fragment.getCorrespondingResource();
+ IResource rootResource = fragment.getParent().getUnderlyingResource();
+
+ try {
+ resource.delete(force, getSubProgressMonitor(1));
+ while (resource instanceof IFolder) {
+ // deleting a package: delete the parent if it is empty (eg. deleting x.y where folder x doesn't have resources but y)
+ // without deleting the package fragment root
+ resource = resource.getParent();
+ if (!resource.equals(rootResource) && resource.members().length == 0) {
+ resource.delete(force, getSubProgressMonitor(1));
+ }
+ }
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ }
+ }
+
+ /**
+ * Convenience method to delete a resource
+ */
+ protected void deleteResource(IResource resource, boolean force)
+ throws JavaModelException {
+ try {
+ resource.delete(force, getSubProgressMonitor(1));
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ }
+ }
+
+ /**
+ * Convenience method to delete resources
+ */
+ protected void deleteResources(IResource[] resources, boolean force)
+ throws JavaModelException {
+ if (resources == null || resources.length == 0)
+ return;
+ IProgressMonitor subProgressMonitor = getSubProgressMonitor(resources.length);
+ IWorkspace workspace = resources[0].getWorkspace();
+ try {
+ workspace.delete(resources, force, subProgressMonitor);
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ }
+ }
+
+ /**
+ * @see IProgressMonitor
+ */
+ public void done() {
+ if (fMonitor != null) {
+ fMonitor.done();
+ }
+ }
+
+ /**
+ * Verifies the operation can proceed and executes the operation.
+ * Subclasses should override <code>#verify</code> and
+ * <code>executeOperation</code> to implement the specific operation behavior.
+ *
+ * @exception JavaModelException The operation has failed.
+ */
+ protected void execute() throws JavaModelException {
+ IJavaModelStatus status = verify();
+ if (status.isOK()) {
+ executeOperation();
+ } else {
+ throw new JavaModelException(status);
+ }
+ }
+
+ /**
+ * Convenience method to run an operation within this operation
+ */
+ public void executeNestedOperation(
+ JavaModelOperation operation,
+ int subWorkAmount)
+ throws JavaModelException {
+ IProgressMonitor subProgressMonitor = getSubProgressMonitor(subWorkAmount);
+ // fix for 1FW7IKC, part (1)
+ try {
+ operation.setNested(true);
+ operation.run(subProgressMonitor);
+ //accumulate the nested operation deltas
+ for (int i = 0; i < operation.fDeltas.length; i++) {
+ addDelta(operation.fDeltas[i]);
+ }
+ } catch (CoreException ce) {
+ if (ce instanceof JavaModelException) {
+ throw (JavaModelException) ce;
+ } else {
+ // translate the core exception to a java model exception
+ if (ce.getStatus().getCode() == IResourceStatus.OPERATION_FAILED) {
+ Throwable e = ce.getStatus().getException();
+ if (e instanceof JavaModelException) {
+ throw (JavaModelException) e;
+ }
+ }
+ throw new JavaModelException(ce);
+ }
+ }
+ }
+
+ /**
+ * Performs the operation specific behavior. Subclasses must override.
+ */
+ protected abstract void executeOperation() throws JavaModelException;
+ /**
+ * Returns the compilation unit the given element is contained in,
+ * or the element itself (if it is a compilation unit),
+ * otherwise <code>null</code>.
+ */
+ protected ICompilationUnit getCompilationUnitFor(IJavaElement element) {
+
+ return ((JavaElement) element).getCompilationUnit();
+ }
+
+ /**
+ * Returns the elements to which this operation applies,
+ * or <code>null</code> if not applicable.
+ */
+ protected IJavaElement[] getElementsToProcess() {
+ return fElementsToProcess;
+ }
+
+ /**
+ * Returns the element to which this operation applies,
+ * or <code>null</code> if not applicable.
+ */
+ protected IJavaElement getElementToProcess() {
+ if (fElementsToProcess == null || fElementsToProcess.length == 0) {
+ return null;
+ }
+ return fElementsToProcess[0];
+ }
+
+ /**
+ * Returns the Java Model this operation is operating in.
+ */
+ public IJavaModel getJavaModel() {
+ if (fElementsToProcess == null || fElementsToProcess.length == 0) {
+ return getParentElement().getJavaModel();
+ } else {
+ return fElementsToProcess[0].getJavaModel();
+ }
+ }
+
+ /**
+ * Returns the parent element to which this operation applies,
+ * or <code>null</code> if not applicable.
+ */
+ protected IJavaElement getParentElement() {
+ if (fParentElements == null || fParentElements.length == 0) {
+ return null;
+ }
+ return fParentElements[0];
+ }
+
+ /**
+ * Returns the parent elements to which this operation applies,
+ * or <code>null</code> if not applicable.
+ */
+ protected IJavaElement[] getParentElements() {
+ return fParentElements;
+ }
+
+ /**
+ * Returns the elements created by this operation.
+ */
+ public IJavaElement[] getResultElements() {
+ return fResultElements;
+ }
+
+ /**
+ * Creates and returns a subprogress monitor if appropriate.
+ */
+ protected IProgressMonitor getSubProgressMonitor(int workAmount) {
+ IProgressMonitor sub = null;
+ if (fMonitor != null) {
+ sub =
+ new SubProgressMonitor(
+ fMonitor,
+ workAmount,
+ SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
+ }
+ return sub;
+ }
+
+ /**
+ * Returns the <code>IWorkspace</code> this operation is working in, or
+ * <code>null</code> if this operation has no elements to process.
+ */
+ protected IWorkspace getWorkspace() {
+ if (fElementsToProcess != null && fElementsToProcess.length > 0) {
+ IJavaProject project = fElementsToProcess[0].getJavaProject();
+ if (project != null) {
+ return project.getJavaModel().getWorkspace();
+ }
+ }
+ return null;
+ }
+
+ public void internalWorked(double work) {
+ if (fMonitor != null) {
+ fMonitor.internalWorked(work);
+ }
+ }
+
+ /**
+ * @see IProgressMonitor
+ */
+ public boolean isCanceled() {
+ if (fMonitor != null) {
+ return fMonitor.isCanceled();
+ }
+ return false;
+ }
+
+ /**
+ * Returns <code>true</code> if this operation performs no resource modifications,
+ * otherwise <code>false</code>. Subclasses must override.
+ */
+ public boolean isReadOnly() {
+ return false;
+ }
+
+ /**
+ * Traverses the deltas for an working copies and makes them
+ * consistent.
+ */
+ protected void makeWorkingCopiesConsistent(IJavaElementDelta[] deltas) {
+ for (int i = 0; i < deltas.length; i++) {
+ walkDeltaMakingWorkingCopiesConsistent(deltas[i]);
+ }
+ }
+
+ /**
+ * Convenience method to move resources
+ */
+ protected void moveResources(IResource[] resources, IPath destinationPath)
+ throws JavaModelException {
+ IProgressMonitor subProgressMonitor = null;
+ if (fMonitor != null) {
+ subProgressMonitor =
+ new SubProgressMonitor(
+ fMonitor,
+ resources.length,
+ SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
+ }
+ IWorkspace workspace = resources[0].getWorkspace();
+ try {
+ workspace.move(resources, destinationPath, false, subProgressMonitor);
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ }
+ }
+
+ /**
+ * Creates and returns a new <code>IJavaElementDelta</code>
+ * on the Java Model.
+ */
+ public JavaElementDelta newJavaElementDelta() {
+ return new JavaElementDelta(getJavaModel());
+ }
+
+ /**
+ * Registers any deltas this operation created, with the
+ * Java Model manager.
+ */
+ protected void registerDeltas() {
+ if (fDeltas != null && !fNested) {
+ // hook to ensure working copies remain consistent
+ makeWorkingCopiesConsistent(fDeltas);
+ JavaModelManager manager =
+ (JavaModelManager) JavaModelManager.getJavaModelManager();
+ for (int i = 0; i < fDeltas.length; i++) {
+ manager.registerJavaModelDelta(fDeltas[i]);
+ }
+ }
+ }
+
+ /**
+ * Main entry point for Java Model operations. Executes this operation
+ * and registers any deltas created.
+ *
+ * @see IWorkspaceRunnable
+ * @exception CoreException if the operation fails
+ */
+ public void run(IProgressMonitor monitor) throws CoreException {
+ try {
+ fMonitor = monitor;
+ execute();
+ } finally {
+ registerDeltas();
+ }
+ }
+
+ /**
+ * @see IProgressMonitor
+ */
+ public void setCanceled(boolean b) {
+ if (fMonitor != null) {
+ fMonitor.setCanceled(b);
+ }
+ }
+
+ /**
+ * Sets whether this operation is nested or not.
+ * @see CreateElementInCUOperation#checkCanceled
+ */
+ protected void setNested(boolean nested) {
+ fNested = nested;
+ }
+
+ /**
+ * @see IProgressMonitor
+ */
+ public void setTaskName(String name) {
+ if (fMonitor != null) {
+ fMonitor.setTaskName(name);
+ }
+ }
+
+ /**
+ * @see IProgressMonitor
+ */
+ public void subTask(String name) {
+ if (fMonitor != null) {
+ fMonitor.subTask(name);
+ }
+ }
+
+ /**
+ * Returns a status indicating if there is any known reason
+ * this operation will fail. Operations are verified before they
+ * are run.
+ *
+ * Subclasses must override if they have any conditions to verify
+ * before this operation executes.
+ *
+ * @see IJavaModelStatus
+ */
+ protected IJavaModelStatus verify() {
+ return commonVerify();
+ }
+
+ /**
+ * Traverses the delta making any working copies consistent
+ */
+ protected void walkDeltaMakingWorkingCopiesConsistent(IJavaElementDelta delta) {
+ if (delta.getElement().getElementType() == IJavaElement.COMPILATION_UNIT) {
+ ICompilationUnit unit = (ICompilationUnit) delta.getElement();
+ if (unit.isWorkingCopy()) {
+ try {
+ unit.makeConsistent(null);
+ } catch (JavaModelException e) {
+ }
+ }
+ } else {
+ IJavaElementDelta[] deltas = delta.getAffectedChildren();
+ for (int i = 0; i < deltas.length; i++) {
+ walkDeltaMakingWorkingCopiesConsistent(deltas[i]);
+ }
+ }
+ }
+
+ /**
+ * @see IProgressMonitor
+ */
+ public void worked(int work) {
+ if (fMonitor != null) {
+ fMonitor.worked(work);
+ checkCanceled();
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelStatus.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelStatus.java
new file mode 100644
index 0000000000..8080495902
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelStatus.java
@@ -0,0 +1,358 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IPath;
+import java.util.Vector;
+
+import org.eclipse.jdt.core.IJavaModelStatusConstants;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jdt.core.IJavaModelStatus;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.resources.IResourceStatus;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * @see IJavaModelStatus
+ */
+
+public class JavaModelStatus
+ extends Status
+ implements IJavaModelStatus, IJavaModelStatusConstants, IResourceStatus {
+
+ /**
+ * The elements related to the failure, or <code>null</code>
+ * if no elements are involved.
+ */
+ protected IJavaElement[] fElements = new IJavaElement[0];
+ /**
+ * The path related to the failure, or <code>null</code>
+ * if no path is involved.
+ */
+ protected IPath fPath;
+ /**
+ * The <code>String</code> related to the failure, or <code>null</code>
+ * if no <code>String</code> is involved.
+ */
+ protected String fString;
+ /**
+ * Singleton OK object
+ */
+ public static final IJavaModelStatus VERIFIED_OK = new JavaModelStatus(OK);
+ /**
+ * Empty children
+ */
+ protected final static IStatus[] fgEmptyChildren = new IStatus[] {
+ };
+
+ protected IStatus[] fChildren = fgEmptyChildren;
+ /**
+ * Constructs an Java model status with no corresponding elements.
+ */
+ public JavaModelStatus() {
+ // no code for an multi-status
+ super(ERROR, JavaCore.PLUGIN_ID, 0, "JavaModelStatus", null);
+ }
+
+ /**
+ * Constructs an Java model status with no corresponding elements.
+ */
+ public JavaModelStatus(int code) {
+ super(ERROR, JavaCore.PLUGIN_ID, code, "JavaModelStatus", null);
+ fElements = JavaElementInfo.fgEmptyChildren;
+ }
+
+ /**
+ * Constructs an Java model status with the given corresponding
+ * elements.
+ */
+ public JavaModelStatus(int code, IJavaElement[] elements) {
+ super(ERROR, JavaCore.PLUGIN_ID, code, "JavaModelStatus", null);
+ fElements = elements;
+ fPath = null;
+ }
+
+ /**
+ * Constructs an Java model status with no corresponding elements.
+ */
+ public JavaModelStatus(int code, String string) {
+ super(ERROR, JavaCore.PLUGIN_ID, code, "JavaModelStatus", null);
+ fElements = JavaElementInfo.fgEmptyChildren;
+ fPath = null;
+ fString = string;
+ }
+
+ /**
+ * Constructs an Java model status with no corresponding elements.
+ */
+ public JavaModelStatus(int code, Throwable throwable) {
+ super(ERROR, JavaCore.PLUGIN_ID, code, "JavaModelStatus", throwable);
+ fElements = JavaElementInfo.fgEmptyChildren;
+ }
+
+ /**
+ * Constructs an Java model status with no corresponding elements.
+ */
+ public JavaModelStatus(int code, IPath path) {
+ super(ERROR, JavaCore.PLUGIN_ID, code, "JavaModelStatus", null);
+ fElements = JavaElementInfo.fgEmptyChildren;
+ fPath = path;
+ }
+
+ /**
+ * Constructs an Java model status with the given corresponding
+ * element.
+ */
+ public JavaModelStatus(int code, IJavaElement element) {
+ this(code, new IJavaElement[] { element });
+ }
+
+ /**
+ * Constructs an Java model status with the given corresponding
+ * element and string
+ */
+ public JavaModelStatus(int code, IJavaElement element, String string) {
+ this(code, new IJavaElement[] { element });
+ fString = string;
+ }
+
+ /**
+ * Constructs an Java model status with no corresponding elements.
+ */
+ public JavaModelStatus(CoreException coreException) {
+ super(
+ ERROR,
+ JavaCore.PLUGIN_ID,
+ CORE_EXCEPTION,
+ "JavaModelStatus",
+ coreException);
+ fElements = JavaElementInfo.fgEmptyChildren;
+ }
+
+ protected int getBits() {
+ int severity = 1 << (getCode() % 100 / 33);
+ int category = 1 << ((getCode() / 100) + 3);
+ return severity | category;
+ }
+
+ /**
+ * @see IStatus
+ */
+ public IStatus[] getChildren() {
+ return fChildren;
+ }
+
+ /**
+ * @see IJavaModelStatus
+ */
+ public IJavaElement[] getElements() {
+ return fElements;
+ }
+
+ /**
+ * Returns the message that is relevant to the code of this status.
+ */
+ public String getMessage() {
+ if (getException() == null) {
+ switch (getCode()) {
+ case CORE_EXCEPTION :
+ return "Core exception.";
+ case BUILDER_INITIALIZATION_ERROR :
+ return "Builder initialization error.";
+ case BUILDER_SERIALIZATION_ERROR :
+ return "Builder serialization error.";
+ case DEVICE_PATH :
+ return "Operation requires a path with no device. Path specified was: "
+ + getPath().toString();
+ case DOM_EXCEPTION :
+ return "JDOM error.";
+ case ELEMENT_DOES_NOT_EXIST :
+ return fElements[0].getElementName() + " does not exist.";
+ case EVALUATION_ERROR :
+ return "Evaluation error: " + getString();
+ case INDEX_OUT_OF_BOUNDS :
+ return "Index out of bounds.";
+ case INVALID_CONTENTS :
+ return "Invalid contents specified.";
+ case INVALID_DESTINATION :
+ return "Invalid destination: " + fElements[0].getElementName();
+ case INVALID_ELEMENT_TYPES :
+ StringBuffer buff =
+ new StringBuffer("Operation not supported for specified element type(s): ");
+ for (int i = 0; i < fElements.length; i++) {
+ if (i > 0) {
+ buff.append(", ");
+ }
+ buff.append(fElements[0].getElementName());
+ }
+ return buff.toString();
+ case INVALID_NAME :
+ return "Invalid name specified: " + getString();
+ case INVALID_PACKAGE :
+ return "Invalid package: " + getString();
+ case INVALID_PATH :
+ return "Invalid path: " + (getPath() == null ? "null" : getPath().toString());
+ case INVALID_PROJECT :
+ return "Invalid project: " + getString();
+ case INVALID_RESOURCE :
+ return "Invalid resource: " + getString();
+ case INVALID_RESOURCE_TYPE :
+ return "Invalid resource type for " + getString();
+ case INVALID_SIBLING :
+ return "Invalid sibling: " + fElements[0].getElementName();
+ case IO_EXCEPTION :
+ return "IO exception.";
+ case NAME_COLLISION :
+ if (fElements != null && fElements.length > 0) {
+ IJavaElement element = fElements[0];
+ String name = element.getElementName();
+ if (element instanceof IPackageFragment
+ && name.equals(IPackageFragment.DEFAULT_PACKAGE_NAME)) {
+ return "Default package cannot be renamed.";
+ }
+ }
+ return "Name collision.";
+ case NO_ELEMENTS_TO_PROCESS :
+ return "Operation requires one or more elements.";
+ case NULL_NAME :
+ return "Operation requires a name.";
+ case NULL_PATH :
+ return "Operation requires a path.";
+ case NULL_STRING :
+ return "Operation requires a string.";
+ case PATH_OUTSIDE_PROJECT :
+ return "Illegal path specified: " + getPath().toString();
+ case READ_ONLY :
+ IJavaElement element = fElements[0];
+ String name = element.getElementName();
+ if (element instanceof IPackageFragment
+ && name.equals(IPackageFragment.DEFAULT_PACKAGE_NAME)) {
+ name = "Default package";
+ }
+ return name + " is read-only.";
+ case RELATIVE_PATH :
+ return "Operation requires an absolute path. Relative path specified was: "
+ + getPath().toString();
+ case TARGET_EXCEPTION :
+ return "Target exception.";
+ case UPDATE_CONFLICT :
+ return "Update conflict.";
+ case NO_LOCAL_CONTENTS :
+ return "Cannot find local contents for resource: " + getPath().toString();
+ }
+ return getString();
+ } else {
+ if (getCode() == CORE_EXCEPTION) {
+ return "Core exception: " + getException().getMessage();
+ }
+ return getException().getMessage();
+ }
+ }
+
+ /**
+ * @see IOperationStatus
+ */
+ public IPath getPath() {
+ return fPath;
+ }
+
+ /**
+ * @see IStatus
+ */
+ public int getSeverity() {
+ if (fChildren == fgEmptyChildren)
+ return super.getSeverity();
+ int severity = -1;
+ for (int i = 0, max = fChildren.length; i < max; i++) {
+ int childrenSeverity = fChildren[i].getSeverity();
+ if (childrenSeverity > severity) {
+ severity = childrenSeverity;
+ }
+ }
+ return severity;
+ }
+
+ /**
+ * @see IJavaModelStatus
+ */
+ public String getString() {
+ return fString;
+ }
+
+ /**
+ * @see IJavaModelStatus
+ */
+ public boolean isDoesNotExist() {
+ return getCode() == ELEMENT_DOES_NOT_EXIST;
+ }
+
+ /**
+ * @see IStatus
+ */
+ public boolean isMultiStatus() {
+ return fChildren != fgEmptyChildren;
+ }
+
+ /**
+ * @see IJavaModelStatus
+ */
+ public boolean isOK() {
+ return getCode() == OK;
+ }
+
+ /**
+ * @see IStatus#matches
+ */
+ public boolean matches(int mask) {
+ if (!isMultiStatus()) {
+ return matches(this, mask);
+ } else {
+ for (int i = 0, max = fChildren.length; i < max; i++) {
+ if (matches((JavaModelStatus) fChildren[i], mask))
+ return true;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Helper for matches(int).
+ */
+ protected boolean matches(JavaModelStatus status, int mask) {
+ int severityMask = mask & 0x7;
+ int categoryMask = mask & ~0x7;
+ int bits = status.getBits();
+ return ((severityMask == 0) || (bits & severityMask) != 0)
+ && ((categoryMask == 0) || (bits & categoryMask) != 0);
+ }
+
+ /**
+ * Creates and returns a new <code>IJavaModelStatus</code> that is a
+ * a multi-status status.
+ *
+ * @see IStatus#.isMultiStatus()
+ */
+ public static IJavaModelStatus newMultiStatus(IJavaModelStatus[] children) {
+ JavaModelStatus jms = new JavaModelStatus();
+ jms.fChildren = children;
+ return jms;
+ }
+
+ /**
+ * Returns a printable representation of this exception for debugging
+ * purposes.
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("Java Model Status [");
+ buffer.append(getMessage());
+ buffer.append("]");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java
new file mode 100644
index 0000000000..62117b893f
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java
@@ -0,0 +1,1465 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.*;
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.internal.codeassist.ISearchableNameEnvironment;
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.eval.IEvaluationContext;
+import org.eclipse.jdt.internal.core.eval.EvaluationContextWrapper;
+import org.eclipse.jdt.internal.core.search.indexing.*;
+import org.eclipse.jdt.internal.core.util.*;
+import org.eclipse.jdt.internal.eval.EvaluationContext;
+
+import java.io.*;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import javax.xml.parsers.*;
+import org.apache.xerces.dom.*;
+import org.apache.xml.serialize.*;
+import org.w3c.dom.*;
+import org.xml.sax.*;
+
+/**
+ * Handle for a Java Project.
+ *
+ * <p>A Java Project internally maintains a devpath that corresponds
+ * to the project's classpath. The classpath may include source folders
+ * from the current project; jars in the current project, other projects,
+ * and the local file system; and binary folders (output location) of other
+ * projects. The Java Model presents source elements corresponding to output
+ * .class files in other projects, and thus uses the devpath rather than
+ * the classpath (which is really a compilation path). The devpath mimics
+ * the classpath, except has source folder entries in place of output
+ * locations in external projects.
+ *
+ * <p>Each JavaProject has an INameLookup facility that locates elements
+ * on by name, based on the devpath.
+ *
+ * @see IJavaProject
+ */
+public class JavaProject extends Openable implements IJavaProject, IProjectNature {
+ /**
+ * An empty array of strings indicating that a project doesn't have any prerequesite projects.
+ */
+ protected static final String[] NO_PREREQUISITES= new String[0];
+
+ /**
+ * The platform project this <code>IJavaProject</code> is based on
+ */
+ protected IProject fProject;
+
+ /**
+ * Constructor needed for <code>IProject.getNature()</code> and <code>IProject.addNature()</code>.
+ *
+ * @see #setProject
+ */
+ public JavaProject() {
+ super(JAVA_PROJECT, null, null);
+ }
+ public JavaProject(IProject project, IJavaElement parent) {
+ super(JAVA_PROJECT, parent, project.getName());
+ fProject= project;
+ }
+ /**
+ * Adds a builder to the build spec for the given project.
+ */
+ protected void addToBuildSpec(String builderID) throws CoreException {
+
+ IProjectDescription description= getProject().getDescription();
+ ICommand javaCommand = getJavaCommand(description);
+
+ if (javaCommand == null) {
+
+ // Add a Java command to the build spec
+ ICommand command= description.newCommand();
+ command.setBuilderName(builderID);
+ setJavaCommand(description, command);
+ }
+ }
+/**
+ * Returns a canonicalized path from the given external path.
+ * Note that the return path contains the same number of segments
+ * and it contains a device only if the given path contained one.
+ * @see java.io.File for the definition of a canonicalized path
+ */
+public static IPath canonicalizedPath(IPath externalPath) {
+ if (externalPath == null) return null;
+
+ // if not external path, return original path
+ if (ResourcesPlugin.getWorkspace().getRoot().findMember(externalPath) != null) {
+ return externalPath;
+ }
+
+ IPath canonicalPath = null;
+ try {
+ canonicalPath = new Path(new File(externalPath.toOSString()).getCanonicalPath());
+ } catch (IOException e) {
+ // default to original path
+ return externalPath;
+ }
+ // keep only segments that were in original path and device if it was there
+ IPath result = canonicalPath.removeFirstSegments(canonicalPath.segmentCount() - externalPath.segmentCount());
+ if (externalPath.getDevice() == null) {
+ return result.setDevice(null);
+ } else {
+ return result;
+ }
+}
+ /**
+ * Compute the file name to use for a given shared property
+ */
+ public String computeSharedPropertyFileName(QualifiedName qName){
+ return /*'.' + qName.getQualifier() + */ '.' + qName.getLocalName();
+ }
+ /**
+ * Configure the project with Java nature.
+ */
+ public void configure() throws CoreException {
+ // register Java builder
+ addToBuildSpec(JavaCore.BUILDER_ID);
+
+ // notify Java delta (Java project added)
+ JavaModelManager manager = (JavaModelManager) JavaModelManager.getJavaModelManager();
+ JavaModel model = (JavaModel) getJavaModel();
+ JavaElementDelta projectDelta = new JavaElementDelta(model);
+ projectDelta.added(this);
+ JavaElementInfo jmi= model.getElementInfo();
+ jmi.addChild(this);
+ manager.registerResourceDelta(projectDelta);
+ manager.fire();
+ }
+ /**
+ * Create's a classpath entry of the specified kind.
+ *
+ * Returns null if unable to create a valid entry.
+ */
+ protected IClasspathEntry createClasspathEntry(IPath path, int kind, IPath sourceAttachmentPath, IPath sourceAttachmentRootPath) {
+ switch(kind){
+
+ case IClasspathEntry.CPE_PROJECT :
+ if (!path.isAbsolute()) return null;
+ return JavaCore.newProjectEntry(path);
+
+ case IClasspathEntry.CPE_LIBRARY :
+ if (!path.isAbsolute()) return null;
+ return JavaCore.newLibraryEntry(path, sourceAttachmentPath, sourceAttachmentRootPath);
+
+ case IClasspathEntry.CPE_SOURCE :
+ if (!path.isAbsolute()) return null;
+ // must be an entry in this project or specify another project
+ // change zrh
+ String projSegment= path.segment(0);
+ if (projSegment != null && projSegment.equals(getElementName())) {
+ // this project
+ return JavaCore.newSourceEntry(path);
+ } else {
+ // another project
+ return JavaCore.newProjectEntry(path);
+ }
+
+ case IClasspathEntry.CPE_VARIABLE :
+ return JavaCore.newVariableEntry(path, sourceAttachmentPath, sourceAttachmentRootPath);
+
+ case ClasspathEntry.K_OUTPUT :
+ if (!path.isAbsolute()) return null;
+ return new ClasspathEntry(ClasspathEntry.K_OUTPUT, IClasspathEntry.CPE_LIBRARY, path, null, null);
+
+ default:
+ return null;
+ }
+ }
+ /**
+ * Returns a new element info for this element.
+ */
+ protected OpenableElementInfo createElementInfo() {
+ return new JavaProjectElementInfo();
+ }
+ /**
+ * Removes the Java nature from the project.
+ */
+ public void deconfigure() throws CoreException {
+
+ // deregister Java builder
+ removeFromBuildSpec(JavaCore.BUILDER_ID);
+ }
+ /**
+ * Returns a default class path.
+ * This is the root of the project
+ */
+ protected IClasspathEntry[] defaultClasspath() throws JavaModelException {
+ return new IClasspathEntry[] {JavaCore.newSourceEntry(getProject().getFullPath())};
+ }
+ /**
+ * Returns a default output location.
+ * This is the project bin folder
+ */
+ protected IPath defaultOutputLocation() throws JavaModelException {
+ return getProject().getFullPath().append("bin");
+ }
+ /**
+ * Returns true if this handle represents the same Java project
+ * as the given handle. Two handles represent the same
+ * project if they are identical or if they represent a project with
+ * the same underlying resource and occurrence counts.
+ *
+ * @see JavaElement#equals
+ */
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof JavaProject))
+ return false;
+ JavaProject other= (JavaProject) o;
+ return getProject().equals(other.getProject()) && fOccurrenceCount == other.fOccurrenceCount;
+ }
+ /**
+ * @see IJavaProject
+ */
+ public IJavaElement findElement(IPath path) throws JavaModelException {
+ if (path == null || path.isAbsolute()) {
+ throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, path));
+ }
+ try {
+ String extension= path.getFileExtension();
+ if (extension == null) {
+ String packageName= path.toString().replace(IPath.SEPARATOR, '.');
+ IPackageFragment[] pkgFragments = getNameLookup().findPackageFragments(packageName, false);
+ if (pkgFragments == null) {
+ return null;
+ } else {
+ // try to return one that is a child of this project
+ for (int i = 0, length = pkgFragments.length; i < length; i++) {
+ IPackageFragment pkgFragment = pkgFragments[i];
+ if (this.equals(pkgFragment.getParent().getParent())) {
+ return pkgFragment;
+ }
+ }
+ // default to the first one
+ return pkgFragments[0];
+ }
+ } else if (extension.equalsIgnoreCase("java") || extension.equalsIgnoreCase("class")) {
+ IPath packagePath= path.removeLastSegments(1);
+ String packageName= packagePath.toString().replace(IPath.SEPARATOR, '.');
+ String typeName= path.lastSegment();
+ typeName= typeName.substring(0, typeName.length() - extension.length() - 1);
+ String qualifiedName= null;
+ if (packageName.length() > 0) {
+ qualifiedName= packageName + "." + typeName;
+ } else {
+ qualifiedName= typeName;
+ }
+ IType type= getNameLookup().findType(qualifiedName, false, INameLookup.ACCEPT_CLASSES | INameLookup.ACCEPT_INTERFACES);
+ if (type != null) {
+ return type.getParent();
+ } else {
+ return null;
+ }
+ } else {
+ // unsupported extension
+ return null;
+ }
+ } catch (JavaModelException e) {
+ if (e.getStatus().getCode() == IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST) {
+ return null;
+ } else {
+ throw e;
+ }
+ }
+ }
+ /**
+ * @see INameLookup
+ */
+ public IPackageFragment findPackageFragment(IPath path) throws JavaModelException {
+ return getNameLookup().findPackageFragment(this.canonicalizedPath(path));
+ }
+ /**
+ * @see INameLookup
+ */
+ public IPackageFragmentRoot findPackageFragmentRoot(IPath path) throws JavaModelException {
+ return getNameLookup().findPackageFragmentRoot(this.canonicalizedPath(path));
+ }
+ /**
+ * @see Openable
+ */
+ protected boolean generateInfos(OpenableElementInfo info, IProgressMonitor pm, Hashtable newElements, IResource underlyingResource) throws JavaModelException {
+ boolean validInfo= false;
+ try {
+ if (((IProject) getUnderlyingResource()).isOpen()) {
+ // put the info now, because setting the classpath requires it
+ fgJavaModelManager.putInfo(this, info);
+
+ // read classpath property (contains actual classpath and output location settings)
+ boolean needToSaveClasspath = false;
+ IPath outputLocation= null;
+ IClasspathEntry[] classpath = null;
+
+ // read from file
+ String sharedClasspath = loadClasspath();
+ if (sharedClasspath != null){
+ try {
+ classpath = readPaths(sharedClasspath);
+ } catch (IOException e){
+ } catch (RuntimeException e){
+ }
+ // extract out the output location
+ if (classpath != null && classpath.length > 0) {
+ IClasspathEntry entry= classpath[classpath.length - 1];
+ if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
+ outputLocation = entry.getPath();
+ IClasspathEntry[] copy= new IClasspathEntry[classpath.length - 1];
+ System.arraycopy(classpath, 0, copy, 0, copy.length);
+ classpath= copy;
+ }
+ }
+ }
+ // restore output location
+ if (outputLocation == null) {
+ outputLocation= defaultOutputLocation();
+ needToSaveClasspath = true;
+ }
+ setOutputLocation0(outputLocation);
+
+ // restore classpath
+ if (classpath == null) {
+ classpath= defaultClasspath();
+ needToSaveClasspath = true;
+ }
+ setRawClasspath0(classpath);
+
+ // need to commit classpath ?
+ //if (needToSaveClasspath) saveClasspath();
+
+ // only valid if reaches here
+ validInfo= true;
+ }
+ } catch (JavaModelException e) {
+ } finally {
+ if (!validInfo)
+ fgJavaModelManager.removeInfo(this);
+ }
+ return validInfo;
+ }
+ /**
+ * @see IJavaProject
+ */
+ public IPackageFragmentRoot[] getAllPackageFragmentRoots() throws JavaModelException {
+ IJavaElement[] tempChildren= getElementInfo().getChildren();
+ IPackageFragmentRoot[] children= new IPackageFragmentRoot[tempChildren.length];
+ for (int i= 0; i < tempChildren.length; i++) {
+ children[i]= (IPackageFragmentRoot) tempChildren[i];
+ }
+ return children;
+ }
+ /**
+ * Returns all package fragments from all of the package fragment roots
+ * on the classpath.
+ */
+ public IPackageFragment[] getAllPackageFragments() throws JavaModelException {
+ IPackageFragmentRoot[] roots= getAllPackageFragmentRoots();
+ return getPackageFragmentsInRoots(roots);
+ }
+ /**
+ * Returns all the <code>IPackageFragmentRoot</code>s the builder needs to
+ * know about in order to build this project. This includes:
+ * <ul>
+ * <li>the source roots for the current project
+ * <li>the binary roots (output locations) for the required projects
+ * <li>the binary roots for any jar/lib used by this project
+ * </li>
+ */
+ public IPackageFragmentRoot[] getBuilderRoots(IResourceDelta delta) throws JavaModelException {
+ Vector builderRoots= new Vector();
+ IClasspathEntry[] classpath;
+ classpath= getResolvedClasspath(true);
+ IResource res;
+ IJavaProject project;
+ for (int i= 0; i < classpath.length; i++) {
+ IClasspathEntry entry= classpath[i];
+ switch (entry.getEntryKind()) {
+ case IClasspathEntry.CPE_LIBRARY :
+ IPackageFragmentRoot[] roots= this.getPackageFragmentRoots(entry);
+ if (roots.length > 0)
+ builderRoots.addElement(roots[0]);
+ break;
+ case IClasspathEntry.CPE_PROJECT :
+ // other project contributions are restrained to their binary output
+ res= retrieveResource(entry.getPath(), delta);
+ if (res != null) {
+ project= (IJavaProject) JavaCore.create(res);
+ if (project.isOpen()){
+ res= retrieveResource(project.getOutputLocation(), delta);
+ if (res != null) {
+ PackageFragmentRoot root= (PackageFragmentRoot) project.getPackageFragmentRoot(res);
+ root.setOccurrenceCount(root.getOccurrenceCount() + 1);
+ ((PackageFragmentRootInfo) root.getElementInfo()).setRootKind(IPackageFragmentRoot.K_BINARY);
+ root.refreshChildren();
+ builderRoots.addElement(root);
+ }
+ }
+ }
+ break;
+ case IClasspathEntry.CPE_SOURCE :
+ if (getCorrespondingResource().getFullPath().isPrefixOf(entry.getPath())) {
+ res= retrieveResource(entry.getPath(), delta);
+ if (res != null)
+ builderRoots.addElement(getPackageFragmentRoot(res));
+ } else {
+ IProject proj= (IProject) getWorkspace().getRoot().findMember(entry.getPath());
+ project= (IJavaProject) JavaCore.create(proj);
+ if (proj.isOpen()){
+ res= retrieveResource(project.getOutputLocation(), delta);
+ PackageFragmentRoot root= (PackageFragmentRoot) project.getPackageFragmentRoot(res);
+ root.setOccurrenceCount(root.getOccurrenceCount() + 1);
+ ((PackageFragmentRootInfo) root.getElementInfo()).setRootKind(IPackageFragmentRoot.K_BINARY);
+ root.refreshChildren();
+ builderRoots.addElement(root);
+ }
+ }
+ break;
+ }
+ }
+ IPackageFragmentRoot[] result= new IPackageFragmentRoot[builderRoots.size()];
+ builderRoots.copyInto(result);
+ return result;
+ }
+ /**
+ * @see IParent
+ */
+ public IJavaElement[] getChildren() throws JavaModelException {
+ return getPackageFragmentRoots();
+ }
+ /**
+ * @see IJavaProject
+ * @deprecated
+ */
+ public IClasspathEntry[] getClasspath() throws JavaModelException {
+ return getRawClasspath();
+ }
+ /**
+ * Returns the XML String encoding of the class path.
+ */
+ protected String getClasspathAsXMLString(IClasspathEntry[] classpath, IPath outputLocation) throws JavaModelException {
+ Document doc= new DocumentImpl();
+ Element cpElement= doc.createElement("classpath");
+ doc.appendChild(cpElement);
+
+ for (int i= 0; i < classpath.length; ++i) {
+ Element cpeElement= getEntryAsXMLElement(doc, classpath[i], getProject().getFullPath());
+ cpElement.appendChild(cpeElement);
+ }
+
+ if (outputLocation != null) {
+ outputLocation= outputLocation.removeFirstSegments(1);
+ outputLocation= outputLocation.makeRelative();
+ Element oElement= doc.createElement("classpathentry");
+ oElement.setAttribute("kind", kindToString(ClasspathEntry.K_OUTPUT));
+ oElement.setAttribute("path", outputLocation.toOSString());
+ cpElement.appendChild(oElement);
+ }
+
+ // produce a String output
+ StringWriter writer = new StringWriter();
+ try {
+ OutputFormat format = new OutputFormat();
+ format.setIndenting(true);
+ Serializer serializer = SerializerFactory.getSerializerFactory(Method.XML).makeSerializer(writer, format);
+ serializer.asDOMSerializer().serialize(doc);
+ } catch (IOException e) {
+ throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
+ }
+ return writer.toString();
+ }
+ /**
+ * Returns the classpath entry that refers to the given path
+ * or <code>null</code> if there is no reference to the path.
+ */
+ public IClasspathEntry getClasspathEntryFor(IPath path) throws JavaModelException {
+ IClasspathEntry[] entries= getResolvedClasspath(true);
+ for (int i= 0; i < entries.length; i++) {
+ if (entries[i].getPath().equals(path)) {
+ return entries[i];
+ }
+ }
+ return null;
+ }
+ /**
+ * Returns the qualified name for the classpath server property
+ * of this project
+ */
+ public QualifiedName getClasspathPropertyName() {
+ return new QualifiedName(JavaCore.PLUGIN_ID, "classpath");
+ }
+ /**
+ * Returns the XML String encoding of the class path.
+ */
+ protected static Element getEntryAsXMLElement(Document document, IClasspathEntry entry, IPath prefixPath) throws JavaModelException {
+
+ Element element= document.createElement("classpathentry");
+ element.setAttribute("kind", kindToString(entry.getEntryKind()));
+ IPath path= entry.getPath();
+ if (entry.getEntryKind() != IClasspathEntry.CPE_VARIABLE){
+ // translate to project relative from absolute (unless a device path)
+ if (path.isAbsolute()) {
+ if (prefixPath != null && prefixPath.isPrefixOf(path)) {
+ if (path.segment(0).equals(prefixPath.segment(0))) {
+ path= path.removeFirstSegments(1);
+ path= path.makeRelative();
+ } else {
+ path= path.makeAbsolute();
+ }
+ }
+ }
+ }
+ element.setAttribute("path", path.toString());
+ if (entry.getSourceAttachmentPath() != null){
+ element.setAttribute("sourcepath", entry.getSourceAttachmentPath().toString());
+ }
+ if (entry.getSourceAttachmentRootPath() != null){
+ element.setAttribute("rootpath", entry.getSourceAttachmentRootPath().toString());
+ }
+ return element;
+ }
+ /**
+ * Returns the <code>char</code> that marks the start of this handles
+ * contribution to a memento.
+ */
+ protected char getHandleMementoDelimiter() {
+ return JEM_JAVAPROJECT;
+ }
+ /**
+ * Find the specific Java command amongst the build spec of a given description
+ */
+ private ICommand getJavaCommand(IProjectDescription description) throws CoreException {
+ ICommand[] commands= description.getBuildSpec();
+ for (int i= 0; i < commands.length; ++i) {
+ if (commands[i].getBuilderName().equals(JavaCore.BUILDER_ID)) {
+ return commands[i];
+ }
+ }
+ return null;
+ }
+ /**
+ * @see IJavaElement
+ */
+ public IJavaProject getJavaProject() {
+ return this;
+ }
+ /**
+ * Convenience method that returns the specific type of info for a Java project.
+ */
+ protected JavaProjectElementInfo getJavaProjectElementInfo() throws JavaModelException {
+ return (JavaProjectElementInfo) getElementInfo();
+ }
+ /**
+ * @see IJavaProject
+ */
+ public INameLookup getNameLookup() throws JavaModelException {
+ JavaProjectElementInfo info= getJavaProjectElementInfo();
+ if (info.getNameLookup() == null) {
+ info.setNameLookup(new NameLookup(this));
+ }
+ return info.getNameLookup();
+ }
+ /**
+ * Returns an array of non-java resources contained in the receiver.
+ */
+ public Object[] getNonJavaResources() throws JavaModelException {
+ return ((JavaProjectElementInfo) getElementInfo()).getNonJavaResources(this);
+ }
+ /**
+ * @see IJavaProject
+ */
+ public IPath getOutputLocation() throws JavaModelException {
+ IPath path = getJavaProjectElementInfo().getOutputLocation();
+ if (path == null) {
+ return this.defaultOutputLocation();
+ } else {
+ return path;
+ }
+ }
+ /**
+ * @see IJavaProject
+ */
+ public IPackageFragmentRoot getPackageFragmentRoot(String jarPath) {
+ jarPath = this.canonicalizedPath(new Path(jarPath)).toString();
+ return new JarPackageFragmentRoot(jarPath, this);
+ }
+ /**
+ * @see IJavaProject
+ */
+ public IPackageFragmentRoot getPackageFragmentRoot(IResource resource) {
+ String name= resource.getName().toUpperCase();
+ if (name.endsWith(".JAR") || name.endsWith(".ZIP")) {
+ return new JarPackageFragmentRoot(resource, this);
+ } else {
+ return new PackageFragmentRoot(resource, this);
+ }
+ }
+ /**
+ * Returns a handle to the package fragment root identified by the given path.
+ * This method is handle-only and the element may or may not exist. Returns
+ * <code>null</code> if unable to generate a handle from the path (for example,
+ * an absolute path that has less than 2 segments. The path may be relative or
+ * absolute.
+ *
+ * @private
+ */
+ public IPackageFragmentRoot getPackageFragmentRoot(IPath path) {
+
+ IResource resource = null;
+ if (!path.isAbsolute() || (resource = getProject().getWorkspace().getRoot().findMember(path)) != null) {
+ if (resource != null){
+ return getPackageFragmentRoot(resource);
+ }
+ if (path.segmentCount() > 0) {
+ String ext= path.getFileExtension();
+ if (ext == null) {
+ return getPackageFragmentRoot(getProject().getFolder(path));
+ } else {
+ // resource jar
+ return getPackageFragmentRoot(getProject().getFile(path));
+ }
+ } else {
+ // default root
+ return getPackageFragmentRoot(getProject());
+ }
+ } else {
+ return getPackageFragmentRoot(path.toString()); // external jar
+ }
+ }
+ /**
+ * @see IJavaProject
+ */
+ public IPackageFragmentRoot[] getPackageFragmentRoots() throws JavaModelException {
+ IPackageFragmentRoot[] children= getAllPackageFragmentRoots();
+ Vector directChildren= new Vector(children.length);
+ for (int i= 0; i < children.length; i++) {
+ IPackageFragmentRoot root= children[i];
+ IJavaProject proj= root.getJavaProject();
+ if (proj != null && proj.equals(this)) {
+ directChildren.addElement(root);
+ }
+ }
+ children= new IPackageFragmentRoot[directChildren.size()];
+ directChildren.copyInto(children);
+ return children;
+ }
+ /**
+ * Returns the package fragment root prefixed by the given path, or
+ * an empty collection if there are no such elements in the model.
+ */
+ protected IPackageFragmentRoot[] getPackageFragmentRoots(IPath path) throws JavaModelException {
+ IPackageFragmentRoot[] roots= getAllPackageFragmentRoots();
+ Vector matches= new Vector();
+ for (int i= 0; i < roots.length; ++i) {
+ if (path.isPrefixOf(roots[i].getPath())) {
+ matches.addElement(roots[i]);
+ }
+ }
+ IPackageFragmentRoot[] copy= new IPackageFragmentRoot[matches.size()];
+ matches.copyInto(copy);
+ return copy;
+ }
+ /**
+ * Returns the package fragment roots identified by the given entry.
+ */
+ public IPackageFragmentRoot[] getPackageFragmentRoots(IClasspathEntry entry) {
+
+ entry = JavaCore.getResolvedClasspathEntry(entry);
+ if (entry == null){
+ return new IPackageFragmentRoot[] {}; // variable not found
+ }
+ IPath path= entry.getPath();
+ IWorkspaceRoot workspaceRoot = getWorkspace().getRoot();
+
+ if (entry.getContentKind() == IPackageFragmentRoot.K_BINARY) {
+ String ext= path.getFileExtension();
+ IPackageFragmentRoot root= null;
+ if (ext != null && (ext.equalsIgnoreCase("zip") || ext.equalsIgnoreCase("jar"))) {
+ // jar
+ // removeFirstSegment removes the part relative to the project which is retrieve
+ // through workspace.getDefaultContentLocation
+ if (path.isAbsolute() && getWorkspace().getRoot().findMember(path) == null) {
+ // file system jar
+ root= new JarPackageFragmentRoot(path.toOSString(), this);
+ } else {
+ // resource jar
+ root= new JarPackageFragmentRoot(workspaceRoot.getFile(path), this);
+ }
+ return new IPackageFragmentRoot[] {root};
+ }
+ }
+ IPath projectPath= getProject().getFullPath();
+ if (projectPath.isPrefixOf(path)) {
+ // local to this project
+ IResource resource= null;
+ // change zrh
+ if (path.segmentCount() > 1) {
+ resource= workspaceRoot.getFolder(path);
+ } else {
+ resource= workspaceRoot.findMember(path);
+ }
+ IPackageFragmentRoot root= new PackageFragmentRoot(resource, this);
+ return new IPackageFragmentRoot[] {root};
+ } else {
+ // another project
+ // change zrh
+ if (path.segmentCount() != 1)
+ return new IPackageFragmentRoot[] {}; // invalid path for a project
+ String project= path.segment(0);
+ IJavaProject javaProject= getJavaModel().getJavaProject(project);
+ Vector sourceRoots= new Vector();
+ IPackageFragmentRoot[] roots= null;
+ try {
+ roots= javaProject.getPackageFragmentRoots();
+ } catch (JavaModelException e) {
+ return new IPackageFragmentRoot[] {};
+ }
+ for (int i= 0; i < roots.length; i++) {
+ try {
+ if (roots[i].getKind() == IPackageFragmentRoot.K_SOURCE) {
+ sourceRoots.addElement(roots[i]);
+ }
+ } catch (JavaModelException e) {
+ // do nothing if the root does not exist
+ }
+ }
+ IPackageFragmentRoot[] copy= new IPackageFragmentRoot[sourceRoots.size()];
+ sourceRoots.copyInto(copy);
+ return copy;
+ }
+ }
+ /**
+ * @see IJavaProject
+ */
+ public IPackageFragment[] getPackageFragments() throws JavaModelException {
+ IPackageFragmentRoot[] roots= getPackageFragmentRoots();
+ return getPackageFragmentsInRoots(roots);
+ }
+ /**
+ * Returns all the package fragments found in the specified
+ * package fragment roots.
+ */
+ protected IPackageFragment[] getPackageFragmentsInRoots(IPackageFragmentRoot[] roots) {
+ Vector frags= new Vector();
+ for (int i= 0; i < roots.length; i++) {
+ IPackageFragmentRoot root= roots[i];
+ try {
+ IJavaElement[] rootFragments= root.getChildren();
+ for (int j= 0; j < rootFragments.length; j++) {
+ frags.addElement(rootFragments[j]);
+ }
+ } catch (JavaModelException e) {
+ // do nothing
+ }
+ }
+ IPackageFragment[] fragments= new IPackageFragment[frags.size()];
+ frags.copyInto(fragments);
+ return fragments;
+ }
+ /**
+ * @see IJavaProject
+ */
+ public IProject getProject() {
+ return fProject;
+ }
+ /**
+ * @see IJavaProject
+ */
+ public IClasspathEntry[] getRawClasspath() throws JavaModelException {
+ JavaProjectElementInfo info= getJavaProjectElementInfo();
+ IClasspathEntry[] classpath= info.getRawClasspath();
+ if (classpath != null) {
+ return classpath;
+ }
+ return defaultClasspath();
+ }
+/**
+ * @see IJavaProject#getRequiredProjectNames
+ */
+public String[] getRequiredProjectNames() throws JavaModelException {
+ return this.projectPrerequisites(getResolvedClasspath(true));
+}
+ /**
+ * @see IJavaProject
+ */
+ public IClasspathEntry[] getResolvedClasspath(boolean ignoreUnresolvedVariable) throws JavaModelException {
+
+ IClasspathEntry[] classpath = getRawClasspath();
+ IClasspathEntry[] resolvedPath = classpath; // clone only if necessary
+ int length = classpath.length;
+ int index = 0;
+
+ for (int i = 0; i < length; i++){
+
+ IClasspathEntry entry = classpath[i];
+
+ /* resolve variables if any, unresolved ones are ignored */
+ if (entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE){
+
+ // clone original path
+ if (resolvedPath == classpath){
+ System.arraycopy(classpath, 0, resolvedPath = new IClasspathEntry[length], 0, i);
+ }
+ // resolve current variable (handling variable->variable->variable->entry
+ IPath variablePath = entry.getPath(); // for error reporting
+ entry = JavaCore.getResolvedClasspathEntry(entry);
+ if (entry == null && !ignoreUnresolvedVariable){
+ throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.CP_VARIABLE_PATH_UNBOUND, variablePath.toString()));
+ }
+ }
+ if (entry != null){
+ resolvedPath[index++] = entry;
+ }
+ }
+
+ // resize resolved classpath in case some variable entries could not be resolved
+ if (index != length){
+ System.arraycopy(resolvedPath, 0, resolvedPath = new IClasspathEntry[index], 0, index);
+ }
+ return resolvedPath;
+ }
+ /**
+ * @see IJavaProject
+ */
+ public ISearchableNameEnvironment getSearchableNameEnvironment() throws JavaModelException {
+ JavaProjectElementInfo info= getJavaProjectElementInfo();
+ if (info.getSearchableEnvironment() == null) {
+ info.setSearchableEnvironment(new SearchableEnvironment(this));
+ }
+ return info.getSearchableEnvironment();
+ }
+ /**
+ * Retrieve a shared property on a project. If the property is not defined, answers null.
+ * Note that it is orthogonal to IResource persistent properties, and client code has to decide
+ * which form of storage to use appropriately. Shared properties produce real resource files which
+ * can be shared through a VCM onto a server. Persistent properties are not shareable.
+ *
+ * @see JavaProject.setSharedProperty(...)
+ */
+ public String getSharedProperty(QualifiedName key) throws CoreException {
+
+ String property = null;
+ try {
+ String propertyFileName= computeSharedPropertyFileName(key);
+ IFile rscFile = getProject().getFile(propertyFileName);
+ if (rscFile.exists()){
+ InputStream input = rscFile.getContents(true);
+ property = new String(Util.readContentsAsBytes(input));
+ }
+ } catch (IOException e) {
+ }
+ return property;
+ }
+ /**
+ * @see JavaElement
+ */
+ public SourceMapper getSourceMapper() {
+ return null;
+ }
+ /**
+ * @see IJavaElement
+ */
+ public IResource getUnderlyingResource() throws JavaModelException {
+ return getProject();
+ }
+ /**
+ * @see IJavaProject
+ */
+ public boolean hasBuildState() {
+ return JavaModelManager.getJavaModelManager().getLastBuiltState(this.getProject(), null) != null;
+ }
+ /**
+ * @see IJavaProject
+ */
+ public boolean hasClasspathCycle(IClasspathEntry[] entries) {
+ StringHashtableOfInt depthTable= new StringHashtableOfInt();
+ try {
+ String projectName= this.getElementName();
+ depthTable.put(projectName, -2); // mark this project as being visited
+ String[] prerequisites= this.projectPrerequisites(entries);
+ for (int i= 0, length= prerequisites.length; i < length; i++) {
+ ((JavaModel) this.getJavaModel()).computeDepth(prerequisites[i], depthTable, projectName, false);
+ }
+ } catch (JavaModelException e) {
+ return e.getStatus().getCode() == IJavaModelStatusConstants.NAME_COLLISION;
+ }
+ return false;
+ }
+ public int hashCode() {
+ return fProject.hashCode();
+ }
+ /**
+ * Answers true if the project potentially contains any source. A project which has no source is immutable.
+ */
+ public boolean hasSource() {
+ // look if any source folder on the classpath
+ // no need for resolved path given source folder cannot be abstracted
+ IClasspathEntry[] entries;
+ try {
+ entries = this.getRawClasspath();
+ } catch(JavaModelException e){
+ return true; // unsure
+ }
+ for (int i = 0, max = entries.length; i < max; i++){
+ if (entries[i].getEntryKind() == IClasspathEntry.CPE_SOURCE){
+ return true;
+ }
+ }
+ return false;
+ }
+ /**
+ * Compare current classpath with given one to see if any different.
+ * Note that the argument classpath contains its binary output.
+ */
+ public boolean isClasspathEqualsTo(IClasspathEntry[] otherClasspathWithOutput) throws JavaModelException {
+
+ if (otherClasspathWithOutput != null && otherClasspathWithOutput.length > 0) {
+
+ IClasspathEntry[] classpath = getRawClasspath();
+ int length = otherClasspathWithOutput.length;
+ if (length == classpath.length+1){ // output is amongst file entries (last one)
+
+ // compare classpath entries
+ for (int i = 0; i < length-1; i++){
+ if (!otherClasspathWithOutput[i].equals(classpath[i])) return false;
+ }
+ // compare binary outputs
+ if (otherClasspathWithOutput[length-1].getContentKind() == ClasspathEntry.K_OUTPUT
+ && otherClasspathWithOutput[length-1].getPath().equals(getOutputLocation())) return true;
+ }
+ }
+ return false;
+ }
+ /**
+ * Returns the kind of a <code>PackageFragmentRoot</code> from its <code>String</code> form.
+ */
+ static int kindFromString(String kindStr) {
+ if (kindStr.equalsIgnoreCase("prj"))
+ return IClasspathEntry.CPE_PROJECT;
+ if (kindStr.equalsIgnoreCase("var"))
+ return IClasspathEntry.CPE_VARIABLE;
+ if (kindStr.equalsIgnoreCase("src"))
+ return IClasspathEntry.CPE_SOURCE;
+ if (kindStr.equalsIgnoreCase("lib"))
+ return IClasspathEntry.CPE_LIBRARY;
+ if (kindStr.equalsIgnoreCase("output"))
+ return ClasspathEntry.K_OUTPUT;
+ return -1;
+ }
+ /**
+ * Returns a <code>String</code> for the kind of a class path entry.
+ */
+ static String kindToString(int kind) {
+ switch (kind) {
+ case IClasspathEntry.CPE_PROJECT :
+ return "src"; // backward compatibility
+ case IClasspathEntry.CPE_SOURCE :
+ return "src";
+ case IClasspathEntry.CPE_LIBRARY :
+ return "lib";
+ case IClasspathEntry.CPE_VARIABLE :
+ return "var";
+ case ClasspathEntry.K_OUTPUT :
+ return "output";
+ default :
+ return "unknown";
+ }
+ }
+ /**
+ * load the classpath from a shareable format (VCM-wise)
+ */
+ public String loadClasspath() throws JavaModelException {
+
+ try {
+ return getSharedProperty(getClasspathPropertyName());
+ } catch(CoreException e){
+ throw new JavaModelException(e);
+ }
+ }
+ /**
+ * @see IJavaProject#newEvaluationContext
+ */
+ public IEvaluationContext newEvaluationContext() {
+ return new EvaluationContextWrapper(new EvaluationContext(), this);
+ }
+ /**
+ * @see IJavaProject
+ * @deprecated
+ */
+ public IClasspathEntry newLibraryEntry(IPath path) {
+ return JavaCore.newLibraryEntry(path, null, null);
+ }
+ /**
+ * @see IJavaProject
+ * @deprecated
+ */
+ public IClasspathEntry newProjectEntry(IPath path) {
+ return JavaCore.newProjectEntry(path);
+ }
+ /**
+ * @see IJavaProject
+ * @deprecated
+ */
+ public IClasspathEntry newSourceEntry(IPath path) {
+ return JavaCore.newSourceEntry(path);
+ }
+ /**
+ * @see IJavaProject
+ */
+ public ITypeHierarchy newTypeHierarchy(IRegion region, IProgressMonitor monitor) throws JavaModelException {
+ if (region == null) {
+ throw new IllegalArgumentException("region cannot be null");
+ }
+ CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(null, region, this, true);
+ runOperation(op, monitor);
+ return op.getResult();
+ }
+ /**
+ * @see IJavaProject
+ */
+ public ITypeHierarchy newTypeHierarchy(IType type, IRegion region, IProgressMonitor monitor) throws JavaModelException {
+ if (type == null) {
+ throw new IllegalArgumentException("type cannot be null");
+ }
+ if (region == null) {
+ throw new IllegalArgumentException("region cannot be null");
+ }
+ CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(type, region, this, true);
+ runOperation(op, monitor);
+ return op.getResult();
+ }
+ /**
+ * Ensures that this project is not currently being deleted before
+ * opening.
+ *
+ * fix for 1FW67PA
+ */
+ public void open(IProgressMonitor pm) throws JavaModelException {
+ JavaModelManager manager= (JavaModelManager) JavaModelManager.getJavaModelManager();
+ if (manager.isBeingDeleted(fProject)) {
+ throw newNotPresentException();
+ } else {
+ super.open(pm);
+ }
+ }
+ /**
+ * Ensures that this project is not currently being deleted before
+ * opening.
+ *
+ * fix for 1FW67PA
+ */
+ protected void openWhenClosed(IProgressMonitor pm) throws JavaModelException {
+ JavaModelManager manager= (JavaModelManager) JavaModelManager.getJavaModelManager();
+ if (manager.isBeingDeleted(fProject) || !this.fProject.isOpen()) {
+ throw newNotPresentException();
+ } else {
+ super.openWhenClosed(pm);
+ }
+ }
+ private String[] projectPrerequisites(IClasspathEntry[] entries) throws JavaModelException {
+ Vector prerequisites= new Vector();
+ for (int i= 0, length= entries.length; i < length; i++) {
+ IClasspathEntry entry= entries[i];
+ entry = JavaCore.getResolvedClasspathEntry(entry);
+ if (entry == null) continue; // ignore unbound variable
+ if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
+ prerequisites.add(entry.getPath().lastSegment());
+ }
+ }
+ int size= prerequisites.size();
+ if (size == 0) {
+ return NO_PREREQUISITES;
+ } else {
+ String[] result= new String[size];
+ prerequisites.copyInto(result);
+ return result;
+ }
+ }
+ /**
+ * Returns a collection of <code>IClasspathEntry</code>s from the given
+ * classpath string in XML format.
+ *
+ * @exception IOException if the stream cannot be read
+ */
+ protected IClasspathEntry[] readPaths(String xmlClasspath) throws IOException {
+ IPath projectPath= getProject().getFullPath();
+ StringReader reader = new StringReader(xmlClasspath);
+ Element cpElement;
+ try {
+ DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ cpElement = parser.parse(new InputSource(reader)).getDocumentElement();
+ } catch(SAXException e) {
+ throw new IOException("bad format");
+ } catch(ParserConfigurationException e){
+ reader.close();
+ throw new IOException("bad format");
+ } finally {
+ reader.close();
+ }
+ if (!cpElement.getNodeName().equalsIgnoreCase("classpath")) {
+ throw new IOException("bad format");
+ }
+ NodeList list= cpElement.getChildNodes();
+ Vector paths= new Vector();
+ int length= list.getLength();
+ for (int i= 0; i < length; ++i) {
+ Node node= list.item(i);
+ short type= node.getNodeType();
+ if (type == Node.ELEMENT_NODE) {
+ Element cpeElement= (Element) node;
+ if (cpeElement.getNodeName().equalsIgnoreCase("classpathentry")) {
+ String cpeElementKind = cpeElement.getAttribute("kind");
+ String pathStr = cpeElement.getAttribute("path");
+ // ensure path is absolute
+ IPath path= new Path(pathStr);
+ int kind= kindFromString(cpeElementKind);
+ if (kind != IClasspathEntry.CPE_VARIABLE && !path.isAbsolute()) {
+ path= projectPath.append(path);
+ }
+ // source attachment info (optional)
+ String sourceAttachmentPathStr = cpeElement.getAttribute("sourcepath");
+ IPath sourceAttachmentPath = sourceAttachmentPathStr.equals("") ? null : new Path(sourceAttachmentPathStr);
+ String sourceAttachmentRootPathStr = cpeElement.getAttribute("rootpath");
+ IPath sourceAttachmentRootPath = sourceAttachmentRootPathStr.equals("") ? null : new Path(sourceAttachmentRootPathStr);
+
+ IClasspathEntry entry= createClasspathEntry(path, kind, sourceAttachmentPath, sourceAttachmentRootPath);
+ if (entry == null) return null;
+ paths.addElement(entry);
+ }
+ }
+ }
+ if (paths.size() > 0) {
+ IClasspathEntry[] ips= new IClasspathEntry[paths.size()];
+ paths.copyInto(ips);
+ return ips;
+ } else {
+ return null;
+ }
+ }
+ /**
+ * Removes the given builder from the build spec for the given project.
+ */
+ protected void removeFromBuildSpec(String builderID) throws CoreException {
+ IProjectDescription description= getProject().getDescription();
+ ICommand[] commands= description.getBuildSpec();
+ for (int i= 0; i < commands.length; ++i) {
+ if (commands[i].getBuilderName().equals(builderID)) {
+ ICommand[] newCommands= new ICommand[commands.length - 1];
+ System.arraycopy(commands, 0, newCommands, 0, i);
+ System.arraycopy(commands, i + 1, newCommands, i, commands.length - i - 1);
+ description.setBuildSpec(newCommands);
+ getProject().setDescription(description, null);
+ return;
+ }
+ }
+ }
+/**
+ * Reset the non-java resources collection for package fragment roots of the
+ * receiver
+ */
+protected void resetNonJavaResourcesForPackageFragmentRoots() throws JavaModelException {
+ IPackageFragmentRoot[] roots = getAllPackageFragmentRoots();
+ if (roots == null) return;
+ for (int i = 0, max = roots.length; i < max; i++) {
+ IPackageFragmentRoot root = roots[i];
+ try {
+ IResource res = root.getUnderlyingResource();
+ if (res != null) {
+ ((PackageFragmentRoot)root).resetNonJavaResources();
+ }
+ } catch(JavaModelException e) {
+ // ignore if the resource cannot be retrieved anymore.
+ }
+ }
+}
+ /**
+ * Returns the <code>IResource</code> that correspond to the specified path.
+ * null if none.
+ */
+ private IResource retrieveResource(IPath path, IResourceDelta delta) throws JavaModelException {
+ IWorkspaceRoot workspaceRoot = getWorkspace().getRoot();
+ IResource res= workspaceRoot.findMember(path);
+
+ if (delta == null)
+ return res;
+
+ if (res == null) {
+ // the resource has been removed or renamed
+ // look for a possible delta that might help to retrieve the new resource if case of renamed
+ IResourceDelta[] deltas= delta.getAffectedChildren();
+ for (int i= 0, max= deltas.length; i < max; i++) {
+ IResourceDelta currentDelta= deltas[i];
+ if (currentDelta.getKind() == IResourceDelta.REMOVED) {
+ IPath moveToPath= currentDelta.getMovedToPath();
+ if (moveToPath != null) {
+ res= workspaceRoot.findMember(moveToPath);
+ if (res == null) {
+ throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, moveToPath));
+ }
+ break;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ return res;
+ }
+ /**
+ * Save the classpath in a shareable format (VCM-wise) if necessary (i.e. semantically different)
+ */
+ public void saveClasspath() throws JavaModelException {
+ this.saveClasspath(false);
+ }
+ /**
+ * Save the classpath in a shareable format (VCM-wise) if necessary (i.e. semantically different)
+ */
+ public void saveClasspath(boolean force) throws JavaModelException {
+ if (!getProject().exists()) return;
+ if (!isOpen()) return; // no update for closed projects ???
+
+ QualifiedName classpathProp = getClasspathPropertyName();
+
+ try {
+ // attempt to prove the classpath has not change
+ String fileClasspathString = getSharedProperty(classpathProp);
+ if (fileClasspathString != null){
+ IClasspathEntry[] fileEntries = readPaths(fileClasspathString);
+ if (!force && isClasspathEqualsTo(fileEntries)) {
+ // no need to save it, it is already the same
+ return;
+ }
+ }
+ } catch (IOException e){
+ } catch (RuntimeException e){
+ } catch(CoreException e){
+ }
+
+ // actual file saving
+ try {
+ setSharedProperty(
+ classpathProp,
+ getClasspathAsXMLString(getRawClasspath(), getOutputLocation()));
+ } catch(CoreException e){
+ throw new JavaModelException(e);
+ }
+ }
+ /**
+ * @see IJavaProject
+ * @deprecated
+ */
+ public void setClasspath(IClasspathEntry[] entries, IProgressMonitor monitor) throws JavaModelException {
+ setRawClasspath(entries, monitor, true);
+ }
+ /**
+ * Update the Java command in the build spec (replace existing one if present,
+ * add one first if none).
+ */
+ private void setJavaCommand(IProjectDescription description, ICommand newCommand) throws CoreException {
+
+ ICommand[] oldCommands = description.getBuildSpec();
+ ICommand oldJavaCommand = getJavaCommand(description);
+
+ ICommand[] newCommands;
+
+ if (oldJavaCommand == null) {
+ // Add a Java build spec before other builders (1FWJK7I)
+ newCommands = new ICommand[oldCommands.length + 1];
+ System.arraycopy(oldCommands, 0, newCommands, 1, oldCommands.length);
+ newCommands[0]= newCommand;
+ } else {
+ for (int i = 0, max = oldCommands.length; i < max; i++){
+ if (oldCommands[i] == oldJavaCommand){
+ oldCommands[i] = newCommand;
+ break;
+ }
+ }
+ newCommands = oldCommands;
+ }
+
+ // Commit the spec change into the project
+ description.setBuildSpec(newCommands);
+ getProject().setDescription(description, null);
+ }
+ /**
+ * @see IJavaProject
+ */
+ public void setOutputLocation(IPath outputLocation, IProgressMonitor monitor) throws JavaModelException {
+ if (outputLocation == null) {
+ throw new IllegalArgumentException("path cannot be null");
+ }
+ if (outputLocation.equals(getOutputLocation())) {
+ return;
+ }
+ SetOutputLocationOperation op= new SetOutputLocationOperation(this, outputLocation);
+ runOperation(op, monitor);
+ }
+ /**
+ * @private - for use by <code>SetOutputLocationOperation</code> only.<br>
+ * Set the path to the location where the builder writes .class files
+ *
+ * @exception JavaModelException if an error occurs setting the output location
+ * or if this project is not present
+ */
+ protected void setOutputLocation0(IPath outputLocation) throws JavaModelException {
+ //getting the element info (if it is generated) has the side effect of setting the
+ //output location to that specified in the classpath file (or the default output location
+ //if none is specified in the classpath file).
+ JavaProjectElementInfo info= getJavaProjectElementInfo();
+ info.setOutputLocation(outputLocation);
+ }
+ /**
+ * Sets the underlying kernel project of this Java project,
+ * and fills in its parent and name.
+ * Called by IProject.getNature().
+ *
+ * @see IProjectNature#setProject
+ */
+ public void setProject(IProject project) {
+ fProject= project;
+ fParent= JavaModelManager.getJavaModel(project.getWorkspace());
+ fName= project.getName();
+ }
+ /**
+ * @see IJavaProject
+ */
+ public void setRawClasspath(IClasspathEntry[] entries, IProgressMonitor monitor) throws JavaModelException {
+ setRawClasspath(entries, monitor, true, getResolvedClasspath(true));
+ }
+ /**
+ * @see IJavaProject
+ */
+ public void setRawClasspath(IClasspathEntry[] entries, IProgressMonitor monitor, boolean saveClasspath) throws JavaModelException {
+ setRawClasspath(entries, monitor, saveClasspath, getResolvedClasspath(true));
+ }
+ /**
+ * @see IJavaProject
+ */
+ public void setRawClasspath(IClasspathEntry[] newEntries, IProgressMonitor monitor, boolean saveClasspath, IClasspathEntry[] oldResolvedPath) throws JavaModelException {
+ JavaModelManager manager= (JavaModelManager) JavaModelManager.getJavaModelManager();
+ try {
+ IJavaModelStatus status= verifyClasspath(newEntries);
+ if (!status.isOK()) {
+ throw new JavaModelException(status);
+ }
+ JavaProjectElementInfo info = getJavaProjectElementInfo();
+ IClasspathEntry[] newRawPath = newEntries;
+ if (newRawPath == null) { //are we already with the default classpath
+ newRawPath = defaultClasspath();
+ }
+ SetClasspathOperation op= new SetClasspathOperation(this, oldResolvedPath, newRawPath, saveClasspath);
+ runOperation(op, monitor);
+ } catch (JavaModelException e) {
+ manager.flush();
+ throw e;
+ }
+ }
+ /**
+ * NOTE: <code>null</code> specifies default classpath, and an empty
+ * array specifies an empty classpath.
+ *
+ * @exception NotPresentException if this project does not exist.
+ */
+ protected void setRawClasspath0(IClasspathEntry[] entries) throws JavaModelException {
+ JavaProjectElementInfo info= getJavaProjectElementInfo();
+
+ synchronized(info){
+ if (entries == null) {
+ entries= defaultClasspath();
+ }
+
+ // clear the existing children
+ info.setChildren(new IPackageFragmentRoot[] {});
+ info.setRawClasspath(entries);
+
+ IndexManager indexManager = ((JavaModelManager)JavaModelManager.getJavaModelManager()).getIndexManager();
+
+ // determine the new children
+ for (int i= 0; i < entries.length; i++) {
+ IClasspathEntry entry= entries[i];
+ IPackageFragmentRoot[] roots= getPackageFragmentRoots(entry);
+ for (int j= 0; j < roots.length; j++) {
+ PackageFragmentRoot root= (PackageFragmentRoot)roots[j];
+ if (root.exists0()){
+ if (root.isArchive()) {
+ IResource rsc= root.getUnderlyingResource();
+ if (rsc == null) {
+ if (indexManager != null) indexManager.indexJarFile(root, getUnderlyingResource().getName());
+ } else {
+ if (indexManager != null) indexManager.indexJarFile((IFile) rsc, getUnderlyingResource().getName());
+ }
+ }
+ info.addChild(roots[j]);
+ }
+ }
+ }
+ // flush namelookup (holds onto caches)
+ info.setNameLookup(null);
+ // See PR 1G8BFWS: ITPJUI:WINNT - internal jar appearing twice in packages view
+ resetNonJavaResourcesForPackageFragmentRoots();
+ ((JavaProjectElementInfo) getElementInfo()).setNonJavaResources(null);
+ }
+ }
+ /**
+ * Record a shared persistent property onto a project.
+ * Note that it is orthogonal to IResource persistent properties, and client code has to decide
+ * which form of storage to use appropriately. Shared properties produce real resource files which
+ * can be shared through a VCM onto a server. Persistent properties are not shareable.
+ *
+ * shared properties end up in resource files, and thus cannot be modified during
+ * delta notifications (a CoreException would then be thrown).
+ *
+ * @see JavaProject.getSharedProperty(...)
+ */
+ public void setSharedProperty(QualifiedName key, String value) throws CoreException {
+
+ IProject project = getProject();
+ String propertyName= computeSharedPropertyFileName(key);
+ IFile rscFile = getProject().getFile(propertyName);
+ InputStream input = new ByteArrayInputStream(value.getBytes());
+ // update the resource content
+ if (rscFile.exists()){
+ rscFile.setContents(input, true, false, null);
+ } else {
+ rscFile.create(input, true, null);
+ }
+ }
+ public void updateClassPath() throws JavaModelException {
+ setRawClasspath(getRawClasspath(), null, false);
+ }
+ /**
+ * Possible failures: <ul>
+ * <li>NAME_COLLISION - two entries specify the same path.
+ * <li>INVALID_PATH - a CPE_PROJECT entry has been specified referring to this project
+ * </ul>
+ */
+ protected IJavaModelStatus verifyClasspath(IClasspathEntry[] classpath) {
+ if (classpath != null) {
+ int entryCount= classpath.length;
+ for (int i= 0; i < entryCount; i++) {
+ IClasspathEntry entry= classpath[i];
+ inner : for (int j= 0; j < entryCount; j++) {
+ if (i == j) {
+ continue inner;
+ }
+ if (JavaConventions.isOverlappingRoots(entry.getPath(), classpath[j].getPath())) {
+ return new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION);
+ }
+ }
+ if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT && entry.getPath().equals(getProject().getFullPath())) {
+ return new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH);
+ }
+ }
+ }
+ return JavaModelStatus.VERIFIED_OK;
+ }
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProjectElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProjectElementInfo.java
new file mode 100644
index 0000000000..4f28e9bb79
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProjectElementInfo.java
@@ -0,0 +1,195 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+
+import org.eclipse.jdt.core.*;
+
+import java.util.*;
+
+/**
+ * Info for IJavaProject.
+ * <p>
+ * Note: <code>getChildren()</code> returns all of the <code>IPackageFragmentRoots</code>
+ * specified on the classpath for the project. This can include roots external to the
+ * project. See <code>JavaProject#getAllPackageFragmentRoots()</code> and
+ * <code>JavaProject#getPackageFragmentRoots()</code>. To get only the <code>IPackageFragmentRoots</code>
+ * that are internal to the project, use <code>JavaProject#getChildren()</code>.
+ */
+
+/* package */
+class JavaProjectElementInfo extends OpenableElementInfo {
+
+ /**
+ * The classpath for this project
+ */
+ protected IClasspathEntry[] fClasspath;
+
+ /**
+ * The name lookup facility to use with this project.
+ */
+ protected NameLookup fNameLookup = null;
+
+ /**
+ * The searchable builder environment facility used
+ * with this project (doubles as the builder environment).
+ */
+ protected SearchableEnvironment fSearchableEnvironment = null;
+
+ /**
+ * The output location for this project.
+ */
+ protected IPath fOutputLocation = null;
+
+ /**
+ * A array with all the non-java resources contained by this PackageFragment
+ */
+ private Object[] fNonJavaResources;
+
+ /**
+ * Create and initialize a new instance of the receiver
+ */
+ public JavaProjectElementInfo() {
+ fNonJavaResources = null;
+ }
+
+ /**
+ * Compute the non-java resources contained in this java project.
+ */
+ private Object[] computeNonJavaResources(JavaProject project) {
+ Object[] nonJavaResources = new IResource[5];
+ int nonJavaResourcesCounter = 0;
+ try {
+ IResource[] members = ((IContainer) project.getUnderlyingResource()).members();
+ for (int i = 0, max = members.length; i < max; i++) {
+ IResource res = members[i];
+ switch (res.getType()) {
+ case IResource.FILE :
+ String extension = res.getProjectRelativePath().getFileExtension();
+ if (!"java".equalsIgnoreCase(extension)
+ && !"class".equalsIgnoreCase(extension)) {
+ // check if this file might be a jar or a zip inside the build path
+ IPath resFullPath = res.getFullPath();
+ if (project.findPackageFragmentRoot(resFullPath) == null) {
+ if (nonJavaResources.length == nonJavaResourcesCounter) {
+ // resize
+ System.arraycopy(
+ nonJavaResources,
+ 0,
+ (nonJavaResources = new IResource[nonJavaResourcesCounter * 2]),
+ 0,
+ nonJavaResourcesCounter);
+ }
+ nonJavaResources[nonJavaResourcesCounter++] = res;
+ }
+ }
+ break;
+ case IResource.FOLDER :
+ IPath resFullPath = res.getFullPath();
+ if (!resFullPath.equals(project.getOutputLocation())
+ && project.findPackageFragmentRoot(resFullPath) == null
+ && project.findPackageFragment(resFullPath) == null) {
+ if (nonJavaResources.length == nonJavaResourcesCounter) {
+ // resize
+ System.arraycopy(
+ nonJavaResources,
+ 0,
+ (nonJavaResources = new IResource[nonJavaResourcesCounter * 2]),
+ 0,
+ nonJavaResourcesCounter);
+ }
+ nonJavaResources[nonJavaResourcesCounter++] = res;
+ }
+ }
+ }
+ if (nonJavaResources.length != nonJavaResourcesCounter) {
+ System.arraycopy(
+ nonJavaResources,
+ 0,
+ (nonJavaResources = new IResource[nonJavaResourcesCounter]),
+ 0,
+ nonJavaResourcesCounter);
+ }
+ } catch (CoreException e) {
+ nonJavaResources = NO_NON_JAVA_RESOURCES;
+ nonJavaResourcesCounter = 0;
+ }
+ return nonJavaResources;
+ }
+
+ /**
+ * @see IJavaProject
+ */
+ protected NameLookup getNameLookup() {
+ return fNameLookup;
+ }
+
+ /**
+ * Returns an array of non-java resources contained in the receiver.
+ */
+ Object[] getNonJavaResources(JavaProject project) {
+ Object[] nonJavaResources = fNonJavaResources;
+ if (nonJavaResources == null) {
+ nonJavaResources = computeNonJavaResources(project);
+ fNonJavaResources = nonJavaResources;
+ }
+ return nonJavaResources;
+ }
+
+ /**
+ * @see IJavaProject
+ */
+ protected IPath getOutputLocation() {
+ return fOutputLocation;
+ }
+
+ /**
+ * Returns the classpath for this project
+ */
+ protected IClasspathEntry[] getRawClasspath() {
+ return fClasspath;
+ }
+
+ /**
+ * @see IJavaProject
+ */
+ protected SearchableEnvironment getSearchableEnvironment() {
+ return fSearchableEnvironment;
+ }
+
+ protected void setNameLookup(NameLookup newNameLookup) {
+ fNameLookup = newNameLookup;
+
+ // Reinitialize the searchable name environment since it caches
+ // the name lookup.
+ fSearchableEnvironment = null;
+ }
+
+ /**
+ * Set the fNonJavaResources to res value
+ */
+ synchronized void setNonJavaResources(Object[] resources) {
+ fNonJavaResources = resources;
+ }
+
+ protected void setOutputLocation(IPath newOutputLocation) {
+ fOutputLocation = newOutputLocation;
+ }
+
+ /**
+ * Sets the classpath for this project
+ */
+ protected void setRawClasspath(IClasspathEntry[] newClasspath) {
+ fClasspath = newClasspath;
+ }
+
+ protected void setSearchableEnvironment(SearchableEnvironment newSearchableEnvironment) {
+ fSearchableEnvironment = newSearchableEnvironment;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LRUCacheEnumerator.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LRUCacheEnumerator.java
new file mode 100644
index 0000000000..7f1423543b
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LRUCacheEnumerator.java
@@ -0,0 +1,67 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.Enumeration;
+
+/**
+ * The <code>LRUCacheEnumerator</code> returns its elements in
+ * the order they are found in the <code>LRUCache</code>, with the
+ * most recent elements first.
+ *
+ * Once the enumerator is created, elements which are later added
+ * to the cache are not returned by the enumerator. However,
+ * elements returned from the enumerator could have been closed
+ * by the cache.
+ */
+public class LRUCacheEnumerator implements Enumeration {
+ /**
+ * Current element;
+ */
+ protected LRUEnumeratorElement fElementQueue;
+
+ public static class LRUEnumeratorElement {
+ /**
+ * Value returned by <code>nextElement()</code>;
+ */
+ public Object fValue;
+
+ /**
+ * Next element
+ */
+ public LRUEnumeratorElement fNext;
+
+ /**
+ * Constructor
+ */
+ public LRUEnumeratorElement(Object value) {
+ fValue = value;
+ }
+ }
+
+ /**
+ * Creates a CacheEnumerator on the list of <code>LRUEnumeratorElements</code>.
+ */
+ public LRUCacheEnumerator(LRUEnumeratorElement firstElement) {
+ fElementQueue = firstElement;
+ }
+
+ /**
+ * Returns true if more elements exist.
+ */
+ public boolean hasMoreElements() {
+ return fElementQueue != null;
+ }
+
+ /**
+ * Returns the next element.
+ */
+ public Object nextElement() {
+ Object temp = fElementQueue.fValue;
+ fElementQueue = fElementQueue.fNext;
+ return temp;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Member.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Member.java
new file mode 100644
index 0000000000..3211307f65
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Member.java
@@ -0,0 +1,183 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+
+/**
+ * @see IMember
+ */
+
+/* package */
+abstract class Member extends SourceRefElement implements IMember {
+ protected Member(int type, IJavaElement parent, String name) {
+ super(type, parent, name);
+ }
+
+ /**
+ * Converts a field constant from the compiler's representation
+ * to the Java Model constant representation (Number or String).
+ */
+ protected static Object convertConstant(Constant constant) {
+ if (constant == null)
+ return null;
+ if (constant == Constant.NotAConstant) {
+ return null;
+ }
+ switch (constant.typeID()) {
+ case TypeIds.T_boolean :
+ return constant.booleanValue() ? Boolean.TRUE : Boolean.FALSE;
+ case TypeIds.T_byte :
+ return new Byte(constant.byteValue());
+ case TypeIds.T_char :
+ return new Character(constant.charValue());
+ case TypeIds.T_double :
+ return new Double(constant.doubleValue());
+ case TypeIds.T_float :
+ return new Float(constant.floatValue());
+ case TypeIds.T_int :
+ return new Integer(constant.intValue());
+ case TypeIds.T_long :
+ return new Long(constant.longValue());
+ case TypeIds.T_null :
+ return null;
+ case TypeIds.T_short :
+ return new Short(constant.shortValue());
+ case TypeIds.T_String :
+ return constant.stringValue();
+ default :
+ return null;
+ }
+ }
+
+ /**
+ * @see JavaElement#equalsDOMNode
+ */
+ protected boolean equalsDOMNode(IDOMNode node) throws JavaModelException {
+ return getElementName().equals(node.getName());
+ }
+
+ /**
+ * @see IMember
+ */
+ public IClassFile getClassFile() {
+ return ((JavaElement) getParent()).getClassFile();
+ }
+
+ /**
+ * @see IMember
+ */
+ public IType getDeclaringType() {
+ JavaElement parent = (JavaElement) getParent();
+ if (parent.fLEType == TYPE) {
+ return (IType) parent;
+ }
+ return null;
+ }
+
+ /**
+ * @see IMember
+ */
+ public int getFlags() throws JavaModelException {
+ MemberElementInfo info = (MemberElementInfo) getElementInfo();
+ return info.getModifiers();
+ }
+
+ /**
+ * @see JavaElement#getHandleMemento()
+ */
+ protected char getHandleMementoDelimiter() {
+ return JavaElement.JEM_TYPE;
+ }
+
+ /**
+ * @see IMember
+ */
+ public ISourceRange getNameRange() throws JavaModelException {
+ MemberElementInfo info = (MemberElementInfo) getRawInfo();
+ return new SourceRange(
+ info.getNameSourceStart(),
+ info.getNameSourceEnd() - info.getNameSourceStart() + 1);
+ }
+
+ /**
+ * @see IMember
+ */
+ public boolean isBinary() {
+ return false;
+ }
+
+ /**
+ * @see IJavaElement
+ */
+ public boolean isReadOnly() {
+ return getClassFile() != null;
+ }
+
+ /**
+ * Changes the source indexes of this element. Updates the name range as well.
+ */
+ public void offsetSourceRange(int amount) {
+ super.offsetSourceRange(amount);
+ try {
+ MemberElementInfo info = (MemberElementInfo) getRawInfo();
+ info.setNameSourceStart(info.getNameSourceStart() + amount);
+ info.setNameSourceEnd(info.getNameSourceEnd() + amount);
+ } catch (JavaModelException npe) {
+ return;
+ }
+ }
+
+ /**
+ */
+ public String readableName() {
+
+ IJavaElement declaringType = getDeclaringType();
+ if (declaringType != null) {
+ String declaringName = ((JavaElement) getDeclaringType()).readableName();
+ StringBuffer buffer = new StringBuffer(declaringName);
+ buffer.append('.');
+ buffer.append(this.getElementName());
+ return buffer.toString();
+ } else {
+ return super.readableName();
+ }
+ }
+
+ /**
+ * Updates the source positions for this element.
+ */
+ public void triggerSourceEndOffset(int amount, int nameStart, int nameEnd) {
+ super.triggerSourceEndOffset(amount, nameStart, nameEnd);
+ updateNameRange(nameStart, nameEnd);
+ }
+
+ /**
+ * Updates the source positions for this element.
+ */
+ public void triggerSourceRangeOffset(int amount, int nameStart, int nameEnd) {
+ super.triggerSourceRangeOffset(amount, nameStart, nameEnd);
+ updateNameRange(nameStart, nameEnd);
+ }
+
+ /**
+ * Updates the name range for this element.
+ */
+ protected void updateNameRange(int nameStart, int nameEnd) {
+ try {
+ MemberElementInfo info = (MemberElementInfo) getRawInfo();
+ info.setNameSourceStart(nameStart);
+ info.setNameSourceEnd(nameEnd);
+ } catch (JavaModelException npe) {
+ return;
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MemberElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MemberElementInfo.java
new file mode 100644
index 0000000000..511f8fa6f9
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MemberElementInfo.java
@@ -0,0 +1,99 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+/**
+ *Element info for IMember elements.
+ */
+/* package */
+abstract class MemberElementInfo extends SourceRefElementInfo {
+ /**
+ * The modifiers associated with this member.
+ *
+ * @see IConstants
+ */
+ protected int flags;
+
+ /**
+ * The start position of this member's name in the its
+ * openable's buffer.
+ */
+ protected int nameStart = -1;
+
+ /**
+ * The last position of this member's name in the its
+ * openable's buffer.
+ */
+ protected int nameEnd = -1;
+
+ /**
+ * This member's name
+ */
+ protected char[] name;
+ /**
+ * @see IGenericType
+ * @see IGenericMethod
+ * @see IGenericField
+ */
+ public int getModifiers() {
+ return this.flags;
+ }
+
+ /**
+ * @see ISourceType
+ * @see ISourceField
+ */
+ public char[] getName() {
+ return this.name;
+ }
+
+ /**
+ * @see ISourceType
+ * @see ISourceMethod
+ * @see ISourceField
+ */
+ public int getNameSourceEnd() {
+ return this.nameEnd;
+ }
+
+ /**
+ * @see ISourceType
+ * @see ISourceMethod
+ * @see ISourceField
+ */
+ public int getNameSourceStart() {
+ return this.nameStart;
+ }
+
+ protected void setFlags(int flags) {
+ this.flags = flags;
+ }
+
+ /**
+ * Sets this member's name
+ */
+ protected void setName(char[] name) {
+ this.name = name;
+ }
+
+ /**
+ * Sets the last position of this member's name, relative
+ * to its openable's source buffer.
+ */
+ protected void setNameSourceEnd(int end) {
+ this.nameEnd = end;
+ }
+
+ /**
+ * Sets the start position of this member's name, relative
+ * to its openable's source buffer.
+ */
+ protected void setNameSourceStart(int start) {
+ this.nameStart = start;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MoveElementsOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MoveElementsOperation.java
new file mode 100644
index 0000000000..3acf61d4b1
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MoveElementsOperation.java
@@ -0,0 +1,45 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.core.IJavaElement;
+
+/**
+ * This operation moves elements from their current
+ * container to a specified destination container, optionally renaming the
+ * elements.
+ * A move operation is equivalent to a copy operation, where
+ * the source elements are deleted after the copy.
+ * <p>This operation can be used for reorganizing elements within the same container.
+ *
+ * @see CopyElementsOperation
+ */
+public class MoveElementsOperation extends CopyElementsOperation {
+ /**
+ * When executed, this operation will move the given elements to the given containers.
+ */
+ public MoveElementsOperation(
+ IJavaElement[] elementsToMove,
+ IJavaElement[] destContainers,
+ boolean force) {
+ super(elementsToMove, destContainers, force);
+ }
+
+ /**
+ * Returns the <code>String</code> to use as the main task name
+ * for progress monitoring.
+ */
+ protected String getMainTaskName() {
+ return "Moving elements...";
+ }
+
+ /**
+ * @see CopyElementsOperation#isMove()
+ */
+ protected boolean isMove() {
+ return true;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MoveResourceElementsOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MoveResourceElementsOperation.java
new file mode 100644
index 0000000000..91e798e569
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MoveResourceElementsOperation.java
@@ -0,0 +1,45 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.core.IJavaElement;
+
+/**
+ * This operation moves resources (package fragments and compilation units) from their current
+ * container to a specified destination container, optionally renaming the
+ * elements.
+ * A move resource operation is equivalent to a copy resource operation, where
+ * the source resources are deleted after the copy.
+ * <p>This operation can be used for reorganizing resources within the same container.
+ *
+ * @see CopyResourceElementsOperation
+ */
+public class MoveResourceElementsOperation
+ extends CopyResourceElementsOperation {
+ /**
+ * When executed, this operation will move the given elements to the given containers.
+ */
+ public MoveResourceElementsOperation(
+ IJavaElement[] elementsToMove,
+ IJavaElement[] destContainers,
+ boolean force) {
+ super(elementsToMove, destContainers, force);
+ }
+
+ /**
+ * @see MultiOperation
+ */
+ protected String getMainTaskName() {
+ return "Moving resources...";
+ }
+
+ /**
+ * @see CopyResourceElementsOperation#isMove()
+ */
+ protected boolean isMove() {
+ return true;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MultiOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MultiOperation.java
new file mode 100644
index 0000000000..26f85ee971
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MultiOperation.java
@@ -0,0 +1,367 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.resources.*;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.eclipse.jdt.core.*;
+
+/**
+ * This class is used to perform operations on multiple <code>IJavaElement</code>.
+ * It is responible for running each operation in turn, collecting
+ * the errors and merging the corresponding <code>JavaElementDelta</code>s.
+ * <p>
+ * If several errors occured, they are collected in a multi-status
+ * <code>JavaModelStatus</code>. Otherwise, a simple <code>JavaModelStatus</code>
+ * is thrown.
+ */
+public abstract class MultiOperation extends JavaModelOperation {
+ /**
+ * The list of renamings supplied to the operation
+ */
+ protected String[] fRenamingsList = null;
+ /**
+ * Table specifying the new parent for elements being
+ * copied/moved/renamed.
+ * Keyed by elements being processed, and
+ * values are the corresponding destination parent.
+ */
+ protected Hashtable fParentElements;
+ /**
+ * Table specifying insertion positions for elements being
+ * copied/moved/renamed. Keyed by elements being processed, and
+ * values are the corresponding insertion point.
+ * @see processElements(IProgressMonitor)
+ */
+ protected Hashtable fInsertBeforeElements = new Hashtable(1);
+ /**
+ * This table presents the data in <code>fRenamingList</code> in a more
+ * convenient way.
+ */
+ protected Hashtable fRenamings;
+ /**
+ * Creates a new <code>MultiOperation</code>.
+ */
+ protected MultiOperation(
+ IJavaElement[] elementsToProcess,
+ IJavaElement[] parentElements,
+ boolean force) {
+ super(elementsToProcess, parentElements, force);
+ fParentElements = new Hashtable(elementsToProcess.length);
+ if (elementsToProcess.length == parentElements.length) {
+ for (int i = 0; i < elementsToProcess.length; i++) {
+ fParentElements.put(elementsToProcess[i], parentElements[i]);
+ }
+ } else { //same destination for all elements to be moved/copied/renamed
+ for (int i = 0; i < elementsToProcess.length; i++) {
+ fParentElements.put(elementsToProcess[i], parentElements[0]);
+ }
+ }
+
+ }
+
+ /**
+ * Creates a new <code>MultiOperation</code> on <code>elementsToProcess</code>.
+ */
+ protected MultiOperation(IJavaElement[] elementsToProcess, boolean force) {
+ super(elementsToProcess, force);
+ }
+
+ /**
+ * Convenience method to create a <code>JavaModelException</code>
+ * embending a <code>JavaModelStatus</code>.
+ */
+ protected void error(int code, IJavaElement element)
+ throws JavaModelException {
+ throw new JavaModelException(new JavaModelStatus(code, element));
+ }
+
+ /**
+ * Executes the operation.
+ *
+ * @exception JavaModelException if one or several errors occured during the operation.
+ * If multiple errors occured, the corresponding <code>JavaModelStatus</code> is a
+ * multi-status. Otherwise, it is a simple one.
+ */
+ protected void executeOperation() throws JavaModelException {
+ try {
+ processElements();
+ } catch (JavaModelException jme) {
+ throw jme;
+ } finally {
+ mergeDeltas();
+ }
+ }
+
+ /**
+ * Returns the parent of the element being copied/moved/renamed.
+ */
+ protected IJavaElement getDestinationParent(IJavaElement child) {
+ return (IJavaElement) fParentElements.get(child);
+ }
+
+ /**
+ * Returns the name to be used by the progress monitor.
+ */
+ protected abstract String getMainTaskName();
+ /**
+ * Returns the new name for <code>element</code>, or <code>null</code>
+ * if there are no renamings specified.
+ */
+ protected String getNewNameFor(IJavaElement element) {
+ if (fRenamings != null)
+ return (String) fRenamings.get(element);
+ else
+ return null;
+ }
+
+ /**
+ * Sets up the renamings hashtable - keys are the elements and
+ * values are the new name.
+ */
+ private void initializeRenamings() {
+ if (fRenamingsList != null
+ && fRenamingsList.length == fElementsToProcess.length) {
+ fRenamings = new Hashtable(fRenamingsList.length);
+ for (int i = 0; i < fRenamingsList.length; i++) {
+ if (fRenamingsList[i] != null) {
+ fRenamings.put(fElementsToProcess[i], fRenamingsList[i]);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns <code>true</code> if this operation represents a move or rename, <code>false</code>
+ * if this operation represents a copy.<br>
+ * Note: a rename is just a move within the same parent with a name change.
+ */
+ protected boolean isMove() {
+ return false;
+ }
+
+ /**
+ * Returns <code>true</code> if this operation represents a rename, <code>false</code>
+ * if this operation represents a copy or move.
+ */
+ protected boolean isRename() {
+ return false;
+ }
+
+ /**
+ * Process all of the changed deltas generated by these operations.
+ */
+ protected void mergeDeltas() {
+ if (fDeltas != null) {
+ JavaElementDelta rootDelta = newJavaElementDelta();
+ boolean insertedTree = false;
+ for (int i = 0; i < fDeltas.length; i++) {
+ IJavaElementDelta delta = fDeltas[i];
+ IJavaElementDelta[] children = delta.getAffectedChildren();
+ for (int j = 0; j < children.length; j++) {
+ JavaElementDelta projectDelta = (JavaElementDelta) children[j];
+ rootDelta.insertDeltaTree(projectDelta.getElement(), projectDelta);
+ insertedTree = true;
+ }
+ }
+ if (insertedTree)
+ fDeltas = new IJavaElementDelta[] { rootDelta };
+ else
+ fDeltas = null;
+ }
+ }
+
+ /**
+ * Subclasses must implement this method to process a given <code>IJavaElement</code>.
+ */
+ protected abstract void processElement(IJavaElement element)
+ throws JavaModelException;
+ /**
+ * Processes all the <code>IJavaElement</code>s in turn, collecting errors
+ * and updating the progress monitor.
+ *
+ * @exception JavaModelException if one or several operation(s) was unable to
+ * be completed.
+ */
+ protected void processElements() throws JavaModelException {
+ beginTask(getMainTaskName(), fElementsToProcess.length);
+ IJavaModelStatus[] errors = new IJavaModelStatus[3];
+ int errorsCounter = 0;
+ for (int i = 0; i < fElementsToProcess.length; i++) {
+ try {
+ verify(fElementsToProcess[i]);
+ processElement(fElementsToProcess[i]);
+ } catch (JavaModelException jme) {
+ if (errorsCounter == errors.length) {
+ // resize
+ System.arraycopy(
+ errors,
+ 0,
+ (errors = new IJavaModelStatus[errorsCounter * 2]),
+ 0,
+ errorsCounter);
+ }
+ errors[errorsCounter++] = jme.getJavaModelStatus();
+ } finally {
+ worked(1);
+ }
+ }
+ done();
+ if (errorsCounter == 1) {
+ throw new JavaModelException(errors[0]);
+ } else
+ if (errorsCounter > 1) {
+ if (errorsCounter != errors.length) {
+ // resize
+ System.arraycopy(
+ errors,
+ 0,
+ (errors = new IJavaModelStatus[errorsCounter]),
+ 0,
+ errorsCounter);
+ }
+ throw new JavaModelException(JavaModelStatus.newMultiStatus(errors));
+ }
+ }
+
+ /**
+ * Sets the insertion position in the new container for the modified element. The element
+ * being modified will be inserted before the specified new sibling. The given sibling
+ * must be a child of the destination container specified for the modified element.
+ * The default is <code>null</code>, which indicates that the element is to be
+ * inserted at the end of the container.
+ */
+ public void setInsertBefore(
+ IJavaElement modifiedElement,
+ IJavaElement newSibling) {
+ fInsertBeforeElements.put(modifiedElement, newSibling);
+ }
+
+ /**
+ * Sets the new names to use for each element being copied. The renamings
+ * correspond to the elements being processed, and the number of
+ * renamings must match the number of elements being processed.
+ * A <code>null</code> entry in the list indicates that an element
+ * is not to be renamed.
+ *
+ * <p>Note that some renamings may not be used. If both a parent
+ * and a child have been selected for copy/move, only the parent
+ * is changed. Therefore, if a new name is specified for the child,
+ * the child's name will not be changed.
+ */
+ public void setRenamings(String[] renamings) {
+ fRenamingsList = renamings;
+ initializeRenamings();
+ }
+
+ /**
+ * This method is called for each <code>IJavaElement</code> before
+ * <code>processElement</code>. It should check that this <code>element</code>
+ * can be processed.
+ */
+ protected abstract void verify(IJavaElement element) throws JavaModelException;
+ /**
+ * Verifies that the <code>destination</code> specified for the <code>element</code> is valid for the types of the
+ * <code>element</code> and <code>destination</code>.
+ */
+ protected void verifyDestination(
+ IJavaElement element,
+ IJavaElement destination)
+ throws JavaModelException {
+ if (destination == null || !destination.exists())
+ error(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, destination);
+
+ int destType = destination.getElementType();
+ switch (element.getElementType()) {
+ case IJavaElement.PACKAGE_DECLARATION :
+ case IJavaElement.IMPORT_DECLARATION :
+ if (destType != IJavaElement.COMPILATION_UNIT)
+ error(IJavaModelStatusConstants.INVALID_DESTINATION, element);
+ break;
+ case IJavaElement.TYPE :
+ if (destType != IJavaElement.COMPILATION_UNIT && destType != IJavaElement.TYPE)
+ error(IJavaModelStatusConstants.INVALID_DESTINATION, element);
+ break;
+ case IJavaElement.METHOD :
+ case IJavaElement.FIELD :
+ case IJavaElement.INITIALIZER :
+ if (destType != IJavaElement.TYPE || destination instanceof BinaryType)
+ error(IJavaModelStatusConstants.INVALID_DESTINATION, element);
+ break;
+ case IJavaElement.COMPILATION_UNIT :
+ if (destType != IJavaElement.PACKAGE_FRAGMENT)
+ error(IJavaModelStatusConstants.INVALID_DESTINATION, element);
+ else
+ if (isMove() && ((ICompilationUnit) element).isWorkingCopy())
+ error(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element);
+ break;
+ case IJavaElement.PACKAGE_FRAGMENT :
+ IPackageFragment fragment = (IPackageFragment) element;
+ IJavaElement parent = fragment.getParent();
+ if (parent.isReadOnly())
+ error(IJavaModelStatusConstants.READ_ONLY, element);
+ else
+ if (destType != IJavaElement.PACKAGE_FRAGMENT_ROOT)
+ error(IJavaModelStatusConstants.INVALID_DESTINATION, element);
+ break;
+ default :
+ error(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element);
+ }
+ }
+
+ /**
+ * Verify that the new name specified for <code>element</code> is
+ * valid for that type of Java element.
+ */
+ protected void verifyRenaming(IJavaElement element) throws JavaModelException {
+ String newName = getNewNameFor(element);
+ boolean isValid = true;
+
+ switch (element.getElementType()) {
+ case IJavaElement.PACKAGE_FRAGMENT :
+ if (element.getElementName().equals(IPackageFragment.DEFAULT_PACKAGE_NAME)) {
+ // don't allow renaming of default package (see PR #1G47GUM)
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION, element));
+ }
+ isValid = JavaConventions.validatePackageName(newName).isOK();
+ break;
+ case IJavaElement.COMPILATION_UNIT :
+ isValid = JavaConventions.validateCompilationUnitName(newName).isOK();
+ break;
+ case IJavaElement.INITIALIZER :
+ isValid = false; //cannot rename initializers
+ break;
+ default :
+ isValid = JavaConventions.validateIdentifier(newName).isOK();
+ break;
+ }
+
+ if (!isValid) {
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.INVALID_NAME, element, newName));
+ }
+ }
+
+ /**
+ * Verifies that the positioning sibling specified for the <code>element</code> is exists and
+ * its parent is the destination container of this <code>element</code>.
+ */
+ protected void verifySibling(IJavaElement element, IJavaElement destination)
+ throws JavaModelException {
+ IJavaElement insertBeforeElement =
+ (IJavaElement) fInsertBeforeElements.get(element);
+ if (insertBeforeElement != null) {
+ if (!insertBeforeElement.exists()
+ || !insertBeforeElement.getParent().equals(destination)) {
+ error(IJavaModelStatusConstants.INVALID_SIBLING, insertBeforeElement);
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NameLookup.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NameLookup.java
new file mode 100644
index 0000000000..983c71333f
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NameLookup.java
@@ -0,0 +1,653 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.core.resources.*;
+import java.util.Vector;
+import java.util.Hashtable;
+import java.io.File;
+
+import org.eclipse.jdt.core.*;
+
+/**
+ * This class implements basic namelookup functionality as
+ * described in <code>INameLookup</code>. It performs its
+ * searches by querying the Java Model directly.
+ *
+ * @see INameLookup
+ */
+
+public class NameLookup implements INameLookup {
+ /**
+ * The <code>IPackageFragmentRoot</code>'s associated
+ * with the classpath of this NameLookup facility's
+ * project.
+ */
+ protected IPackageFragmentRoot[] fPackageFragmentRoots = null;
+ /**
+ * Table that maps package names to lists of package fragments for
+ * all package fragments in the package fragment roots known
+ * by this name lookup facility. To allow > 1 package fragment
+ * with the same name, values are arrays of package fragments
+ * ordered as they appear on the classpath.
+ */
+ protected Hashtable fPackageFragments;
+
+ /**
+ * Singleton <code>SingleTypeRequestor</code>.
+ * @see findType(String, IPackageFragment, boolean, int)
+ */
+ protected SingleTypeRequestor fgSingleTypeRequestor = new SingleTypeRequestor();
+ /**
+ * Singleton <code>JavaElementRequestor</code>.
+ * @see findType(String, boolean, int)
+ */
+ protected JavaElementRequestor fgJavaElementRequestor =
+ new JavaElementRequestor();
+ /**
+ * The <code>IWorkspace</code> that this NameLookup
+ * is configure within.
+ */
+ protected IWorkspace workspace;
+
+ public NameLookup(IJavaProject project) throws JavaModelException {
+ configureFromProject(project);
+ }
+
+ /**
+ * Returns true if:<ul>
+ * <li>the given type is an existing class and the flag's <code>ACCEPT_CLASSES</code>
+ * bit is on
+ * <li>the given type is an existing interface and the <code>ACCEPT_INTERFACES</code>
+ * bit is on
+ * <li>neither the <code>ACCEPT_CLASSES</code> or <code>ACCEPT_INTERFACES</code>
+ * bit is on
+ * </ul>
+ * Otherwise, false is returned.
+ */
+ protected boolean acceptType(IType type, int acceptFlags) {
+ if (acceptFlags == 0)
+ return true; // no flags, always accepted
+ try {
+ if (type.isClass()) {
+ return (acceptFlags & ACCEPT_CLASSES) != 0;
+ } else {
+ return (acceptFlags & ACCEPT_INTERFACES) != 0;
+ }
+ } catch (JavaModelException npe) {
+ return false; // the class is not present, do not accept.
+ }
+ }
+
+ /**
+ * Configures this <code>NameLookup</code> based on the
+ * info of the given <code>IJavaProject</code>.
+ *
+ * @throws JavaModelException if the <code>IJavaProject</code> has no classpath.
+ */
+ private void configureFromProject(IJavaProject project)
+ throws JavaModelException {
+ workspace = project.getJavaModel().getWorkspace();
+ fPackageFragmentRoots = ((JavaProject) project).getAllPackageFragmentRoots();
+ fPackageFragments = new Hashtable();
+ IPackageFragment[] frags = ((JavaProject) project).getAllPackageFragments();
+ for (int i = 0; i < frags.length; i++) {
+ IPackageFragment fragment = frags[i];
+ IPackageFragment[] entry =
+ (IPackageFragment[]) fPackageFragments.get(fragment.getElementName());
+ if (entry == null) {
+ entry = new IPackageFragment[1];
+ entry[0] = fragment;
+ fPackageFragments.put(fragment.getElementName(), entry);
+ } else {
+ IPackageFragment[] copy = new IPackageFragment[entry.length + 1];
+ System.arraycopy(entry, 0, copy, 0, entry.length);
+ copy[entry.length] = fragment;
+ fPackageFragments.put(fragment.getElementName(), copy);
+ }
+ }
+ }
+
+ /**
+ * Finds every type in the project whose simple name matches
+ * the prefix, informing the requestor of each hit. The requestor
+ * is polled for cancellation at regular intervals.
+ *
+ * <p>The <code>partialMatch</code> argument indicates partial matches
+ * should be considered.
+ */
+ private void findAllTypes(
+ String prefix,
+ boolean partialMatch,
+ int acceptFlags,
+ IJavaElementRequestor requestor) {
+ int count = fPackageFragmentRoots.length;
+ for (int i = 0; i < count; i++) {
+ if (requestor.isCanceled())
+ return;
+ IPackageFragmentRoot root = fPackageFragmentRoots[i];
+ IJavaElement[] packages = null;
+ try {
+ packages = root.getChildren();
+ } catch (JavaModelException npe) {
+ continue; // the root is not present, continue;
+ }
+ if (packages != null) {
+ for (int j = 0, packageCount = packages.length; j < packageCount; j++) {
+ if (requestor.isCanceled())
+ return;
+ seekTypes(
+ prefix,
+ (IPackageFragment) packages[j],
+ partialMatch,
+ acceptFlags,
+ requestor);
+ }
+ }
+ }
+ }
+
+ /**
+ * @see INameLookup
+ */
+ public ICompilationUnit findCompilationUnit(String qualifiedTypeName) {
+ String pkgName = IPackageFragment.DEFAULT_PACKAGE_NAME;
+ String cuName = qualifiedTypeName;
+
+ int index = qualifiedTypeName.lastIndexOf('.');
+ if (index != -1) {
+ pkgName = qualifiedTypeName.substring(0, index);
+ cuName = qualifiedTypeName.substring(index + 1);
+ }
+
+ index = cuName.indexOf('$');
+ if (index != -1) {
+ cuName = cuName.substring(0, index);
+ }
+ cuName += ".java";
+
+ IPackageFragment[] frags = (IPackageFragment[]) fPackageFragments.get(pkgName);
+ if (frags != null) {
+ for (int i = 0; i < frags.length; i++) {
+ IPackageFragment frag = frags[i];
+ if (!(frag instanceof JarPackageFragment)) {
+ ICompilationUnit cu = frag.getCompilationUnit(cuName);
+ if (cu != null && cu.exists()) {
+ return cu;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @see INameLookup
+ */
+ public IPackageFragment findPackageFragment(IPath path) {
+ if (!path.isAbsolute()) {
+ throw new IllegalArgumentException("Path must be absolute");
+ }
+ IResource possibleFragment = workspace.getRoot().findMember(path);
+ if (possibleFragment == null) {
+ //external jar
+ for (int i = 0; i < fPackageFragmentRoots.length; i++) {
+ IPackageFragmentRoot root = fPackageFragmentRoots[i];
+ if (!root.isExternal()) {
+ continue;
+ }
+ IPath rootPath = root.getPath();
+ int matchingCount = rootPath.matchingFirstSegments(path);
+ if (matchingCount != 0) {
+ String name = path.toOSString();
+ // + 1 is for the File.separatorChar
+ name = name.substring(rootPath.toOSString().length() + 1, name.length());
+ name = name.replace(File.separatorChar, '.');
+ IJavaElement[] list = null;
+ try {
+ list = root.getChildren();
+ } catch (JavaModelException npe) {
+ continue; // the package fragment root is not present;
+ }
+ int elementCount = list.length;
+ for (int j = 0; j < elementCount; j++) {
+ IPackageFragment packageFragment = (IPackageFragment) list[j];
+ if (nameMatches(name, packageFragment, false)) {
+ if (packageFragment.exists())
+ return packageFragment;
+ }
+ }
+ }
+ }
+ } else {
+ IJavaElement fromFactory = JavaCore.create(possibleFragment);
+ if (fromFactory == null) {
+ return null;
+ }
+ if (fromFactory instanceof IPackageFragment) {
+ return (IPackageFragment) fromFactory;
+ } else
+ if (fromFactory instanceof IJavaProject) {
+ // default package in a default root
+ JavaProject project = (JavaProject) fromFactory;
+ try {
+ IClasspathEntry entry = project.getClasspathEntryFor(path);
+ if (entry != null) {
+ IPackageFragmentRoot root =
+ project.getPackageFragmentRoot(project.getUnderlyingResource());
+ IPackageFragment[] pkgs =
+ (IPackageFragment[]) fPackageFragments.get(
+ IPackageFragment.DEFAULT_PACKAGE_NAME);
+ if (pkgs == null) {
+ return null;
+ }
+ for (int i = 0; i < pkgs.length; i++) {
+ if (pkgs[i].getParent().equals(root)) {
+ return pkgs[i];
+ }
+ }
+ }
+ } catch (JavaModelException e) {
+ return null;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @see INameLookup
+ */
+ public IPackageFragmentRoot findPackageFragmentRoot(IPath path) {
+ if (!path.isAbsolute()) {
+ throw new IllegalArgumentException("Path must be absolute");
+ }
+ for (int i = 0; i < fPackageFragmentRoots.length; i++) {
+ IPackageFragmentRoot classpathRoot = fPackageFragmentRoots[i];
+ if (classpathRoot.getPath().equals(path)) {
+ return classpathRoot;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @see INameLookup
+ */
+ public IPackageFragment[] findPackageFragments(
+ String name,
+ boolean partialMatch) {
+ int count = fPackageFragmentRoots.length;
+ if (partialMatch) {
+ name = name.toLowerCase();
+ for (int i = 0; i < count; i++) {
+ IPackageFragmentRoot root = fPackageFragmentRoots[i];
+ IJavaElement[] list = null;
+ try {
+ list = root.getChildren();
+ } catch (JavaModelException npe) {
+ continue; // the package fragment root is not present;
+ }
+ int elementCount = list.length;
+ IPackageFragment[] result = new IPackageFragment[elementCount];
+ int resultLength = 0;
+ for (int j = 0; j < elementCount; j++) {
+ IPackageFragment packageFragment = (IPackageFragment) list[j];
+ if (nameMatches(name, packageFragment, true)) {
+ if (packageFragment.exists())
+ result[resultLength++] = packageFragment;
+ }
+ }
+ if (resultLength > 0) {
+ System.arraycopy(
+ result,
+ 0,
+ result = new IPackageFragment[resultLength],
+ 0,
+ resultLength);
+ return result;
+ } else {
+ return null;
+ }
+ }
+ } else {
+ // Return only fragments that exists
+ IPackageFragment[] fragments = (IPackageFragment[]) fPackageFragments.get(name);
+ if (fragments != null) {
+ IPackageFragment[] result = new IPackageFragment[fragments.length];
+ int resultLength = 0;
+ for (int i = 0; i < fragments.length; i++) {
+ IPackageFragment packageFragment = fragments[i];
+ if (packageFragment.exists())
+ result[resultLength++] = packageFragment;
+ }
+ if (resultLength > 0) {
+ System.arraycopy(
+ result,
+ 0,
+ result = new IPackageFragment[resultLength],
+ 0,
+ resultLength);
+ return result;
+ } else {
+ return null;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ *
+ */
+ public IType findType(
+ String typeName,
+ String packageName,
+ boolean partialMatch,
+ int acceptFlags) {
+ if (packageName == null) {
+ packageName = IPackageFragment.DEFAULT_PACKAGE_NAME;
+ }
+
+ seekPackageFragments(packageName, false, fgJavaElementRequestor);
+ IPackageFragment[] packages = fgJavaElementRequestor.getPackageFragments();
+ fgJavaElementRequestor.reset();
+ for (int i = 0, length = packages.length; i < length; i++) {
+ IType type = findType(typeName, packages[i], partialMatch, acceptFlags);
+ if (type != null)
+ return type;
+ }
+ return null;
+ }
+
+ /**
+ * @see INameLookup
+ */
+ public IType findType(
+ String name,
+ IPackageFragment pkg,
+ boolean partialMatch,
+ int acceptFlags) {
+ if (pkg == null) {
+ return null;
+ }
+ // Return first found (ignore duplicates).
+ seekTypes(name, pkg, partialMatch, acceptFlags, fgSingleTypeRequestor);
+ IType type = fgSingleTypeRequestor.getType();
+ fgSingleTypeRequestor.reset();
+ return type;
+ }
+
+ /**
+ * @see INameLookup
+ */
+ public IType findType(String name, boolean partialMatch, int acceptFlags) {
+ int index = name.lastIndexOf('.');
+ String className = null, packageName = null;
+ if (index == -1) {
+ packageName = IPackageFragment.DEFAULT_PACKAGE_NAME;
+ className = name;
+ } else {
+ packageName = name.substring(0, index);
+ className = name.substring(index + 1);
+ }
+
+ return findType(className, packageName, partialMatch, acceptFlags);
+ }
+
+ /**
+ * Returns true if the given element's name matches the
+ * specified <code>searchName</code>, otherwise false.
+ *
+ * <p>The <code>partialMatch</code> argument indicates partial matches
+ * should be considered.
+ * NOTE: in partialMatch mode, the case will be ignored, and the searchName must already have
+ * been lowercased.
+ */
+ protected boolean nameMatches(
+ String searchName,
+ IJavaElement element,
+ boolean partialMatch) {
+ if (partialMatch) {
+ // partial matches are used in completion mode, thus case insensitive mode
+ return element.getElementName().toLowerCase().startsWith(searchName);
+ } else {
+ return element.getElementName().equals(searchName);
+ }
+ }
+
+ /**
+ * @see INameLookup
+ */
+ public void seekPackageFragments(
+ String name,
+ boolean partialMatch,
+ IJavaElementRequestor requestor) {
+ int count = fPackageFragmentRoots.length;
+ String matchName = partialMatch ? name.toLowerCase() : name;
+ for (int i = 0; i < count; i++) {
+ if (requestor.isCanceled())
+ return;
+ IPackageFragmentRoot root = fPackageFragmentRoots[i];
+ IJavaElement[] list = null;
+ try {
+ list = root.getChildren();
+ } catch (JavaModelException npe) {
+ continue; // this root package fragment is not present
+ }
+ int elementCount = list.length;
+ for (int j = 0; j < elementCount; j++) {
+ if (requestor.isCanceled())
+ return;
+ IPackageFragment packageFragment = (IPackageFragment) list[j];
+ if (nameMatches(matchName, packageFragment, partialMatch))
+ requestor.acceptPackageFragment(packageFragment);
+ }
+ }
+ }
+
+ /**
+ * Notifies the given requestor of all types (classes and interfaces) in the
+ * given type with the given (possibly qualified) name. Checks
+ * the requestor at regular intervals to see if the requestor
+ * has canceled.
+ *
+ * @param partialMatch partial name matches qualify when <code>true</code>,
+ * only exact name matches qualify when <code>false</code>
+ */
+ protected void seekQualifiedMemberTypes(
+ String qualifiedName,
+ IType type,
+ boolean partialMatch,
+ IJavaElementRequestor requestor) {
+ if (type == null)
+ return;
+ IType[] types = null;
+ try {
+ types = type.getTypes();
+ } catch (JavaModelException npe) {
+ return; // the enclosing type is not present
+ }
+ String matchName = qualifiedName;
+ int index = qualifiedName.indexOf('$');
+ boolean nested = false;
+ if (index != -1) {
+ matchName = qualifiedName.substring(0, index);
+ nested = true;
+ }
+ int length = types.length;
+ for (int i = 0; i < length; i++) {
+ if (requestor.isCanceled())
+ return;
+ IType memberType = types[i];
+ if (nameMatches(matchName, memberType, partialMatch))
+ if (nested) {
+ seekQualifiedMemberTypes(
+ qualifiedName.substring(index + 1, qualifiedName.length()),
+ memberType,
+ partialMatch,
+ requestor);
+ } else {
+ requestor.acceptMemberType(memberType);
+ }
+ }
+ }
+
+ /**
+ * @see INameLookup
+ */
+ public void seekTypes(
+ String name,
+ IPackageFragment pkg,
+ boolean partialMatch,
+ int acceptFlags,
+ IJavaElementRequestor requestor) {
+
+ String matchName = partialMatch ? name.toLowerCase() : name;
+ if (matchName.indexOf('.') >= 0) { //looks for member type A.B
+ matchName = matchName.replace('.', '$');
+ }
+ if (pkg == null) {
+ findAllTypes(matchName, partialMatch, acceptFlags, requestor);
+ return;
+ }
+ IPackageFragmentRoot root = (IPackageFragmentRoot) pkg.getParent();
+ try {
+ int packageFlavor = root.getKind();
+ switch (packageFlavor) {
+ case IPackageFragmentRoot.K_BINARY :
+ seekTypesInBinaryPackage(matchName, pkg, partialMatch, acceptFlags, requestor);
+ break;
+ case IPackageFragmentRoot.K_SOURCE :
+ seekTypesInSourcePackage(matchName, pkg, partialMatch, acceptFlags, requestor);
+ break;
+ default :
+ return;
+ }
+ } catch (JavaModelException e) {
+ return;
+ }
+ }
+
+ /**
+ * Performs type search in a binary package.
+ */
+ protected void seekTypesInBinaryPackage(
+ String name,
+ IPackageFragment pkg,
+ boolean partialMatch,
+ int acceptFlags,
+ IJavaElementRequestor requestor) {
+ IClassFile[] classFiles = null;
+ try {
+ classFiles = pkg.getClassFiles();
+ } catch (JavaModelException npe) {
+ return; // the package is not present
+ }
+ int length = classFiles.length;
+
+ String unqualifiedName = name;
+ int index = name.lastIndexOf('$');
+ if (index != -1) {
+ //the type name of the inner type
+ unqualifiedName = name.substring(index + 1, name.length());
+ }
+ String lowerName = name.toLowerCase();
+ for (int i = 0; i < length; i++) {
+ if (requestor.isCanceled())
+ return;
+ IClassFile classFile = classFiles[i];
+ /**
+ * In the following call to nameMatches we must always send true
+ * for the partialMatch argument since name will never have the
+ * extension ".class" and the classFile always will.
+ */
+ if (nameMatches(lowerName, classFile, true)) {
+ IType type = null;
+ try {
+ type = classFile.getType();
+ } catch (JavaModelException npe) {
+ continue; // the classFile is not present
+ }
+ if (!partialMatch
+ || (type.getElementName().length() > 0
+ && !Character.isDigit(
+ type.getElementName().charAt(0)))) { //not an anonymous type
+ if (nameMatches(unqualifiedName, type, partialMatch)
+ && acceptType(type, acceptFlags))
+ requestor.acceptType(type);
+ }
+ }
+ }
+ }
+
+ /**
+ * Performs type search in a source package.
+ */
+ protected void seekTypesInSourcePackage(
+ String name,
+ IPackageFragment pkg,
+ boolean partialMatch,
+ int acceptFlags,
+ IJavaElementRequestor requestor) {
+ ICompilationUnit[] compilationUnits = null;
+ try {
+ compilationUnits = pkg.getCompilationUnits();
+ } catch (JavaModelException npe) {
+ return; // the package is not present
+ }
+ int length = compilationUnits.length;
+ String matchName = name;
+ int index = name.indexOf('$');
+ boolean memberType = false;
+ if (index != -1) {
+ //the compilation unit name of the inner type
+ matchName = name.substring(0, index);
+ memberType = true;
+ }
+
+ /**
+ * In the following, matchName will never have the extension ".java" and
+ * the compilationUnits always will. So add it if we're looking for
+ * an exact match.
+ */
+ String unitName = partialMatch ? matchName.toLowerCase() : matchName + ".java";
+
+ for (int i = 0; i < length; i++) {
+ if (requestor.isCanceled())
+ return;
+ ICompilationUnit compilationUnit = compilationUnits[i];
+
+ if (nameMatches(unitName, compilationUnit, partialMatch)) {
+ IType[] types = null;
+ try {
+ types = compilationUnit.getTypes();
+ } catch (JavaModelException npe) {
+ continue; // the compilation unit is not present
+ }
+ int typeLength = types.length;
+ for (int j = 0; j < typeLength; j++) {
+ if (requestor.isCanceled())
+ return;
+ IType type = types[j];
+ if (nameMatches(matchName, type, partialMatch)
+ && acceptType(type, acceptFlags))
+ if (!memberType) {
+ requestor.acceptType(type);
+ } else {
+ seekQualifiedMemberTypes(
+ name.substring(index + 1, name.length()),
+ type,
+ partialMatch,
+ requestor);
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NonVoidMethodRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NonVoidMethodRequestor.java
new file mode 100644
index 0000000000..40545699d1
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NonVoidMethodRequestor.java
@@ -0,0 +1,36 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.internal.codeassist.ISearchRequestor;
+import org.eclipse.jdt.core.IMethod;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.Signature;
+
+/**
+ * This class modifies the <code>SearchableEnvironmentRequestor</code>'s
+ * functionality by only accepting methods with return types that are not void.
+ */
+public class NonVoidMethodRequestor extends SearchableEnvironmentRequestor {
+ /**
+ * NonVoidMethodRequestor constructor comment.
+ * @param requestor org.eclipse.jdt.internal.codeassist.ISearchRequestor
+ */
+ public NonVoidMethodRequestor(ISearchRequestor requestor) {
+ super(requestor);
+ }
+
+ public void acceptMethod(IMethod method) {
+ try {
+ if (!Signature.getReturnType(method.getSignature()).equals("V")) {
+ super.acceptMethod(method);
+ }
+ } catch (JavaModelException npe) {
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Openable.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Openable.java
new file mode 100644
index 0000000000..f29961c7e1
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Openable.java
@@ -0,0 +1,444 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.jdt.internal.codeassist.CompletionEngine;
+import org.eclipse.jdt.internal.codeassist.ICompletionRequestor;
+import org.eclipse.jdt.internal.codeassist.ISelectionRequestor;
+import org.eclipse.jdt.internal.codeassist.ISearchableNameEnvironment;
+import org.eclipse.jdt.internal.codeassist.SelectionEngine;
+import org.eclipse.jdt.internal.compiler.ConfigurableOption;
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.core.*;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Locale;
+
+/**
+ * Abstract class for implementations of java elements which are IOpenable.
+ *
+ * @see IJavaElement, IOpenable
+ */
+public abstract class Openable
+ extends JavaElement
+ implements IOpenable, IBufferChangedListener {
+
+ protected Openable(int type, IJavaElement parent, String name) {
+ super(type, parent, name);
+ }
+
+ /**
+ * The buffer associated with this element has changed. Registers
+ * this element as being out of synch with its buffer's contents.
+ * If the buffer has been closed, this element is set as NOT out of
+ * synch with the contents.
+ *
+ * @see IBufferChangedListener
+ */
+ public void bufferChanged(BufferChangedEvent event) {
+ if (event.getBuffer().isClosed()) {
+ fgJavaModelManager.getElementsOutOfSynchWithBuffers().remove(this);
+ } else {
+ fgJavaModelManager.getElementsOutOfSynchWithBuffers().put(this, this);
+ }
+ }
+
+ /**
+ * Updates the info objects for this element and all of its children by
+ * removing the current infos, generating new infos, and then placing
+ * the new infos into the Java Model cache tables.
+ */
+ protected void buildStructure(OpenableElementInfo info, IProgressMonitor pm)
+ throws JavaModelException {
+
+ // remove existing (old) infos
+ removeInfo();
+ Hashtable newElements = new Hashtable(11);
+ info.setIsStructureKnown(
+ generateInfos(info, pm, newElements, getUnderlyingResource()));
+ fgJavaModelManager.getElementsOutOfSynchWithBuffers().remove(this);
+ for (Enumeration e = newElements.keys(); e.hasMoreElements();) {
+ IJavaElement key = (IJavaElement) e.nextElement();
+ Object value = newElements.get(key);
+ fgJavaModelManager.putInfo(key, value);
+ }
+ // add the info for this at the end, to ensure that a getInfo cannot reply null in case the LRU cache needs
+ // to be flushed. Might lead to performance issues.
+ // see PR 1G2K5S7: ITPJCORE:ALL - NPE when accessing source for a binary type
+ fgJavaModelManager.putInfo(this, info);
+ }
+
+ /**
+ * Close the buffer associated with this element, if any.
+ */
+ protected void closeBuffer(OpenableElementInfo info) {
+ IBuffer buffer = null;
+ buffer = getBufferManager().getBuffer(this);
+ if (buffer != null) {
+ buffer.removeBufferChangedListener(this);
+ buffer.close();
+ fgJavaModelManager.getElementsOutOfSynchWithBuffers().remove(this);
+ }
+ }
+
+ /**
+ * This element is being closed. Do any necessary cleanup.
+ */
+ protected void closing(Object info) throws JavaModelException {
+ OpenableElementInfo openableInfo = (OpenableElementInfo) info;
+ closeBuffer(openableInfo);
+ super.closing(info);
+ }
+
+ /**
+ * @see ICodeAssist
+ */
+ protected void codeComplete(
+ org.eclipse.jdt.internal.compiler.env.ICompilationUnit cu,
+ org.eclipse.jdt.internal.compiler.env.ICompilationUnit unitToSkip,
+ int position,
+ ICodeCompletionRequestor requestor)
+ throws JavaModelException {
+ if (requestor == null) {
+ throw new IllegalArgumentException("requestor cannot be null");
+ }
+ if (position < -1 || position > getBuffer().getLength()) {
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.INDEX_OUT_OF_BOUNDS));
+ }
+ SearchableEnvironment environment =
+ (SearchableEnvironment) ((JavaProject) getJavaProject())
+ .getSearchableNameEnvironment();
+ environment.unitToSkip = unitToSkip;
+
+ CompletionEngine engine =
+ new CompletionEngine(
+ environment,
+ new CompletionRequestorWrapper(requestor),
+ JavaModelManager.convertConfigurableOptions(JavaCore.getOptions()));
+ engine.complete(cu, position);
+ environment.unitToSkip = null;
+ }
+
+ /**
+ * @see ICodeAssist
+ */
+ protected IJavaElement[] codeSelect(
+ org.eclipse.jdt.internal.compiler.env.ICompilationUnit cu,
+ int offset,
+ int length)
+ throws JavaModelException {
+ SelectionRequestor requestor =
+ new SelectionRequestor(((JavaProject) getJavaProject()).getNameLookup(), this);
+ this.codeSelect(cu, offset, length, requestor);
+ return requestor.getElements();
+ }
+
+ /**
+ * @see ICodeAssist
+ */
+ protected void codeSelect(
+ org.eclipse.jdt.internal.compiler.env.ICompilationUnit cu,
+ int offset,
+ int length,
+ ISelectionRequestor requestor)
+ throws JavaModelException {
+
+ // fix for 1FWNMHH, part (1)
+ if (length == 0) {
+ return;
+ }
+
+ int end = getBuffer().getLength();
+ if (offset < 0 || length < 0 || offset + length > end) {
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.INDEX_OUT_OF_BOUNDS));
+ }
+
+ // fix for 1FVGGKF
+ ISearchableNameEnvironment environment =
+ ((JavaProject) getJavaProject()).getSearchableNameEnvironment();
+
+ // fix for 1FVXGDK
+ SelectionEngine engine =
+ new SelectionEngine(
+ environment,
+ requestor,
+ JavaModelManager.convertConfigurableOptions(JavaCore.getOptions()));
+ engine.select(cu, offset, offset + length - 1);
+ }
+
+ /**
+ * Returns a new element info for this element.
+ */
+ protected OpenableElementInfo createElementInfo() {
+ return new OpenableElementInfo();
+ }
+
+ /**
+ * Builds this element's structure and properties in the given
+ * info object, based on this element's current contents (i.e. buffer
+ * contents if this element has an open buffer, or resource contents
+ * if this element does not have an open buffer). Children
+ * are placed in the given newElements table (note, this element
+ * has already been placed in the newElements table). Returns true
+ * if successful, or false if an error is encountered while determining
+ * the structure of this element.
+ */
+ protected abstract boolean generateInfos(
+ OpenableElementInfo info,
+ IProgressMonitor pm,
+ Hashtable newElements,
+ IResource underlyingResource)
+ throws JavaModelException;
+ /**
+ * Note: a buffer with no unsaved changes can be closed by the Java Model
+ * since it has a finite number of buffers allowed open at one time. If this
+ * is the first time a request is being made for the buffer, an attempt is
+ * made to create and fill this element's buffer. If the buffer has been
+ * closed since it was first opened, the buffer is re-created.
+ *
+ * @see IOpenable
+ */
+ public IBuffer getBuffer() throws JavaModelException {
+ if (hasBuffer()) {
+ // ensure element is open
+ if (!isOpen()) {
+ getElementInfo();
+ }
+ IBuffer buffer = getBufferManager().getBuffer(this);
+ if (buffer == null) {
+ // try to (re)open a buffer
+ buffer = openBuffer(null);
+ }
+ return buffer;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the buffer manager for this element.
+ */
+ protected IBufferManager getBufferManager() {
+ return BufferManager.getDefaultBufferManager();
+ }
+
+ /**
+ * Return my underlying resource. Elements that may not have a
+ * corresponding resource must override this method.
+ *
+ * @see IJavaElement
+ */
+ public IResource getCorrespondingResource() throws JavaModelException {
+ return getUnderlyingResource();
+ }
+
+ /**
+ * @see IJavaElement
+ */
+ public IResource getUnderlyingResource() throws JavaModelException {
+ IResource parentResource = fParent.getUnderlyingResource();
+ if (parentResource == null) {
+ return null;
+ }
+ int type = parentResource.getType();
+ if (type == IResource.FOLDER || type == IResource.PROJECT) {
+ IContainer folder = (IContainer) parentResource;
+ IResource resource = folder.findMember(fName);
+ if (resource == null) {
+ throw newNotPresentException();
+ } else {
+ return resource;
+ }
+ } else {
+ return parentResource;
+ }
+ }
+
+ /**
+ * Returns true if this element may have an associated source buffer,
+ * otherwise false. Subclasses must override as required.
+ */
+ protected boolean hasBuffer() {
+ return false;
+ }
+
+ /**
+ * @see IParent
+ */
+ public boolean hasChildren() throws JavaModelException {
+ return getChildren().length > 0;
+ }
+
+ /**
+ * @see IOpenable
+ */
+ public boolean hasUnsavedChanges() throws JavaModelException {
+
+ if (isReadOnly() || !isOpen()) {
+ return false;
+ }
+ if (getBuffer() != null && getBuffer().hasUnsavedChanges()) {
+ return true;
+ }
+ // for package fragments, package fragment roots, and projects must check open buffers
+ // to see if they have an child with unsaved changes
+ if (fLEType == PACKAGE_FRAGMENT
+ || fLEType == PACKAGE_FRAGMENT_ROOT
+ || fLEType == JAVA_PROJECT
+ || fLEType == JAVA_MODEL) { // fix for 1FWNMHH, part (2)
+ Enumeration openBuffers = getBufferManager().getOpenBuffers();
+ while (openBuffers.hasMoreElements()) {
+ IBuffer buffer = (IBuffer) openBuffers.nextElement();
+ if (buffer.hasUnsavedChanges()) {
+ IJavaElement owner = (IJavaElement) buffer.getOwner();
+ if (isAncestorOf(owner)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Subclasses must override as required.
+ *
+ * @see IOpenable
+ */
+ public boolean isConsistent() throws JavaModelException {
+ return true;
+ }
+
+ /**
+ *
+ * @see IOpenable
+ */
+ public boolean isOpen() {
+ return fgJavaModelManager.getInfo(this) != null;
+ }
+
+ /**
+ * Returns true if this represents a source element.
+ * Openable source elements have an associated buffer created
+ * when they are opened.
+ */
+ protected boolean isSourceElement() {
+ return false;
+ }
+
+ /**
+ * @see IOpenable
+ */
+ public void makeConsistent(IProgressMonitor pm) throws JavaModelException {
+ if (!isConsistent()) {
+ buildStructure((OpenableElementInfo) getElementInfo(), pm);
+ }
+ }
+
+ /**
+ * @see IOpenable
+ */
+ public void open(IProgressMonitor pm) throws JavaModelException {
+ if (!isOpen()) {
+ openWhenClosed(pm);
+ }
+ }
+
+ /**
+ * Opens a buffer on the contents of this element, and returns
+ * the buffer, or returns <code>null</code> if opening fails.
+ * By default, do nothing - subclasses that have buffers
+ * must override as required.
+ */
+ protected IBuffer openBuffer(IProgressMonitor pm) throws JavaModelException {
+ return null;
+ }
+
+ /**
+ * Open an <code>Openable</code> that is known to be closed (no check for <code>isOpen()</code>).
+ */
+ protected void openWhenClosed(IProgressMonitor pm) throws JavaModelException {
+ try {
+ // 1) Parent must be open - open the parent if necessary
+ Openable openableParent = (Openable) getOpenableParent();
+ if (openableParent != null) {
+ OpenableElementInfo openableParentInfo =
+ (OpenableElementInfo) fgJavaModelManager.getInfo((IJavaElement) openableParent);
+ if (openableParentInfo == null) {
+ openableParent.openWhenClosed(pm);
+ }
+ // Parent is open.
+ }
+
+ // 1.5) Ensure my resource is local
+ IResource resource = getCorrespondingResource();
+ if (resource != null) {
+ try {
+ JavaModelManager.getJavaModelManager().ensureLocal(resource);
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ }
+ }
+
+ // 2) create the new element info and open a buffer
+ OpenableElementInfo info = createElementInfo();
+ if (resource != null && isSourceElement()) {
+ openBuffer(pm);
+ }
+
+ // 3) build the structure of the openable
+ buildStructure(info, pm);
+
+ // 4) anything special
+ opening(info);
+
+ // if any problems occuring openning the element, ensure that it's info
+ // does not remain in the cache (some elements, pre-cache their info
+ // as they are being opened).
+ } catch (JavaModelException e) {
+ fgJavaModelManager.removeInfo(this);
+ throw e;
+ }
+ }
+
+ /**
+ * @see IOpenable
+ */
+ public void save(IProgressMonitor pm, boolean force)
+ throws JavaModelException {
+ if (isReadOnly()) {
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this));
+ }
+ IBuffer buf = getBuffer();
+ if (buf != null) { // some Openables (like a JavaProject) don't have a buffer
+ buf.save(pm, force);
+ this.makeConsistent(pm); // update the element info of this element
+ }
+ }
+
+ /**
+ * Find enclosing package fragment root if any
+ */
+ public IPackageFragmentRoot getPackageFragmentRoot() {
+ IJavaElement current = this;
+ do {
+ if (current instanceof IPackageFragmentRoot)
+ return (IPackageFragmentRoot) current;
+ current = current.getParent();
+ } while (current != null);
+ return null;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/OpenableElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/OpenableElementInfo.java
new file mode 100644
index 0000000000..a95e05c06a
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/OpenableElementInfo.java
@@ -0,0 +1,13 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+/** Element info for IOpenable elements. */
+/* package */
+class OpenableElementInfo extends JavaElementInfo {
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/OverflowingLRUCache.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/OverflowingLRUCache.java
new file mode 100644
index 0000000000..e4af524a0b
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/OverflowingLRUCache.java
@@ -0,0 +1,444 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.util.*;
+
+import java.util.Enumeration;
+
+/**
+ * The <code>OverflowingLRUCache</code> is an LRUCache which attempts
+ * to maintain a size equal or less than its <code>fSpaceLimit</code>
+ * by removing the least recently used elements.
+ *
+ * <p>The cache will remove elements which successfully close and all
+ * elements which are explicitly removed.
+ *
+ * <p>If the cache cannot remove enough old elements to add new elements
+ * it will grow beyond <code>fSpaceLimit</code>. Later, it will attempt to
+ * shink back to the maximum space limit.
+ *
+ * The method <code>close</code> should attempt to close the element. If
+ * the element is successfully closed it will return true and the element will
+ * be removed from the cache. Otherwise the element will remain in the cache.
+ *
+ * <p>The cache implicitly attempts shrinks on calls to <code>put</code>and
+ * <code>setSpaceLimit</code>. Explicitly calling the <code>shrink</code> method
+ * will also cause the cache to attempt to shrink.
+ *
+ * <p>The cache calculates the used space of all elements which implement
+ * <code>ILRUCacheable</code>. All other elements are assumed to be of size one.
+ *
+ * <p>Use the <code>#peek(Object)</code> and <code>#disableTimestamps()</code> method to
+ * circumvent the timestamp feature of the cache. This feature is intended to be used
+ * only when the <code>#close(LRUCacheEntry)</code> method causes changes to the cache.
+ * For example, if a parent closes its children when </code>#close(LRUCacheEntry)</code> is called,
+ * it should be careful not to change the LRU linked list. It can be sure it is not causing
+ * problems by calling <code>#peek(Object)</code> instead of <code>#get(Object)</code> method.
+ *
+ * @see LRUCache
+ */
+public abstract class OverflowingLRUCache extends LRUCache {
+ /**
+ * Indicates if the cache has been over filled and by how much.
+ */
+ protected int fOverflow = 0;
+ /**
+ * Indicates whether or not timestamps should be updated
+ */
+ protected boolean fTimestampsOn = true;
+ /**
+ * Indicates how much space should be reclaimed when the cache overflows.
+ * Inital load factor of one half.
+ */
+ protected double fLoadFactor = 0.667;
+ /**
+ * Creates a OverflowingLRUCache.
+ * @param size Size limit of cache.
+ */
+ public OverflowingLRUCache(int size) {
+ this(size, 0);
+ }
+
+ /**
+ * Creates a OverflowingLRUCache.
+ * @param size Size limit of cache.
+ * @param overflow Size of the overflow.
+ */
+ public OverflowingLRUCache(int size, int overflow) {
+ super(size);
+ fOverflow = overflow;
+ }
+
+ /**
+ * Returns a new cache containing the same contents.
+ *
+ * @return New copy of this object.
+ */
+ public Object clone() {
+
+ OverflowingLRUCache newCache =
+ (OverflowingLRUCache) newInstance(fSpaceLimit, fOverflow);
+ LRUCacheEntry qEntry;
+
+ /* Preserve order of entries by copying from oldest to newest */
+ qEntry = this.fEntryQueueTail;
+ while (qEntry != null) {
+ newCache.privateAdd(qEntry._fKey, qEntry._fValue, qEntry._fSpace);
+ qEntry = qEntry._fPrevious;
+ }
+ return newCache;
+ }
+
+ /**
+ * Returns true if the element is successfully closed and
+ * removed from the cache, otherwise false.
+ *
+ * <p>NOTE: this triggers an external remove from the cache
+ * by closing the obejct.
+ *
+ */
+ protected abstract boolean close(LRUCacheEntry entry);
+ /**
+ * Returns an enumerator of the values in the cache with the most
+ * recently used first.
+ */
+ public Enumeration elements() {
+ if (fEntryQueue == null)
+ return new LRUCacheEnumerator(null);
+ LRUCacheEnumerator.LRUEnumeratorElement head =
+ new LRUCacheEnumerator.LRUEnumeratorElement(fEntryQueue._fValue);
+ LRUCacheEntry currentEntry = fEntryQueue._fNext;
+ LRUCacheEnumerator.LRUEnumeratorElement currentElement = head;
+ while (currentEntry != null) {
+ currentElement.fNext =
+ new LRUCacheEnumerator.LRUEnumeratorElement(currentEntry._fValue);
+ currentElement = currentElement.fNext;
+
+ currentEntry = currentEntry._fNext;
+ }
+ return new LRUCacheEnumerator(head);
+ }
+
+ /**
+ * This method exposed only for testing purposes!
+ *
+ * @return Hashtable of entries
+ * @private - for internal testing only
+ */
+ public java.util.Hashtable getEntryTable() {
+ return fEntryTable;
+ }
+
+ /**
+ * Returns the load factor for the cache. The load factor determines how
+ * much space is reclaimed when the cache exceeds its space limit.
+ * @return double
+ */
+ public double getLoadFactor() {
+ return fLoadFactor;
+ }
+
+ /**
+ * @return The space by which the cache has overflown.
+ */
+ public int getOverflow() {
+ return fOverflow;
+ }
+
+ /**
+ * Ensures there is the specified amount of free space in the receiver,
+ * by removing old entries if necessary. Returns true if the requested space was
+ * made available, false otherwise. May not be able to free enough space
+ * since some elements cannot be removed until they are saved.
+ *
+ * @param space Amount of space to free up
+ */
+ protected boolean makeSpace(int space) {
+ int limit = fSpaceLimit;
+ if (fOverflow == 0) {
+ /* if space is already available */
+ if (fCurrentSpace + space <= limit) {
+ return true;
+ }
+ }
+
+ // System.out.println("Cache Reached Max!");
+ // printStats();
+
+ /* Free up space by removing oldest entries */
+ int spaceNeeded = (int) (fLoadFactor * fSpaceLimit);
+ spaceNeeded = (spaceNeeded > space) ? spaceNeeded : space;
+ LRUCacheEntry entry = fEntryQueueTail;
+ // int i = 0;
+ while (fCurrentSpace + spaceNeeded > limit && entry != null) {
+ this.privateRemoveEntry(entry, false, false);
+ entry = entry._fPrevious;
+ // i++;
+ }
+
+ // System.out.println("Checked " + i + " entries.");
+ // System.out.println("Current Space at " + fCurrentSpace);
+ // printStats();
+
+ /* check again, since we may have aquired enough space */
+ if (fCurrentSpace + space <= limit) {
+ fOverflow = 0;
+ return true;
+ }
+
+ /* update fOverflow */
+ fOverflow = fCurrentSpace + space - limit;
+ return false;
+ }
+
+ /**
+ * Returns a new instance of the reciever.
+ */
+ protected abstract LRUCache newInstance(int size, int overflow);
+ /**
+ * Answers the value in the cache at the given key.
+ * If the value is not in the cache, returns null
+ *
+ * This function does not modify timestamps.
+ */
+ public Object peek(Object key) {
+
+ LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get(key);
+ if (entry == null) {
+ return null;
+ }
+ return entry._fValue;
+ }
+
+ /**
+ * @private For testing purposes only
+ */
+ public void printStats() {
+ int forwardListLength = 0;
+ LRUCacheEntry entry = fEntryQueue;
+ while (entry != null) {
+ forwardListLength++;
+ entry = entry._fNext;
+ }
+ System.out.println("Forward length: " + forwardListLength);
+
+ int backwardListLength = 0;
+ entry = fEntryQueueTail;
+ while (entry != null) {
+ backwardListLength++;
+ entry = entry._fPrevious;
+ }
+ System.out.println("Backward length: " + backwardListLength);
+
+ Enumeration keys = fEntryTable.keys();
+ java.util.Vector v = new java.util.Vector();
+ class Temp {
+ public Class fClass;
+ public int fCount;
+ public Temp(Class aClass) {
+ fClass = aClass;
+ fCount = 1;
+ }
+ public String toString() {
+ return "Class: " + fClass + " has " + fCount + " entries.";
+ }
+ }
+ java.util.Hashtable h = new java.util.Hashtable();
+ while (keys.hasMoreElements()) {
+ entry = (LRUCacheEntry) fEntryTable.get(keys.nextElement());
+ Class key = entry._fValue.getClass();
+ Temp t = (Temp) h.get(key);
+ if (t == null) {
+ h.put(key, new Temp(key));
+ } else {
+ t.fCount++;
+ }
+ }
+
+ keys = h.keys();
+ while (keys.hasMoreElements()) {
+ System.out.println(h.get(keys.nextElement()));
+ }
+ }
+
+ /**
+ * Removes the entry from the entry queue.
+ * Calls <code>privateRemoveEntry</code> with the external functionality enabled.
+ *
+ * @param shuffle indicates whether we are just shuffling the queue
+ * (i.e., the entry table is left alone).
+ */
+ protected void privateRemoveEntry(LRUCacheEntry entry, boolean shuffle) {
+ privateRemoveEntry(entry, shuffle, true);
+ }
+
+ /**
+ * Removes the entry from the entry queue. If <i>external</i> is true, the entry is removed
+ * without checking if it can be removed. It is assumed that the client has already closed
+ * the element it is trying to remove (or will close it promptly).
+ *
+ * If <i>external</i> is false, and the entry is not closed, it is not removed and the
+ * pointers are not changed.
+ *
+ * @param shuffle indicates whether we are just shuffling the queue
+ * (i.e., the entry table is left alone).
+ */
+ protected void privateRemoveEntry(
+ LRUCacheEntry entry,
+ boolean shuffle,
+ boolean external) {
+ if (!shuffle) {
+ if (external) {
+ fEntryTable.remove(entry._fKey);
+ fCurrentSpace -= entry._fSpace;
+ privateNotifyDeletionFromCache(entry);
+ } else {
+ if (!close(entry)) {
+ return;
+ }
+ }
+ }
+
+ LRUCacheEntry previous = entry._fPrevious;
+ LRUCacheEntry next = entry._fNext;
+
+ /* if this was the first entry */
+ if (previous == null) {
+ fEntryQueue = next;
+ } else {
+ previous._fNext = next;
+ }
+
+ /* if this was the last entry */
+ if (next == null) {
+ fEntryQueueTail = previous;
+ } else {
+ next._fPrevious = previous;
+ }
+ }
+
+ /**
+ * Sets the value in the cache at the given key. Returns the value.
+ *
+ * @param key Key of object to add.
+ * @param value Value of object to add.
+ * @return added value.
+ */
+ public Object put(Object key, Object value) {
+ /* attempt to rid ourselves of the overflow, if there is any */
+ if (fOverflow > 0)
+ shrink();
+
+ /* Check whether there's an entry in the cache */
+ int newSpace = spaceFor(key, value);
+ LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get(key);
+
+ if (entry != null) {
+
+ /**
+ * Replace the entry in the cache if it would not overflow
+ * the cache. Otherwise flush the entry and re-add it so as
+ * to keep cache within budget
+ */
+ int oldSpace = entry._fSpace;
+ int newTotal = fCurrentSpace - oldSpace + newSpace;
+ if (newTotal <= fSpaceLimit) {
+ updateTimestamp(entry);
+ entry._fValue = value;
+ entry._fSpace = newSpace;
+ fCurrentSpace = newTotal;
+ fOverflow = 0;
+ return value;
+ } else {
+ privateRemoveEntry(entry, false, false);
+ }
+ }
+
+ // attempt to make new space
+ makeSpace(newSpace);
+
+ // add without worring about space, it will
+ // be handled later in a makeSpace call
+ privateAdd(key, value, newSpace);
+
+ return value;
+ }
+
+ /**
+ * Removes and returns the value in the cache for the given key.
+ * If the key is not in the cache, returns null.
+ *
+ * @param key Key of object to remove from cache.
+ * @return Value removed from cache.
+ */
+ public Object remove(Object key) {
+ return removeKey(key);
+ }
+
+ /**
+ * Sets the load factor for the cache. The load factor determines how
+ * much space is reclaimed when the cache exceeds its space limit.
+ * @param newLoadFactor double
+ * @throws IllegalArgumentException when the new load factor is not in (0.0, 1.0]
+ */
+ public void setLoadFactor(double newLoadFactor)
+ throws IllegalArgumentException {
+ if (newLoadFactor <= 1.0 && newLoadFactor > 0.0)
+ fLoadFactor = newLoadFactor;
+ else
+ throw new IllegalArgumentException("incorrect load factor");
+ }
+
+ /**
+ * Sets the maximum amount of space that the cache can store
+ *
+ * @param limit Number of units of cache space
+ */
+ public void setSpaceLimit(int limit) {
+ if (limit < fSpaceLimit) {
+ makeSpace(fSpaceLimit - limit);
+ }
+ fSpaceLimit = limit;
+ }
+
+ /**
+ * Attempts to shrink the cache if it has overflown.
+ * Returns true if the cache shrinks to less than or equal to <code>fSpaceLimit</code>.
+ */
+ public boolean shrink() {
+ if (fOverflow > 0)
+ return makeSpace(0);
+ return true;
+ }
+
+ /**
+ * Returns a String that represents the value of this object. This method
+ * is for debugging purposes only.
+ */
+ public String toString() {
+ return "OverflowingLRUCache "
+ + ((fCurrentSpace + fOverflow) * 100.0 / fSpaceLimit)
+ + "% full\n"
+ + this.toStringContents();
+ }
+
+ /**
+ * Updates the timestamp for the given entry, ensuring that the queue is
+ * kept in correct order. The entry must exist.
+ *
+ * <p>This method will do nothing if timestamps have been disabled.
+ */
+ protected void updateTimestamp(LRUCacheEntry entry) {
+ if (fTimestampsOn) {
+ entry._fTimestamp = fTimestampCounter++;
+ if (fEntryQueue != entry) {
+ this.privateRemoveEntry(entry, true);
+ this.privateAddEntry(entry, true);
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageDeclaration.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageDeclaration.java
new file mode 100644
index 0000000000..338f330f7c
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageDeclaration.java
@@ -0,0 +1,50 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.jdom.IDOMNode;
+
+/**
+ * @see IPackageDeclaration
+ */
+
+/* package */
+class PackageDeclaration
+ extends SourceRefElement
+ implements IPackageDeclaration {
+ protected PackageDeclaration(ICompilationUnit parent, String name) {
+ super(PACKAGE_DECLARATION, parent, name);
+ }
+
+ /**
+ * @see JavaElement#equalsDOMNode
+ */
+ protected boolean equalsDOMNode(IDOMNode node) throws JavaModelException {
+ return (node.getNodeType() == IDOMNode.PACKAGE)
+ && getElementName().equals(node.getName());
+ }
+
+ /**
+ * @see JavaElement#getHandleMemento()
+ */
+ protected char getHandleMementoDelimiter() {
+ return JavaElement.JEM_PACKAGEDECLARATION;
+ }
+
+ /**
+ * @private Debugging purposes
+ */
+ protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+ buffer.append("package ");
+ buffer.append(getElementName());
+ if (info == null) {
+ buffer.append(" (not open)");
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragment.java
new file mode 100644
index 0000000000..4b58ce7b39
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragment.java
@@ -0,0 +1,371 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.jdt.core.*;
+
+import java.util.*;
+
+/**
+ * @see IPackageFragment
+ */
+public class PackageFragment extends Openable implements IPackageFragment {
+ /**
+ * Constant empty list of class files
+ */
+ protected static IClassFile[] fgEmptyClassFileList = new IClassFile[] {
+ };
+
+ /**
+ * Constant empty list of compilation units
+ */
+ protected static ICompilationUnit[] fgEmptyCompilationUnitList =
+ new ICompilationUnit[] {
+ };
+
+ /**
+ * Constructs a handle for a package fragment
+ *
+ * @see IPackageFragment
+ */
+ protected PackageFragment(IPackageFragmentRoot root, String name) {
+ super(PACKAGE_FRAGMENT, root, name);
+ }
+
+ /**
+ * Compute the children of this package fragment.
+ *
+ * <p>Package fragments which are folders recognize files based on the
+ * type of the fragment
+ * <p>Package fragments which are in a jar only recognize .class files (
+ * @see JarPackageFragment).
+ */
+ protected boolean computeChildren(OpenableElementInfo info, IResource resource)
+ throws JavaModelException {
+ Vector vChildren = new Vector();
+ int kind = getKind();
+ String extType;
+ if (kind == IPackageFragmentRoot.K_SOURCE) {
+ extType = "java";
+ } else {
+ extType = "class";
+ }
+ try {
+ IResource[] members = ((IContainer) resource).members();
+ for (int i = 0, max = members.length; i < max; i++) {
+ IResource child = members[i];
+ if (child.getType() != IResource.FOLDER) {
+ String extension = child.getProjectRelativePath().getFileExtension();
+ if (extension != null) {
+ if (extension.equalsIgnoreCase(extType)) {
+ IJavaElement childElement;
+ if (kind == IPackageFragmentRoot.K_SOURCE) {
+ childElement = getCompilationUnit(child.getName());
+ } else {
+ childElement = getClassFile(child.getName());
+ }
+ vChildren.addElement(childElement);
+ }
+ }
+ }
+ }
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ }
+ vChildren.trimToSize();
+ IJavaElement[] children = new IJavaElement[vChildren.size()];
+ vChildren.copyInto(children);
+ info.setChildren(children);
+ return true;
+ }
+
+ /**
+ * Returns true if this fragment contains at least one java resource.
+ * Returns false otherwise.
+ */
+ public boolean containsJavaResources() throws JavaModelException {
+ return ((PackageFragmentInfo) getElementInfo()).containsJavaResources();
+ }
+
+ /**
+ * @see ISourceManipulation
+ */
+ public void copy(
+ IJavaElement container,
+ IJavaElement sibling,
+ String rename,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ if (container == null) {
+ throw new IllegalArgumentException("container cannot be null");
+ }
+ IJavaElement[] elements = new IJavaElement[] { this };
+ IJavaElement[] containers = new IJavaElement[] { container };
+ IJavaElement[] siblings = null;
+ if (sibling != null) {
+ siblings = new IJavaElement[] { sibling };
+ }
+ String[] renamings = null;
+ if (rename != null) {
+ renamings = new String[] { rename };
+ }
+ getJavaModel().copy(elements, containers, siblings, renamings, force, monitor);
+ }
+
+ /**
+ * @see IPackageFragment
+ */
+ public ICompilationUnit createCompilationUnit(
+ String name,
+ String contents,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ CreateCompilationUnitOperation op =
+ new CreateCompilationUnitOperation(this, name, contents, force);
+ runOperation(op, monitor);
+ return getCompilationUnit(name);
+ }
+
+ /**
+ * @see JavaElement
+ */
+ protected OpenableElementInfo createElementInfo() {
+ return new PackageFragmentInfo();
+ }
+
+ /**
+ * @see ISourceManipulation
+ */
+ public void delete(boolean force, IProgressMonitor monitor)
+ throws JavaModelException {
+ IJavaElement[] elements = new IJavaElement[] { this };
+ getJavaModel().delete(elements, force, monitor);
+ }
+
+ /**
+ * @see Openable
+ */
+ protected boolean generateInfos(
+ OpenableElementInfo info,
+ IProgressMonitor pm,
+ Hashtable newElements,
+ IResource underlyingResource)
+ throws JavaModelException {
+ return computeChildren(info, underlyingResource);
+ }
+
+ /**
+ * @see IPackageFragment
+ */
+ public IClassFile getClassFile(String name) {
+ return new ClassFile(this, name);
+ }
+
+ /**
+ * Returns a the collection of class files in this - a folder package fragment which has a root
+ * that has its kind set to <code>IPackageFragmentRoot.K_Source</code> does not
+ * recognize class files.
+ *
+ * @see IPackageFragment
+ * @see JarPackageFragment
+ */
+ public IClassFile[] getClassFiles() throws JavaModelException {
+ if (getKind() == IPackageFragmentRoot.K_SOURCE) {
+ return fgEmptyClassFileList;
+ }
+
+ Vector v = getChildrenOfType(CLASS_FILE);
+ IClassFile[] array = new IClassFile[v.size()];
+ v.copyInto(array);
+ return array;
+ }
+
+ /**
+ * @see IPackageFragment
+ */
+ public ICompilationUnit getCompilationUnit(String name) {
+ return new CompilationUnit(this, name);
+ }
+
+ /**
+ * @see IPackageFragment
+ */
+ public ICompilationUnit[] getCompilationUnits() throws JavaModelException {
+ if (getKind() == IPackageFragmentRoot.K_BINARY) {
+ return fgEmptyCompilationUnitList;
+ }
+
+ Vector v = getChildrenOfType(COMPILATION_UNIT);
+ ICompilationUnit[] array = new ICompilationUnit[v.size()];
+ v.copyInto(array);
+ return array;
+ }
+
+ /**
+ * @see JavaElement#getHandleMemento()
+ */
+ protected char getHandleMementoDelimiter() {
+ return JavaElement.JEM_PACKAGEFRAGMENT;
+ }
+
+ /**
+ * @see IPackageFragment
+ */
+ public int getKind() throws JavaModelException {
+ return ((IPackageFragmentRoot) getParent()).getKind();
+ }
+
+ /**
+ * Returns an array of non-java resources contained in the receiver.
+ */
+ public Object[] getNonJavaResources() throws JavaModelException {
+ if (this.isDefaultPackage()) {
+ // We don't want to show non java resources of the default package (see PR #1G58NB8)
+ return JavaElementInfo.NO_NON_JAVA_RESOURCES;
+ } else {
+ return ((PackageFragmentInfo) getElementInfo()).getNonJavaResources(
+ getUnderlyingResource());
+ }
+ }
+
+ /**
+ * @see IJavaElement
+ */
+ public IResource getUnderlyingResource() throws JavaModelException {
+ IResource rootResource = fParent.getUnderlyingResource();
+ if (rootResource == null) {
+ //jar package fragment root that has no associated resource
+ return null;
+ }
+ // the underlying resource may be a folder or a project (in the case that the project folder
+ // is atually the package fragment root)
+ if (rootResource.getType() == IResource.FOLDER
+ || rootResource.getType() == IResource.PROJECT) {
+ IContainer folder = (IContainer) rootResource;
+ String[] segs = Signature.getSimpleNames(fName);
+ for (int i = 0; i < segs.length; ++i) {
+ IResource child = folder.findMember(segs[i]);
+ if (child == null || child.getType() != IResource.FOLDER) {
+ throw newNotPresentException();
+ }
+ folder = (IFolder) child;
+ }
+ return folder;
+ } else {
+ return rootResource;
+ }
+ }
+
+ /**
+ * @see IPackageFragment
+ */
+ public boolean hasSubpackages() throws JavaModelException {
+ IJavaElement[] packages = ((IPackageFragmentRoot) getParent()).getChildren();
+ String name = getElementName();
+ int nameLength = name.length();
+ String packageName = isDefaultPackage() ? name : name + ".";
+ for (int i = 0; i < packages.length; i++) {
+ String otherName = packages[i].getElementName();
+ if (otherName.length() > nameLength && otherName.startsWith(packageName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @see IPackageFragment
+ */
+ public boolean isDefaultPackage() {
+ return this.getElementName().length() == 0;
+ }
+
+ /**
+ * @see ISourceManipulation
+ */
+ public void move(
+ IJavaElement container,
+ IJavaElement sibling,
+ String rename,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ if (container == null) {
+ throw new IllegalArgumentException("conatiner cannot be null");
+ }
+ IJavaElement[] elements = new IJavaElement[] { this };
+ IJavaElement[] containers = new IJavaElement[] { container };
+ IJavaElement[] siblings = null;
+ if (sibling != null) {
+ siblings = new IJavaElement[] { sibling };
+ }
+ String[] renamings = null;
+ if (rename != null) {
+ renamings = new String[] { rename };
+ }
+ getJavaModel().move(elements, containers, siblings, renamings, force, monitor);
+ }
+
+ /**
+ * Recomputes the children of this element, based on the current state
+ * of the workbench.
+ */
+ public void refreshChildren() {
+ try {
+ OpenableElementInfo info = (OpenableElementInfo) getElementInfo();
+ computeChildren(info, getUnderlyingResource());
+ } catch (JavaModelException e) {
+ // do nothing.
+ }
+ }
+
+ /**
+ * @see ISourceManipulation
+ */
+ public void rename(String name, boolean force, IProgressMonitor monitor)
+ throws JavaModelException {
+ if (name == null) {
+ throw new IllegalArgumentException("name cannot be null");
+ }
+ IJavaElement[] elements = new IJavaElement[] { this };
+ IJavaElement[] dests = new IJavaElement[] { this.getParent()};
+ String[] renamings = new String[] { name };
+ getJavaModel().rename(elements, dests, renamings, force, monitor);
+ }
+
+ /**
+ * @private Debugging purposes
+ */
+ protected void toStringChildren(int tab, StringBuffer buffer, Object info) {
+ if (tab == 0) {
+ super.toStringChildren(tab, buffer, info);
+ }
+ }
+
+ /**
+ * @private Debugging purposes
+ */
+ protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+ if (getElementName().length() == 0) {
+ buffer.append("[default]");
+ } else {
+ buffer.append(getElementName());
+ }
+ if (info == null) {
+ buffer.append(" (not open)");
+ } else {
+ if (tab > 0) {
+ buffer.append(" (...)");
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentInfo.java
new file mode 100644
index 0000000000..22e1ea7e65
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentInfo.java
@@ -0,0 +1,106 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.CoreException;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+/**
+ * Element info for PackageFragments.
+ */
+class PackageFragmentInfo extends OpenableElementInfo {
+
+ /**
+ * A array with all the non-java resources contained by this PackageFragment
+ */
+ protected Object[] fNonJavaResources;
+
+ /**
+ * Create and initialize a new instance of the receiver
+ */
+ public PackageFragmentInfo() {
+ fNonJavaResources = null;
+ }
+
+ /**
+ * Compute the non-java resources of this package fragment.
+ *
+ * <p>Package fragments which are folders recognize files based on the
+ * type of the fragment
+ * <p>Package fragments which are in a jar only recognize .class files (
+ * @see JarPackageFragment).
+ */
+ private Object[] computeNonJavaResources(IResource resource) {
+ Object[] nonJavaResources = new IResource[5];
+ int nonJavaResourcesCounter = 0;
+ try {
+ IResource[] members = ((IContainer) resource).members();
+ for (int i = 0, max = members.length; i < max; i++) {
+ IResource child = members[i];
+ if (child.getType() != IResource.FOLDER) {
+ String extension = child.getProjectRelativePath().getFileExtension();
+ if (!"java".equalsIgnoreCase(extension)
+ && !"class".equalsIgnoreCase(extension)) {
+ if (nonJavaResources.length == nonJavaResourcesCounter) {
+ // resize
+ System.arraycopy(
+ nonJavaResources,
+ 0,
+ (nonJavaResources = new IResource[nonJavaResourcesCounter * 2]),
+ 0,
+ nonJavaResourcesCounter);
+ }
+ nonJavaResources[nonJavaResourcesCounter++] = child;
+ }
+ }
+ }
+ if (nonJavaResourcesCounter == 0) {
+ nonJavaResources = NO_NON_JAVA_RESOURCES;
+ } else {
+ if (nonJavaResources.length != nonJavaResourcesCounter) {
+ System.arraycopy(
+ nonJavaResources,
+ 0,
+ (nonJavaResources = new IResource[nonJavaResourcesCounter]),
+ 0,
+ nonJavaResourcesCounter);
+ }
+ }
+ } catch (CoreException e) {
+ nonJavaResources = NO_NON_JAVA_RESOURCES;
+ nonJavaResourcesCounter = 0;
+ }
+ return nonJavaResources;
+ }
+
+ /**
+ */
+ boolean containsJavaResources() {
+ return fChildren.length != 0;
+ }
+
+ /**
+ * Returns an array of non-java resources contained in the receiver.
+ */
+ Object[] getNonJavaResources(IResource underlyingResource) {
+ Object[] nonJavaResources = fNonJavaResources;
+ if (nonJavaResources == null) {
+ nonJavaResources = computeNonJavaResources(underlyingResource);
+ fNonJavaResources = nonJavaResources;
+ }
+ return nonJavaResources;
+ }
+
+ /**
+ * Set the fNonJavaResources to res value
+ */
+ synchronized void setNonJavaResources(Object[] resources) {
+ fNonJavaResources = resources;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java
new file mode 100644
index 0000000000..be9bbc77ff
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java
@@ -0,0 +1,369 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import java.util.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * @see IPackageFragmentRoot
+ */
+public class PackageFragmentRoot
+ extends Openable
+ implements IPackageFragmentRoot {
+
+ /**
+ * The resource associated with this root.
+ * @see IResource
+ */
+ protected IResource fResource;
+ /**
+ * Constructs a package fragment root which is the root of the java package
+ * directory hierarchy.
+ */
+ protected PackageFragmentRoot(IResource resource, IJavaProject project) {
+ this(resource, project, resource.getProjectRelativePath().toString());
+ fResource = resource;
+ }
+
+ /**
+ * Constructs a package fragment root which is the root of the java package
+ * directory hierarchy.
+ */
+ protected PackageFragmentRoot(
+ IResource resource,
+ IJavaProject project,
+ String path) {
+ super(PACKAGE_FRAGMENT_ROOT, project, path);
+ fResource = resource;
+ }
+
+ /**
+ * @see IPackageFragmentRoot
+ */
+ public void attachSource(
+ IPath zipPath,
+ IPath rootPath,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, this));
+ }
+
+ /**
+ * Compute the package fragment children of this package fragment root.
+ *
+ * @exception JavaModelException The resource associated with this package fragment root does not exist
+ */
+ protected boolean computeChildren(OpenableElementInfo info)
+ throws JavaModelException {
+ try {
+ // the underlying resource may be a folder or a project (in the case that the project folder
+ // is actually the package fragment root)
+ if (fResource.getType() == IResource.FOLDER
+ || fResource.getType() == IResource.PROJECT) {
+ Vector vChildren = new Vector(5);
+ computeFolderChildren((IContainer) fResource, "", vChildren);
+ IJavaElement[] children = new IJavaElement[vChildren.size()];
+ vChildren.copyInto(children);
+ info.setChildren(children);
+ }
+ } catch (JavaModelException e) {
+ //problem resolving children; structure remains unknown
+ info.setChildren(new IJavaElement[] {
+ });
+ throw e;
+ }
+ return true;
+ }
+
+ /**
+ * Starting at this folder, create package fragments and add the fragments to the collection
+ * of children.
+ *
+ * @exception JavaModelException The resource associated with this package fragment does not exist
+ */
+ protected void computeFolderChildren(
+ IContainer folder,
+ String prefix,
+ Vector vChildren)
+ throws JavaModelException {
+ IPackageFragment pkg = getPackageFragment(prefix);
+ vChildren.addElement(pkg);
+ try {
+ IPath outputLocationPath = getJavaProject().getOutputLocation();
+ IResource[] members = folder.members();
+ for (int i = 0, max = members.length; i < max; i++) {
+ IResource member = members[i];
+ if (member.getType() == IResource.FOLDER
+ && member.getName().indexOf('.') < 0) {
+ String newPrefix;
+ if (prefix.length() == 0) {
+ newPrefix = member.getName();
+ } else {
+ newPrefix = prefix + "." + member.getName();
+ }
+ // eliminate binary output only if nested inside direct subfolders
+ if (!member.getFullPath().equals(outputLocationPath)) {
+ computeFolderChildren((IFolder) member, newPrefix, vChildren);
+ }
+ }
+ }
+ } catch (IllegalArgumentException e) {
+ throw new JavaModelException(
+ e,
+ IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST);
+ // could be thrown by ElementTree when path is not found
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ }
+ }
+
+ /**
+ * Returns a new element info for this element.
+ */
+ protected OpenableElementInfo createElementInfo() {
+ return new PackageFragmentRootInfo();
+ }
+
+ /**
+ * @see IPackageFragmentRoot
+ */
+ public IPackageFragment createPackageFragment(
+ String name,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ CreatePackageFragmentOperation op =
+ new CreatePackageFragmentOperation(this, name, force);
+ runOperation(op, monitor);
+ return getPackageFragment(name);
+ }
+
+ /**
+ * Returns the root's kind - K_SOURCE or K_BINARY, defaults
+ * to K_SOURCE if it is not on the classpath.
+ *
+ * @exception NotPresentException if the project and root do
+ * not exist.
+ */
+ protected int determineKind(IResource underlyingResource)
+ throws JavaModelException {
+ IClasspathEntry[] entries = getJavaProject().getResolvedClasspath(true);
+ for (int i = 0; i < entries.length; i++) {
+ IClasspathEntry entry = entries[i];
+ if (entry.getPath().equals(underlyingResource.getFullPath())) {
+ return entry.getContentKind();
+ }
+ }
+ return IPackageFragmentRoot.K_SOURCE;
+ }
+
+ /**
+ * Compares two objects for equality;
+ * for <code>PackageFragmentRoot</code>s, equality is having the
+ * same <code>JavaModel</code>, same resources, and occurrence count.
+ *
+ */
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof PackageFragmentRoot))
+ return false;
+ PackageFragmentRoot other = (PackageFragmentRoot) o;
+ return getJavaModel().equals(other.getJavaModel())
+ && fResource.equals(other.fResource)
+ && fOccurrenceCount == other.fOccurrenceCount;
+ }
+
+ /**
+ * @see IJavaElement
+ */
+ public boolean exists() {
+ if (!this.exists0())
+ return false;
+
+ // Make the root path a workspace relative path (case of a jar external to its project but internal to the workspace)
+ IPath path = this.getPath();
+ IJavaProject project = this.getJavaProject();
+
+ // Check that the package fragment root is in its parent's classpath
+ try {
+ IPackageFragmentRoot[] roots = project.getPackageFragmentRoots();
+ for (int i = 0, length = roots.length; i < length; i++) {
+ if (this.equals(roots[i]))
+ return true;
+ }
+ if (project.getOutputLocation().equals(path)) {
+ // special permission granted to project binary output (when building)
+ return true;
+ }
+ return false;
+ } catch (JavaModelException e) {
+ return false;
+ }
+ }
+
+ public boolean exists0() {
+ return super.exists();
+ }
+
+ /**
+ * @see Openable
+ */
+ protected boolean generateInfos(
+ OpenableElementInfo info,
+ IProgressMonitor pm,
+ Hashtable newElements,
+ IResource underlyingResource)
+ throws JavaModelException {
+ ((PackageFragmentRootInfo) info).setRootKind(determineKind(underlyingResource));
+ return computeChildren(info);
+ }
+
+ /**
+ * @see JavaElement#getHandleMemento()
+ */
+ protected char getHandleMementoDelimiter() {
+ return JavaElement.JEM_PACKAGEFRAGMENTROOT;
+ }
+
+ /**
+ * @see IPackageFragmentRoot
+ */
+ public int getKind() throws JavaModelException {
+ return ((PackageFragmentRootInfo) getElementInfo()).getRootKind();
+ }
+
+ /**
+ * Returns an array of non-java resources contained in the receiver.
+ */
+ public Object[] getNonJavaResources() throws JavaModelException {
+ return ((PackageFragmentRootInfo) getElementInfo()).getNonJavaResources(
+ getJavaProject(),
+ getUnderlyingResource());
+ }
+
+ /**
+ * @see IPackageFragmentRoot
+ */
+ public IPackageFragment getPackageFragment(String packageName) {
+ return new PackageFragment(this, packageName);
+ }
+
+ /**
+ * Returns the package name for the given folder
+ * (which is a decendent of this root).
+ */
+ protected String getPackageName(IFolder folder) throws JavaModelException {
+ IPath myPath = getPath();
+ IPath pkgPath = folder.getFullPath();
+ int mySegmentCount = myPath.segmentCount();
+ int pkgSegmentCount = pkgPath.segmentCount();
+ StringBuffer name = new StringBuffer(IPackageFragment.DEFAULT_PACKAGE_NAME);
+ for (int i = mySegmentCount; i < pkgSegmentCount; i++) {
+ if (i > mySegmentCount) {
+ name.append(".");
+ }
+ name.append(pkgPath.segment(i));
+ }
+ return name.toString();
+ }
+
+ /**
+ * @see IPackageFragmentRoot
+ */
+ public IPath getPath() {
+ return fResource.getFullPath();
+ }
+
+ /**
+ * Cannot attach source to a folder.
+ *
+ * @see IPackageFragmentRoot
+ */
+ public IPath getSourceAttachmentPath() throws JavaModelException {
+ return null;
+ }
+
+ /**
+ * Cannot attach source to a folder.
+ *
+ * @see IPackageFragmentRoot
+ */
+ public IPath getSourceAttachmentRootPath() throws JavaModelException {
+ return null;
+ }
+
+ /**
+ * @see IJavaElement
+ */
+ public IResource getUnderlyingResource() throws JavaModelException {
+ if (fResource.exists()) {
+ return fResource;
+ } else {
+ throw newNotPresentException();
+ }
+
+ }
+
+ public int hashCode() {
+ return fResource.hashCode();
+ }
+
+ /**
+ * @see IPackageFragmentRoot
+ */
+ public boolean isArchive() {
+ return false;
+ }
+
+ /**
+ * @see IPackageFragmentRoot
+ */
+ public boolean isExternal() {
+ return false;
+ }
+
+ /**
+ * Recomputes the children of this element, based on the current state
+ * of the workbench.
+ */
+ public void refreshChildren() {
+ try {
+ OpenableElementInfo info = (OpenableElementInfo) getElementInfo();
+ computeChildren(info);
+ } catch (JavaModelException e) {
+ // do nothing.
+ }
+ }
+
+ /**
+ * Reset the array of non-java resources contained in the receiver to null.
+ */
+ public void resetNonJavaResources() throws JavaModelException {
+ ((PackageFragmentRootInfo) getElementInfo()).setNonJavaResources(null);
+ }
+
+ /**
+ * @private Debugging purposes
+ */
+ protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+ if (getElementName().length() == 0) {
+ buffer.append("[project root]");
+ } else {
+ buffer.append(getElementName());
+ }
+ if (info == null) {
+ buffer.append(" (not open)");
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRootInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRootInfo.java
new file mode 100644
index 0000000000..11b815cc28
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRootInfo.java
@@ -0,0 +1,147 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaModelException;
+
+import java.util.Enumeration;
+
+/**
+ * The element info for <code>PackageFragmentRoot</code>s.
+ */
+class PackageFragmentRootInfo extends OpenableElementInfo {
+
+ /**
+ * The kind of the root associated with this info.
+ * Valid kinds are: <ul>
+ * <li><code>IPackageFragmentRoot.K_SOURCE</code>
+ * <li><code>IPackageFragmentRoot.K_BINARY</code></ul>
+ */
+ protected int fRootKind = IPackageFragmentRoot.K_SOURCE;
+
+ /**
+ * A array with all the non-java resources contained by this PackageFragment
+ */
+ protected Object[] fNonJavaResources;
+ /**
+ * Create and initialize a new instance of the receiver
+ */
+ public PackageFragmentRootInfo() {
+ fNonJavaResources = null;
+ }
+
+ /**
+ * Starting at this folder, create non-java resources for this package fragment root
+ * and add them to the non-java resources collection.
+ *
+ * @exception JavaModelException The resource associated with this package fragment does not exist
+ */
+ private Object[] computeFolderNonJavaResources(
+ IJavaProject project,
+ IContainer folder)
+ throws JavaModelException {
+ Object[] nonJavaResources = new IResource[5];
+ int nonJavaResourcesCounter = 0;
+ try {
+ IResource[] members = folder.members();
+ for (int i = 0, max = members.length; i < max; i++) {
+ IResource member = members[i];
+ if (member.getType() == IResource.FILE) {
+ String extension = member.getProjectRelativePath().getFileExtension();
+ if (!"java".equalsIgnoreCase(extension)
+ && !"class".equalsIgnoreCase(extension)) {
+ if (project.findPackageFragmentRoot(member.getFullPath()) == null) {
+ if (nonJavaResources.length == nonJavaResourcesCounter) {
+ // resize
+ System.arraycopy(
+ nonJavaResources,
+ 0,
+ (nonJavaResources = new IResource[nonJavaResourcesCounter * 2]),
+ 0,
+ nonJavaResourcesCounter);
+ }
+ nonJavaResources[nonJavaResourcesCounter++] = member;
+ }
+ }
+ }
+ }
+ if (nonJavaResources.length != nonJavaResourcesCounter) {
+ System.arraycopy(
+ nonJavaResources,
+ 0,
+ (nonJavaResources = new IResource[nonJavaResourcesCounter]),
+ 0,
+ nonJavaResourcesCounter);
+ }
+ return nonJavaResources;
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ }
+ }
+
+ /**
+ * Compute the non-package resources of this package fragment root.
+ *
+ * @exception JavaModelException The resource associated with this package fragment root does not exist
+ */
+ private Object[] computeNonJavaResources(
+ IJavaProject project,
+ IResource underlyingResource) {
+ Object[] nonJavaResources = NO_NON_JAVA_RESOURCES;
+ try {
+ // the underlying resource may be a folder or a project (in the case that the project folder
+ // is actually the package fragment root)
+ if (underlyingResource.getType() == IResource.FOLDER
+ || underlyingResource.getType() == IResource.PROJECT) {
+ nonJavaResources =
+ computeFolderNonJavaResources(project, (IContainer) underlyingResource);
+ }
+ } catch (JavaModelException e) {
+ }
+ return nonJavaResources;
+ }
+
+ /**
+ * Returns an array of non-java resources contained in the receiver.
+ */
+ synchronized Object[] getNonJavaResources(
+ IJavaProject project,
+ IResource underlyingResource) {
+ Object[] nonJavaResources = fNonJavaResources;
+ if (nonJavaResources == null) {
+ nonJavaResources = this.computeNonJavaResources(project, underlyingResource);
+ fNonJavaResources = nonJavaResources;
+ }
+ return nonJavaResources;
+ }
+
+ /**
+ * Returns the kind of this root.
+ */
+ public int getRootKind() {
+ return fRootKind;
+ }
+
+ /**
+ * Set the fNonJavaResources to res value
+ */
+ synchronized void setNonJavaResources(Object[] resources) {
+ fNonJavaResources = resources;
+ }
+
+ /**
+ * Sets the kind of this root.
+ */
+ protected void setRootKind(int newRootKind) {
+ fRootKind = newRootKind;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Problem.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Problem.java
new file mode 100644
index 0000000000..28e6812e77
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Problem.java
@@ -0,0 +1,243 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.impl.*;
+
+public class Problem implements IProblem, ProblemSeverities, ProblemIrritants {
+ private char[] fileName;
+ private int id;
+ private int startPosition, endPosition, line;
+ private int severity;
+ private String[] arguments;
+ private String message;
+ public Problem(
+ char[] originatingFileName,
+ String message,
+ int id,
+ String[] stringArguments,
+ int severity,
+ int startPosition,
+ int endPosition,
+ int line) {
+
+ this.fileName = originatingFileName;
+ this.message = message;
+ this.id = id;
+ this.arguments = stringArguments;
+ this.severity = severity;
+ this.startPosition = startPosition;
+ this.endPosition = endPosition;
+ this.line = line;
+ }
+
+ public String errorReportSource(ICompilationUnit compilationUnit) {
+ //extra from the source the innacurate token
+ //and "highlight" it using some underneath ^^^^^
+ //put some context around too.
+
+ //this code assumes that the font used in the console is fixed size
+
+ //sanity .....
+ if ((startPosition > endPosition)
+ || ((startPosition <= 0) && (endPosition <= 0)))
+ return "\n!! no source information available !!";
+
+ //regular behavior....(slow code)
+
+ final int AROUND = 60; //increase this value to see more ....
+ final char SPACE = '\u0020';
+ final char MARK = '^';
+ final char TAB = '\t';
+ char[] source = compilationUnit.getContents();
+ //the next code tries to underline the token.....
+ //it assumes (for a good display) that token source does not
+ //contain any \r \n. This is false on statements !
+ //(the code still works but the display is not optimal !)
+
+ //compute the how-much-char we are displaying around the inaccurate token
+ int begin = startPosition >= source.length ? source.length - 1 : startPosition;
+ int relativeStart = 0;
+ int end = endPosition >= source.length ? source.length - 1 : endPosition;
+ int relativeEnd = 0;
+ label : for (relativeStart = 0;; relativeStart++) {
+ if (begin == 0)
+ break label;
+ if ((source[begin - 1] == '\n') || (source[begin - 1] == '\r'))
+ break label;
+ begin--;
+ }
+ label : for (relativeEnd = 0;; relativeEnd++) {
+ if ((end + 1) >= source.length)
+ break label;
+ if ((source[end + 1] == '\r') || (source[end + 1] == '\n')) {
+ break label;
+ }
+ end++;
+ }
+ //extract the message form the source
+ char[] extract = new char[end - begin + 1];
+ System.arraycopy(source, begin, extract, 0, extract.length);
+ char c;
+ //remove all SPACE and TAB that begin the error message...
+ int trimLeftIndex = 0;
+ while (((c = extract[trimLeftIndex++]) == TAB) || (c == SPACE)) {
+ };
+ System.arraycopy(
+ extract,
+ trimLeftIndex - 1,
+ extract = new char[extract.length - trimLeftIndex + 1],
+ 0,
+ extract.length);
+ relativeStart -= trimLeftIndex;
+ //buffer spaces and tabs in order to reach the error position
+ int pos = 0;
+ char[] underneath = new char[extract.length]; // can't be bigger
+ for (int i = 0; i <= relativeStart; i++) {
+ if (extract[i] == TAB) {
+ underneath[pos++] = TAB;
+ } else {
+ underneath[pos++] = SPACE;
+ }
+ }
+ //mark the error position
+ for (int i = startPosition;
+ i <= (endPosition >= source.length ? source.length - 1 : endPosition);
+ i++)
+ underneath[pos++] = MARK;
+ //resize underneathto remove 'null' chars
+ System.arraycopy(underneath, 0, underneath = new char[pos], 0, pos);
+
+ return " (at line " + String.valueOf(line) + ")" + //NON NLS
+ "\n\t" + new String(extract) + "\n\t" + new String(underneath);
+ }
+
+ /**
+ * Answer back the original arguments recorded into the problem.
+ * @return java.lang.String[]
+ */
+ public String[] getArguments() {
+ return arguments;
+ }
+
+ /**
+ * Answer the type of problem.
+ * @see com.ibm.compiler.java.problem.ProblemIrritants
+ * @return int
+ */
+ public int getID() {
+ return id;
+ }
+
+ /**
+ * Answer a localized, human-readable message string which describes the problem.
+ * @return java.lang.String
+ */
+ public String getMessage() {
+ return message;
+ }
+
+ /**
+ * Answer the file name in which the problem was found.
+ * @return char[]
+ */
+ public char[] getOriginatingFileName() {
+ return fileName;
+ }
+
+ /**
+ * Answer the severity of the problem.
+ * @return int
+ */
+ public int getSeverity() {
+ return severity;
+ }
+
+ /**
+ * Answer the end position of the problem (inclusive), or -1 if unknown.
+ * @return int
+ */
+ public int getSourceEnd() {
+ return endPosition;
+ }
+
+ /**
+ * Answer the line number in source where the problem begins.
+ * @return int
+ */
+ public int getSourceLineNumber() {
+ return line;
+ }
+
+ /**
+ * Answer the start position of the problem (inclusive), or -1 if unknown.
+ * @return int
+ */
+ public int getSourceStart() {
+ return startPosition;
+ }
+
+ /*
+ * Helper method: checks the severity to see if the Error bit is set.
+ * @return boolean
+ */
+ public boolean isError() {
+ return (severity & ProblemSeverities.Error) != 0;
+ }
+
+ /*
+ * Helper method: checks the severity to see if the Error bit is not set.
+ * @return boolean
+ */
+ public boolean isWarning() {
+ return (severity & ProblemSeverities.Error) == 0;
+ }
+
+ /**
+ * Set the end position of the problem (inclusive), or -1 if unknown.
+ *
+ * Used for shifting problem positions.
+ * @param sourceEnd the new value of the sourceEnd of the receiver
+ */
+ public void setSourceEnd(int sourceEnd) {
+ endPosition = sourceEnd;
+ }
+
+ /**
+ * Set the line number in source where the problem begins.
+ * @param lineNumber the new value of the line number of the receiver
+ */
+ public void setSourceLineNumber(int lineNumber) {
+ line = lineNumber;
+ }
+
+ /**
+ * Set the start position of the problem (inclusive), or -1 if unknown.
+ *
+ * Used for shifting problem positions.
+ * @param sourceStart the new value of the source start position of the receiver
+ */
+ public void setSourceStart(int sourceStart) {
+ startPosition = sourceStart;
+ }
+
+ public String toString() {
+
+ String s = "Pb(" + (id & IgnoreCategoriesMask) + ") ";
+ if (message != null) {
+ s += message;
+ } else {
+ if (arguments != null)
+ for (int i = 0; i < arguments.length; i++)
+ s += " " + arguments[i];
+ }
+ return s;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ProblemFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ProblemFactory.java
new file mode 100644
index 0000000000..79a7ba06c8
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ProblemFactory.java
@@ -0,0 +1,135 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+import java.text.*;
+import java.util.*;
+
+/**
+ * @see IProblemFactory
+ */
+public class ProblemFactory implements IProblemFactory {
+ private ResourceBundle compilerResources;
+ public String[] messageTemplates;
+ private Locale locale;
+ public ProblemFactory() {
+ this(Locale.getDefault());
+ }
+
+ /**
+ * @param loc the locale used to get the right message
+ */
+ public ProblemFactory(Locale loc) {
+ locale = loc;
+ compilerResources =
+ ResourceBundle.getBundle(
+ "org.eclipse.jdt.internal.compiler.problem.Messages",
+ loc);
+ //$NON-NLS-1$
+ initializeMessageTemplates();
+ }
+
+ /**
+ * Returns a new IProblem created according to the parameters value
+ * @param originatingFileName the name of the file name from which the problem is originated
+ * @param problemId the problem id
+ * @param arguments the arguments needed to set the error message
+ * @param severity the severity of the problem
+ * @param startPosition the starting position of the problem
+ * @param endPosition the end position of the problem
+ * @param lineNumber the line on which the problem occured
+ * @return com.ibm.compiler.java.api.IProblem
+ * @see IProblemFactory
+ */
+ public IProblem createProblem(
+ char[] originatingFileName,
+ int problemId,
+ String[] arguments,
+ int severity,
+ int startPosition,
+ int endPosition,
+ int lineNumber) {
+
+ return new Problem(
+ originatingFileName,
+ this.getLocalizedMessage(problemId, arguments),
+ problemId,
+ arguments,
+ severity,
+ startPosition,
+ endPosition,
+ lineNumber);
+ }
+
+ /**
+ * Returns the locale used to retrieve the error messages.
+ */
+ public Locale getLocale() {
+ return locale;
+ }
+
+ public final String getLocalizedMessage(int id, String[] problemArguments) {
+ StringBuffer output = new StringBuffer(80);
+ String message = messageTemplates[(id & ProblemIrritants.IgnoreCategoriesMask)];
+ if (message == null) {
+ return "Unable to retrieve the error message for problem id: "
+ + id
+ + ". Check compiler resources.";
+ }
+
+ int length = message.length();
+ int start = -1, end = length;
+ while (true) {
+ if ((end = message.indexOf('{', start)) > -1) {
+ output.append(message.substring(start + 1, end));
+ if ((start = message.indexOf('}', end)) > -1) {
+ try {
+ output.append(
+ problemArguments[Integer.parseInt(message.substring(end + 1, start))]);
+ } catch (NumberFormatException nfe) {
+ output.append(message.substring(end + 1, start + 1));
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return "Corrupted compiler resources for problem id: "
+ + (id & ProblemIrritants.IgnoreCategoriesMask)
+ + ". Check compiler resources.";
+ }
+ } else {
+ output.append(message.substring(end, length));
+ break;
+ }
+ } else {
+ output.append(message.substring(start + 1, length));
+ break;
+ }
+ }
+ return output.toString();
+ }
+
+ /**
+ * This method initializes the MessageTemplates class variable according
+ * to the current Locale.
+ */
+ public final void initializeMessageTemplates() {
+ messageTemplates = new String[500];
+ for (int i = 0; i < messageTemplates.length; i++) {
+ try {
+ messageTemplates[i] = compilerResources.getString(String.valueOf(i));
+ //$NON-NLS-1$
+ } catch (MissingResourceException e) {
+ }
+ }
+ }
+
+ /**
+ * @see IProblemFactory
+ */
+ public final String localizedMessage(Problem problem) {
+ return getLocalizedMessage(problem.getID(), problem.getArguments());
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Region.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Region.java
new file mode 100644
index 0000000000..b6b319e276
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Region.java
@@ -0,0 +1,154 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+/**
+ * @see IRegion
+ */
+
+public class Region implements IRegion {
+
+ /**
+ * A collection of the top level elements
+ * that have been added to the region
+ */
+ protected Vector fRootElements;
+ /**
+ * Creates an empty region.
+ *
+ * @see IRegion
+ */
+ public Region() {
+ fRootElements = new Vector(1);
+ }
+
+ /**
+ * @see IRegion#add(IJavaElement)
+ */
+ public void add(IJavaElement element) {
+ if (!contains(element)) {
+ //"new" element added to region
+ removeAllChildren(element);
+ fRootElements.addElement(element);
+ fRootElements.trimToSize();
+ }
+ }
+
+ /**
+ * @see IRegion
+ */
+ public boolean contains(IJavaElement element) {
+
+ int size = fRootElements.size();
+ Vector parents = getAncestors(element);
+
+ for (int i = 0; i < size; i++) {
+ IJavaElement aTop = (IJavaElement) fRootElements.elementAt(i);
+ if (aTop.equals(element)) {
+ return true;
+ }
+ for (int j = 0, pSize = parents.size(); j < pSize; j++) {
+ if (aTop.equals(parents.elementAt(j))) {
+ //an ancestor is already included
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns a collection of all the parents of this element
+ * in bottom-up order.
+ *
+ */
+ private Vector getAncestors(IJavaElement element) {
+ Vector parents = new Vector();
+ IJavaElement parent = element.getParent();
+ while (parent != null) {
+ parents.addElement(parent);
+ parent = parent.getParent();
+ }
+ parents.trimToSize();
+ return parents;
+ }
+
+ /**
+ * @see IRegion
+ */
+ public IJavaElement[] getElements() {
+ int size = fRootElements.size();
+ IJavaElement[] roots = new IJavaElement[size];
+ for (int i = 0; i < size; i++) {
+ roots[i] = (IJavaElement) fRootElements.elementAt(i);
+ }
+
+ return roots;
+ }
+
+ /**
+ * @see IRegion#remove(IJavaElement)
+ */
+ public boolean remove(IJavaElement element) {
+
+ removeAllChildren(element);
+ return fRootElements.removeElement(element);
+ }
+
+ /**
+ * Removes any children of this element that are contained within this
+ * region as this parent is about to be added to the region.
+ *
+ * <p>Children are all children, not just direct children.
+ */
+ private void removeAllChildren(IJavaElement element) {
+ if (element instanceof IParent) {
+ Vector newRootElements = new Vector();
+ for (int i = 0, size = fRootElements.size(); i < size; i++) {
+ IJavaElement currentRoot = (IJavaElement) fRootElements.elementAt(i);
+ //walk the current root hierarchy
+ IJavaElement parent = currentRoot.getParent();
+ boolean isChild = false;
+ while (parent != null) {
+ if (parent.equals(element)) {
+ isChild = true;
+ break;
+ }
+ parent = parent.getParent();
+ }
+ if (!isChild) {
+ newRootElements.addElement(currentRoot);
+ }
+ }
+ fRootElements = newRootElements;
+ }
+ }
+
+ /**
+ * Returns a printable representation of this region.
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ IJavaElement[] roots = getElements();
+ buffer.append('[');
+ for (int i = 0; i < roots.length; i++) {
+ buffer.append(roots[i].getElementName());
+ if (i < (roots.length - 1)) {
+ buffer.append(", ");
+ }
+ }
+ buffer.append(']');
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/RenameElementsOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/RenameElementsOperation.java
new file mode 100644
index 0000000000..0c4a6d580a
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/RenameElementsOperation.java
@@ -0,0 +1,89 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaModelStatus;
+import org.eclipse.jdt.core.IJavaModelStatusConstants;
+import org.eclipse.jdt.core.IMethod;
+import org.eclipse.jdt.core.ISourceReference;
+import org.eclipse.jdt.core.JavaModelException;
+
+/**
+ * This operation renames elements.
+ *
+ * <p>Notes:<ul>
+ * <li>Resource rename is not supported - this operation only renames
+ * elements contained in compilation units.
+ * <li>When a main type is renamed, its compilation unit and constructors are renamed.
+ * <li>Constructors cannot be renamed.
+ * </ul>
+ */
+public class RenameElementsOperation extends MoveElementsOperation {
+ /**
+ * When executed, this operation will rename the specified elements with the given names in the
+ * corresponding destinations.
+ */
+ public RenameElementsOperation(
+ IJavaElement[] elements,
+ IJavaElement[] destinations,
+ String[] newNames,
+ boolean force) {
+ //a rename is a move to the same parent with a new name specified
+ //these elements are from different parents
+ super(elements, destinations, force);
+ setRenamings(newNames);
+ }
+
+ /**
+ * @see MultiOperation
+ */
+ protected String getMainTaskName() {
+ return "Renaming elements...";
+ }
+
+ /**
+ * @see CopyElementsOperation#isRename()
+ */
+ protected boolean isRename() {
+ return true;
+ }
+
+ /**
+ * @see MultiOperation
+ */
+ protected IJavaModelStatus verify() {
+ IJavaModelStatus status = super.verify();
+ if (!status.isOK())
+ return status;
+ if (fRenamingsList == null || fRenamingsList.length == 0)
+ return new JavaModelStatus(IJavaModelStatusConstants.NULL_NAME);
+ return JavaModelStatus.VERIFIED_OK;
+ }
+
+ /**
+ * @see MultiOperation
+ */
+ protected void verify(IJavaElement element) throws JavaModelException {
+ int elementType = element.getElementType();
+
+ if (element == null || !element.exists())
+ error(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, element);
+
+ if (element.isReadOnly())
+ error(IJavaModelStatusConstants.READ_ONLY, element);
+
+ if (!(element instanceof ISourceReference))
+ error(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element);
+
+ if (elementType < IJavaElement.TYPE || elementType == IJavaElement.INITIALIZER)
+ error(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element);
+
+ verifyRenaming(element);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/RenameResourceElementsOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/RenameResourceElementsOperation.java
new file mode 100644
index 0000000000..c5a9371033
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/RenameResourceElementsOperation.java
@@ -0,0 +1,74 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaModelStatusConstants;
+import org.eclipse.jdt.core.JavaModelException;
+
+/**
+ * This operation renames resources (Package fragments and compilation units).
+ *
+ * <p>Notes:<ul>
+ * <li>When a compilation unit is renamed, its main type and the constructors of the
+ * main type are renamed.
+ * </ul>
+ */
+public class RenameResourceElementsOperation
+ extends MoveResourceElementsOperation {
+ /**
+ * When executed, this operation will rename the specified elements with the given names in the
+ * corresponding destinations.
+ */
+ public RenameResourceElementsOperation(
+ IJavaElement[] elements,
+ IJavaElement[] destinations,
+ String[] newNames,
+ boolean force) {
+ //a rename is a move to the same parent with a new name specified
+ //these elements are from different parents
+ super(elements, destinations, force);
+ setRenamings(newNames);
+ }
+
+ /**
+ * @see MultiOperation
+ */
+ protected String getMainTaskName() {
+ return "Renaming resources...";
+ }
+
+ /**
+ * @see CopyResourceElementsOperation#isRename()
+ */
+ protected boolean isRename() {
+ return true;
+ }
+
+ /**
+ * @see MultiOperation
+ */
+ protected void verify(IJavaElement element) throws JavaModelException {
+ super.verify(element);
+
+ String newName = getNewNameFor(element);
+ int elementType = element.getElementType();
+
+ if (!(elementType == IJavaElement.COMPILATION_UNIT
+ || elementType == IJavaElement.PACKAGE_FRAGMENT)) {
+ error(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element);
+ }
+ if (elementType == IJavaElement.COMPILATION_UNIT) {
+ if (((ICompilationUnit) element).isWorkingCopy()) {
+ error(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element);
+ }
+ }
+ verifyRenaming(element);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java
new file mode 100644
index 0000000000..0a74f4e827
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java
@@ -0,0 +1,360 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.*;
+import org.eclipse.core.resources.*;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+import org.eclipse.jdt.internal.codeassist.*;
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+
+/**
+ * This class provides a <code>SearchableBuilderEnvironment</code> for code assist which
+ * uses the Java model as a search tool.
+ */
+
+public class SearchableEnvironment
+ implements ISearchableNameEnvironment, IJavaSearchConstants {
+ protected NameLookup nameLookup;
+ protected ICompilationUnit unitToSkip;
+ public CompilationUnit unitToLookInside;
+
+ protected IJavaProject project;
+ /**
+ * Creates a SearchableEnvironment on the given project
+ */
+ public SearchableEnvironment(IJavaProject project) throws JavaModelException {
+ this.project = project;
+ this.nameLookup = (NameLookup) ((JavaProject) project).getNameLookup();
+ }
+
+ /**
+ * Returns the given type in the the given package if it exists,
+ * otherwise <code>null</code>.
+ */
+ protected NameEnvironmentAnswer find(String typeName, String packageName) {
+ if (packageName == null)
+ packageName = IPackageFragment.DEFAULT_PACKAGE_NAME;
+ IType type =
+ this.nameLookup.findType(
+ typeName,
+ packageName,
+ false,
+ INameLookup.ACCEPT_CLASSES | INameLookup.ACCEPT_INTERFACES);
+ if (type == null) {
+ // look inside the compilation unit that is being searched currently
+ //for a non-public or inner type.
+ if (this.unitToLookInside != null) {
+ if (this.unitToLookInside.getParent().getElementName().equals(packageName)) {
+ try {
+ IType[] allTypes = this.unitToLookInside.getTypes();
+ for (int i = 0; i < allTypes.length; i++) {
+ if (allTypes[i].getElementName().equals(typeName)) {
+ type = allTypes[i];
+ break;
+ }
+ }
+ } catch (JavaModelException e) {
+ }
+ }
+ }
+ }
+ if (type != null) {
+ if (type instanceof BinaryType) {
+ try {
+ return new NameEnvironmentAnswer(
+ (IBinaryType) ((BinaryType) type).getRawInfo());
+ } catch (JavaModelException npe) {
+ return null;
+ }
+ } else { //SourceType
+ try {
+ return new NameEnvironmentAnswer(
+ (ISourceType) ((SourceType) type).getRawInfo());
+ } catch (JavaModelException npe) {
+ return null;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @see SearchableBuilderEnvironment
+ */
+ public void findPackages(char[] prefix, ISearchRequestor requestor) {
+ this.nameLookup.seekPackageFragments(
+ new String(prefix),
+ true,
+ new SearchableEnvironmentRequestor(requestor));
+ }
+
+ /**
+ * @see INameEnvironment
+ */
+ public NameEnvironmentAnswer findType(char[][] compoundTypeName) {
+ if (compoundTypeName == null)
+ return null;
+ int length = compoundTypeName.length;
+ if (length == 1)
+ return find(new String(compoundTypeName[0]), null);
+ StringBuffer buffer = new StringBuffer(length * 6);
+ int lengthM1 = length - 1;
+ for (int i = 0; i < lengthM1; i++) {
+ buffer.append(compoundTypeName[i]);
+ if (i + 1 != lengthM1)
+ buffer.append(".");
+ }
+ String className = new String(compoundTypeName[lengthM1]);
+ return find(className, buffer.toString());
+ }
+
+ /**
+ * @see INameEnvironment
+ */
+ public NameEnvironmentAnswer findType(char[] name, char[][] packages) {
+ if (name == null)
+ return null;
+
+ if (packages == null || packages.length == 0)
+ return find(new String(name), null);
+
+ int length = packages.length;
+ StringBuffer buffer = new StringBuffer(length * 6);
+ for (int i = 0; i < length; i++) {
+ buffer.append(packages[i]);
+ if (i + 1 != length)
+ buffer.append(".");
+ }
+ String className = new String(name);
+ return find(className, buffer.toString());
+ }
+
+ /**
+ * @see ISearchableNameEnvironment
+ */
+ public void findTypes(char[] prefix, final ISearchRequestor storage) {
+
+ /*
+ if (true){
+ findTypes(new String(prefix), storage, INameLookup.ACCEPT_CLASSES | INameLookup.ACCEPT_INTERFACES);
+ return;
+ }
+ */
+ try {
+ final String excludePath;
+ if (this.unitToSkip != null) {
+ if (!(this.unitToSkip instanceof IJavaElement)) {
+ // revert to model investigation
+ findTypes(
+ new String(prefix),
+ storage,
+ INameLookup.ACCEPT_CLASSES | INameLookup.ACCEPT_INTERFACES);
+ return;
+ }
+ excludePath =
+ ((IJavaElement) this.unitToSkip)
+ .getUnderlyingResource()
+ .getFullPath()
+ .toString();
+ } else {
+ excludePath = null;
+ }
+ int lastDotIndex = CharOperation.lastIndexOf('.', prefix);
+ char[] qualification, simpleName;
+ if (lastDotIndex < 0) {
+ qualification = null;
+ simpleName = CharOperation.toLowerCase(prefix);
+ } else {
+ qualification = CharOperation.subarray(prefix, 0, lastDotIndex);
+ simpleName =
+ CharOperation.toLowerCase(
+ CharOperation.subarray(prefix, lastDotIndex + 1, prefix.length));
+ }
+
+ SearchEngine searchEngine = new SearchEngine();
+
+ IProject projectRsc = (IProject) this.project.getUnderlyingResource();
+ IJavaSearchScope scope =
+ searchEngine.createJavaSearchScope(new IResource[] { projectRsc });
+
+ IProgressMonitor progressMonitor = new IProgressMonitor() {
+ boolean isCanceled = false;
+ public void beginTask(String name, int totalWork) {
+ }
+ public void done() {
+ }
+ public void internalWorked(double work) {
+ }
+ public boolean isCanceled() {
+ return isCanceled;
+ }
+ public void setCanceled(boolean value) {
+ isCanceled = value;
+ }
+ public void setTaskName(String name) {
+ }
+ public void subTask(String name) {
+ }
+ public void worked(int work) {
+ }
+ };
+ ITypeNameRequestor nameRequestor = new ITypeNameRequestor() {
+ public void acceptClass(
+ char[] packageName,
+ char[] simpleTypeName,
+ char[][] enclosingTypeNames,
+ String path) {
+ if (excludePath != null && excludePath.equals(path))
+ return;
+ if (enclosingTypeNames != null && enclosingTypeNames.length > 0)
+ return; // accept only top level types
+ storage.acceptClass(packageName, simpleTypeName, 0);
+ }
+ public void acceptInterface(
+ char[] packageName,
+ char[] simpleTypeName,
+ char[][] enclosingTypeNames,
+ String path) {
+ if (excludePath != null && excludePath.equals(path))
+ return;
+ if (enclosingTypeNames != null && enclosingTypeNames.length > 0)
+ return; // accept only top level types
+ storage.acceptInterface(packageName, simpleTypeName, 0);
+ }
+ };
+ try {
+ searchEngine.searchAllTypeNames(
+ projectRsc.getWorkspace(),
+ qualification,
+ simpleName,
+ PREFIX_MATCH,
+ CASE_INSENSITIVE,
+ IJavaSearchConstants.TYPE,
+ scope,
+ nameRequestor,
+ CANCEL_IF_NOT_READY_TO_SEARCH,
+ progressMonitor);
+ } catch (OperationCanceledException e) {
+ findTypes(
+ new String(prefix),
+ storage,
+ INameLookup.ACCEPT_CLASSES | INameLookup.ACCEPT_INTERFACES);
+ }
+ } catch (JavaModelException e) {
+ findTypes(
+ new String(prefix),
+ storage,
+ INameLookup.ACCEPT_CLASSES | INameLookup.ACCEPT_INTERFACES);
+ }
+ }
+
+ /**
+ * Returns all types whose name starts with the given (qualified) <code>prefix</code>.
+ *
+ * If the <code>prefix</code> is unqualified, all types whose simple name matches
+ * the <code>prefix</code> are returned.
+ */
+ private void findTypes(String prefix, ISearchRequestor storage, int type) {
+ SearchableEnvironmentRequestor requestor =
+ new SearchableEnvironmentRequestor(storage, this.unitToSkip);
+ int index = prefix.lastIndexOf('.');
+ if (index == -1) {
+ this.nameLookup.seekTypes(prefix, null, true, type, requestor);
+ } else {
+ String packageName = prefix.substring(0, index);
+ String className = prefix.substring(index + 1);
+ JavaElementRequestor javaElementRequestor = new JavaElementRequestor();
+ this.nameLookup.seekPackageFragments(packageName, false, javaElementRequestor);
+ IPackageFragment[] packageFragments =
+ javaElementRequestor.getPackageFragments();
+ if (packageFragments == null)
+ return;
+ for (int i = 0, packagesLength = packageFragments.length;
+ i < packagesLength;
+ i++) {
+ if (packageFragments[i] == null)
+ continue;
+ this.nameLookup.seekTypes(
+ className,
+ packageFragments[i],
+ true,
+ type,
+ requestor);
+ }
+ }
+ }
+
+ /**
+ * @see SearchableBuilderEnvironment
+ */
+ public boolean isPackage(char[][] parentPackageName, char[] subPackageName) {
+ if (parentPackageName == null || parentPackageName.length == 0)
+ return isTopLevelPackage(subPackageName);
+ if (subPackageName == null)
+ return false;
+ int length = parentPackageName.length;
+ StringBuffer buffer = new StringBuffer((length + 1) * 6);
+ for (int i = 0; i < length; i++) {
+ if (parentPackageName[i] == null || isQualified(parentPackageName[i]))
+ return false;
+ buffer.append(parentPackageName[i]);
+ buffer.append(".");
+ }
+ if (isQualified(subPackageName)) {
+ return false;
+ }
+ buffer.append(subPackageName);
+ boolean result =
+ this.nameLookup.findPackageFragments(buffer.toString(), false) != null;
+ return result;
+
+ }
+
+ /**
+ * Returns true if there are no '.' characters in the given name.
+ */
+ protected boolean isQualified(char[] name) {
+ if (name != null) {
+ return CharOperation.indexOf('.', name) > -1;
+ }
+ return false;
+ }
+
+ /**
+ * @see SearchableBuilderEnvironment
+ */
+ public boolean isTopLevelPackage(char[] packageName) {
+ if (packageName == null)
+ return false;
+ boolean result =
+ !isQualified(packageName)
+ && this.nameLookup.findPackageFragments(new String(packageName), false) != null;
+ return result;
+
+ }
+
+ /**
+ * Returns a printable string for the array.
+ */
+ protected String toStringChar(char[] name) {
+ return "[" + new String(name) + "]";
+ }
+
+ /**
+ * Returns a printable string for the array.
+ */
+ protected String toStringCharChar(char[][] names) {
+ StringBuffer result = new StringBuffer();
+ for (int i = 0; i < names.length; i++) {
+ result.append(toStringChar(names[i]));
+ }
+ return result.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironmentRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironmentRequestor.java
new file mode 100644
index 0000000000..b979876025
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironmentRequestor.java
@@ -0,0 +1,92 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.codeassist.ISearchRequestor;
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+import org.eclipse.jdt.core.IInitializer;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.JavaModelException;
+
+/**
+ * Implements <code>IJavaElementRequestor</code>, wrappering and forwarding
+ * results onto a <code>org.eclipse.jdt.internal.codeassist.api.ISearchRequestor</code>.
+ */
+class SearchableEnvironmentRequestor
+ extends JavaElementRequestor
+ implements IJavaElementRequestor {
+ /**
+ * The <code>ISearchRequestor</code> this JavaElementRequestor wraps
+ * and forwards results to.
+ */
+ protected ISearchRequestor fRequestor;
+ /**
+ * The <code>ICompilationUNit</code> this JavaElementRequestor will not
+ * accept types within.
+ */
+ protected ICompilationUnit fUnitToSkip;
+ /**
+ * Constructs a SearchableEnvironmentRequestor that wraps the
+ * given SearchRequestor.
+ */
+ public SearchableEnvironmentRequestor(ISearchRequestor requestor) {
+ fRequestor = requestor;
+ fUnitToSkip = null;
+ }
+
+ /**
+ * Constructs a SearchableEnvironmentRequestor that wraps the
+ * given SearchRequestor. The requestor will not accept types in
+ * the <code>unitToSkip</code>.
+ */
+ public SearchableEnvironmentRequestor(
+ ISearchRequestor requestor,
+ ICompilationUnit unitToSkip) {
+ fRequestor = requestor;
+ fUnitToSkip = unitToSkip;
+ }
+
+ /**
+ * Do nothing, a SearchRequestor does not accept initializers
+ * so there is no need to forward this results.
+ *
+ * @see IJavaElementRequestor
+ */
+ public void acceptInitializer(IInitializer initializer) {
+
+ }
+
+ /**
+ * @see IJavaElementRequestor
+ */
+ public void acceptPackageFragment(IPackageFragment packageFragment) {
+ fRequestor.acceptPackage(packageFragment.getElementName().toCharArray());
+ }
+
+ /**
+ * @see IJavaElementRequestor
+ */
+ public void acceptType(IType type) {
+ try {
+ if (fUnitToSkip != null && fUnitToSkip.equals(type.getCompilationUnit())) {
+ return;
+ }
+ if (type.isClass()) {
+ fRequestor.acceptClass(
+ type.getPackageFragment().getElementName().toCharArray(),
+ type.getElementName().toCharArray(),
+ type.getFlags());
+ } else {
+ fRequestor.acceptInterface(
+ type.getPackageFragment().getElementName().toCharArray(),
+ type.getElementName().toCharArray(),
+ type.getFlags());
+ }
+ } catch (JavaModelException npe) {
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SelectionRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SelectionRequestor.java
new file mode 100644
index 0000000000..3a48ffc6a4
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SelectionRequestor.java
@@ -0,0 +1,317 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.resources.*;
+import org.eclipse.jdt.internal.compiler.IProblem;
+import org.eclipse.jdt.internal.codeassist.ISelectionRequestor;
+import org.eclipse.jdt.internal.codeassist.SelectionEngine;
+import org.eclipse.jdt.core.*;
+
+/**
+ * Implementation of <code>ISelectionRequestor</code> to assist with
+ * code resolve in a compilation unit. Translates names to elements.
+ */
+public class SelectionRequestor implements ISelectionRequestor {
+ /**
+ * The name lookup facility used to resolve packages
+ */
+ protected INameLookup fNameLookup = null;
+
+ /**
+ * Fix for 1FVXGDK
+ *
+ * The compilation unit we are resolving in
+ */
+ protected IJavaElement fCodeResolve;
+
+ /**
+ * The collection of resolved elements.
+ */
+ protected IJavaElement[] fElements = fgEmptyElements;
+
+ /**
+ * Empty collection used for efficiency.
+ */
+ protected static IJavaElement[] fgEmptyElements = new IJavaElement[] {
+ };
+
+ /**
+ * Creates a selection requestor that uses that given
+ * name lookup facility to resolve names.
+ *
+ * Fix for 1FVXGDK
+ */
+ public SelectionRequestor(INameLookup nameLookup, IJavaElement codeResolve) {
+ super();
+ fNameLookup = nameLookup;
+ fCodeResolve = codeResolve;
+ }
+
+ /**
+ * Resolve the binary method
+ *
+ * fix for 1FWFT6Q
+ */
+ protected void acceptBinaryMethod(
+ IType type,
+ char[] selector,
+ char[][] parameterPackageNames,
+ char[][] parameterTypeNames) {
+ String[] parameterTypes = null;
+ if (parameterTypeNames != null) {
+ parameterTypes = new String[parameterTypeNames.length];
+ for (int i = 0, max = parameterTypeNames.length; i < max; i++) {
+ String pkg = IPackageFragment.DEFAULT_PACKAGE_NAME;
+ if (parameterPackageNames[i] != null && parameterPackageNames[i].length > 0) {
+ pkg = new String(parameterPackageNames[i]) + ".";
+ }
+ parameterTypes[i] =
+ Signature.createTypeSignature(pkg + new String(parameterTypeNames[i]), true);
+ }
+ }
+ IMethod method = type.getMethod(new String(selector), parameterTypes);
+ if (method.exists()) {
+ fElements = growAndAddToArray(fElements, method);
+ }
+ }
+
+ /**
+ * Resolve the class.
+ */
+ public void acceptClass(
+ char[] packageName,
+ char[] className,
+ boolean needQualification) {
+ acceptType(
+ packageName,
+ className,
+ INameLookup.ACCEPT_CLASSES,
+ needQualification);
+ }
+
+ /**
+ * Do nothing.
+ */
+ public void acceptError(IProblem error) {
+ }
+
+ /**
+ * Resolve the field.
+ */
+ public void acceptField(
+ char[] declaringTypePackageName,
+ char[] declaringTypeName,
+ char[] name) {
+ IType type =
+ resolveType(
+ declaringTypePackageName,
+ declaringTypeName,
+ INameLookup.ACCEPT_CLASSES | INameLookup.ACCEPT_INTERFACES);
+ if (type != null) {
+ IField field = type.getField(new String(name));
+ if (field.exists()) {
+ fElements = growAndAddToArray(fElements, field);
+ }
+ }
+ }
+
+ /**
+ * Resolve the interface
+ */
+ public void acceptInterface(
+ char[] packageName,
+ char[] interfaceName,
+ boolean needQualification) {
+ acceptType(
+ packageName,
+ interfaceName,
+ INameLookup.ACCEPT_INTERFACES,
+ needQualification);
+ }
+
+ /**
+ * Resolve the method
+ */
+ public void acceptMethod(
+ char[] declaringTypePackageName,
+ char[] declaringTypeName,
+ char[] selector,
+ char[][] parameterPackageNames,
+ char[][] parameterTypeNames) {
+ IType type =
+ resolveType(
+ declaringTypePackageName,
+ declaringTypeName,
+ INameLookup.ACCEPT_CLASSES | INameLookup.ACCEPT_INTERFACES);
+ // fix for 1FWFT6Q
+ if (type != null) {
+ if (type.isBinary()) {
+ acceptBinaryMethod(type, selector, parameterPackageNames, parameterTypeNames);
+ } else {
+ acceptSourceMethod(type, selector, parameterPackageNames, parameterTypeNames);
+ }
+ }
+ }
+
+ /**
+ * Resolve the package
+ */
+ public void acceptPackage(char[] packageName) {
+ IPackageFragment[] pkgs =
+ fNameLookup.findPackageFragments(new String(packageName), false);
+ if (pkgs != null) {
+ for (int i = 0, length = pkgs.length; i < length; i++) {
+ fElements = growAndAddToArray(fElements, pkgs[i]);
+ }
+ }
+ }
+
+ /**
+ * Resolve the source method
+ *
+ * fix for 1FWFT6Q
+ */
+ protected void acceptSourceMethod(
+ IType type,
+ char[] selector,
+ char[][] parameterPackageNames,
+ char[][] parameterTypeNames) {
+ String name = new String(selector);
+ IMethod[] methods = null;
+ try {
+ methods = type.getMethods();
+ } catch (JavaModelException e) {
+ return;
+ }
+ IJavaElement[] matches = new IJavaElement[] {
+ };
+ for (int i = 0; i < methods.length; i++) {
+ if (methods[i].getElementName().equals(name)
+ && methods[i].getParameterTypes().length == parameterTypeNames.length) {
+ matches = growAndAddToArray(matches, methods[i]);
+ }
+ }
+
+ // if no matches, nothing to report
+ if (matches.length == 0) {
+ return;
+ }
+
+ // if there is only one match, we've got it
+ if (matches.length == 1) {
+ fElements = growAndAddToArray(fElements, matches[0]);
+ return;
+ }
+
+ // more than one match - must match simple parameter types
+ for (int i = 0; i < matches.length; i++) {
+ IMethod method = (IMethod) matches[i];
+ String[] signatures = method.getParameterTypes();
+ boolean match = true;
+ for (int p = 0; p < signatures.length; p++) {
+ String simpleName = Signature.getSimpleName(Signature.toString(signatures[p]));
+ if (!simpleName.equals(new String(parameterTypeNames[p]))) {
+ match = false;
+ break;
+ }
+ }
+ if (match) {
+ fElements = growAndAddToArray(fElements, method);
+ }
+ }
+
+ }
+
+ /**
+ * Resolve the type, adding to the resolved elements.
+ */
+ protected void acceptType(
+ char[] packageName,
+ char[] typeName,
+ int acceptFlags,
+ boolean needQualification) {
+ IType type = resolveType(packageName, typeName, acceptFlags);
+ if (type != null) {
+ fElements = growAndAddToArray(fElements, type);
+ }
+
+ }
+
+ /**
+ * Returns the resolved elements.
+ */
+ public IJavaElement[] getElements() {
+ return fElements;
+ }
+
+ /**
+ * Adds the new element to a new array that contains all of the elements of the old array.
+ * Returns the new array.
+ */
+ protected IJavaElement[] growAndAddToArray(
+ IJavaElement[] array,
+ IJavaElement addition) {
+ IJavaElement[] old = array;
+ array = new IJavaElement[old.length + 1];
+ System.arraycopy(old, 0, array, 0, old.length);
+ array[old.length] = addition;
+ return array;
+ }
+
+ /**
+ * Resolve the type
+ */
+ protected IType resolveType(
+ char[] packageName,
+ char[] typeName,
+ int acceptFlags) {
+ //fix for 1FVXGDK
+ IType type = null;
+ if (packageName == null || packageName.length == 0) {
+ // default package
+ type = fNameLookup.findType(new String(typeName), false, acceptFlags);
+ } else {
+ IPackageFragment[] pkgs =
+ fNameLookup.findPackageFragments(new String(packageName), false);
+ if (pkgs != null) {
+ for (int i = 0, length = pkgs.length; i < length; i++) {
+ type = fNameLookup.findType(new String(typeName), pkgs[i], false, acceptFlags);
+ if (type != null)
+ break;
+ }
+ }
+ }
+ if (type == null) {
+ String pName = IPackageFragment.DEFAULT_PACKAGE_NAME;
+ if (packageName != null) {
+ pName = new String(packageName);
+ }
+ if (fCodeResolve != null
+ && fCodeResolve.getParent().getElementName().equals(pName)) {
+ // look inside the type in which we are resolving in
+ String tName = new String(typeName);
+ tName = tName.replace('.', '$');
+ IType[] allTypes = null;
+ try {
+ java.util.Vector v =
+ ((JavaElement) fCodeResolve).getChildrenOfType(IJavaElement.TYPE);
+ allTypes = new IType[v.size()];
+ v.copyInto(allTypes);
+ } catch (JavaModelException e) {
+ return null;
+ }
+ for (int i = 0; i < allTypes.length; i++) {
+ if (allTypes[i].getTypeQualifiedName().equals(tName)) {
+ return allTypes[i];
+ }
+ }
+ }
+ }
+ return type;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetClasspathOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetClasspathOperation.java
new file mode 100644
index 0000000000..323fc06bbd
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetClasspathOperation.java
@@ -0,0 +1,256 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.jdt.core.*;
+
+/**
+ * This operation sets an <code>IJavaProject</code>'s classpath.
+ *
+ * @see IJavaProject
+ */
+public class SetClasspathOperation extends JavaModelOperation {
+ IClasspathEntry[] oldResolvedPath;
+ IClasspathEntry[] newRawPath;
+ boolean saveClasspath;
+ /**
+ * When executed, this operation sets the classpath of the given project.
+ */
+ public SetClasspathOperation(
+ IJavaProject project,
+ IClasspathEntry[] oldResolvedPath,
+ IClasspathEntry[] newRawPath,
+ boolean saveClasspath) {
+ super(new IJavaElement[] { project });
+ this.oldResolvedPath = oldResolvedPath;
+ this.newRawPath = newRawPath;
+ this.saveClasspath = saveClasspath;
+ }
+
+ /**
+ * Adds deltas for the given roots, with the specified change flag,
+ * and closes the root. Helper method for #setClasspath
+ */
+ protected void addDeltas(
+ IPackageFragmentRoot[] roots,
+ int flag,
+ JavaElementDelta delta) {
+ for (int i = 0; i < roots.length; i++) {
+ IPackageFragmentRoot root = roots[i];
+ delta.changed(root, flag);
+ try {
+ root.close();
+ } catch (JavaModelException e) {
+ }
+ }
+ }
+
+ /**
+ * Returns the index of the item in the list if the given list contains the specified entry. If the list does
+ * not contain the entry, -1 is returned.
+ * A helper method for #setClasspath
+ */
+ protected int classpathContains(
+ IClasspathEntry[] list,
+ IClasspathEntry entry) {
+ for (int i = 0; i < list.length; i++) {
+ if (list[i].equals(entry)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Sets the classpath of the pre-specified project.
+ */
+ protected void executeOperation() throws JavaModelException {
+ beginTask("Setting classpath...", 2);
+ JavaProject project = ((JavaProject) getElementsToProcess()[0]);
+
+ project.setRawClasspath0(this.newRawPath);
+
+ // change builder specs to build in the order given by the new classpath
+ JavaModelManager manager = project.getJavaModelManager();
+ manager.setBuildOrder(
+ ((JavaModel) project.getJavaModel()).computeBuildOrder(true));
+
+ if (this.oldResolvedPath != null) {
+ generateClasspathChangeDeltas(
+ this.oldResolvedPath,
+ project.getResolvedClasspath(true),
+ manager,
+ project);
+ } else {
+ project.saveClasspath(this.saveClasspath);
+ }
+
+ done();
+ }
+
+ /**
+ * Generates the delta of removed/added/reordered roots.
+ * Use three deltas in case the same root is removed/added/reordered (i.e. changed from
+ * K_SOURCE to K_BINARY or visa versa)
+ */
+ protected void generateClasspathChangeDeltas(
+ IClasspathEntry[] oldResolvedPath,
+ IClasspathEntry[] newResolvedPath,
+ JavaModelManager manager,
+ JavaProject project) {
+
+ boolean hasChangedSourceEntries = false;
+
+ JavaElementDelta delta = new JavaElementDelta(getJavaModel());
+ boolean hasDelta = false;
+ boolean oldResolvedPathLongest =
+ oldResolvedPath.length >= newResolvedPath.length;
+ for (int i = 0; i < oldResolvedPath.length; i++) {
+ int index = classpathContains(newResolvedPath, oldResolvedPath[i]);
+ if (index == -1) {
+ IPackageFragmentRoot[] pkgFragmentRoots =
+ project.getPackageFragmentRoots(oldResolvedPath[i]);
+ addDeltas(pkgFragmentRoots, IJavaElementDelta.F_REMOVED_FROM_CLASSPATH, delta);
+ hasChangedSourceEntries |= oldResolvedPath[i].getEntryKind()
+ == IClasspathEntry.CPE_SOURCE;
+ // force detach source on jar package fragment roots (source will be lazily computed when needed)
+ for (int j = 0, length = pkgFragmentRoots.length; j < length; j++) {
+ IPackageFragmentRoot root = pkgFragmentRoots[j];
+ if (root instanceof JarPackageFragmentRoot) {
+ JarPackageFragmentRoot jarRoot = (JarPackageFragmentRoot) root;
+ try {
+ jarRoot.getWorkspace().getRoot().setPersistentProperty(
+ jarRoot.getSourceAttachmentPropertyName(),
+ null);
+ // loose info - will be recomputed
+ } catch (CoreException ce) {
+ }
+ }
+ }
+
+ hasDelta = true;
+ } else
+ if (oldResolvedPathLongest && index != i) { //reordering of the classpath
+ addDeltas(
+ project.getPackageFragmentRoots(oldResolvedPath[i]),
+ IJavaElementDelta.F_CLASSPATH_REORDER,
+ delta);
+ hasChangedSourceEntries |= oldResolvedPath[i].getEntryKind()
+ == IClasspathEntry.CPE_SOURCE;
+ hasDelta = true;
+ }
+ }
+
+ for (int i = 0; i < newResolvedPath.length; i++) {
+ int index = classpathContains(oldResolvedPath, newResolvedPath[i]);
+ if (index == -1) {
+ addDeltas(
+ project.getPackageFragmentRoots(newResolvedPath[i]),
+ IJavaElementDelta.F_ADDED_TO_CLASSPATH,
+ delta);
+ hasChangedSourceEntries |= newResolvedPath[i].getEntryKind()
+ == IClasspathEntry.CPE_SOURCE;
+ hasDelta = true;
+ } else
+ if (!oldResolvedPathLongest && index != i) { //reordering of the classpath
+ addDeltas(
+ project.getPackageFragmentRoots(newResolvedPath[i]),
+ IJavaElementDelta.F_CLASSPATH_REORDER,
+ delta);
+ hasChangedSourceEntries |= newResolvedPath[i].getEntryKind()
+ == IClasspathEntry.CPE_SOURCE;
+ hasDelta = true;
+ }
+ }
+ if (hasDelta) {
+ try {
+ project.saveClasspath(this.saveClasspath);
+ } catch (JavaModelException e) {
+ }
+ this.addDelta(delta);
+ // loose all built state - next build will be a full one
+ manager.setLastBuiltState(project.getProject(), null);
+
+ if (hasChangedSourceEntries)
+ updateAffectedProjects(project.getProject().getFullPath());
+ }
+ }
+
+ /**
+ * Possible failures: <ul>
+ * <li>NO_ELEMENTS_TO_PROCESS - the project supplied to the operation is
+ * <code>null</code>.
+ * <li>NULL_PATH - the output location path supplied to the operation
+ * is <code>null</code>.
+ * <li>PATH_OUTSIDE_PROJECT - the output location path supplied to the operation
+ * is outside of the project supplied to this operation.
+ * <li>DEVICE_PATH - the path supplied to this operation must not specify a
+ * device
+ * <li>RELATIVE_PATH - the path supplied to this operation must be
+ * an absolute path
+ * <li>INVALID_PATH - the output location cannot overlap any package fragment
+ * root, except the project folder.
+ * <li>ELEMENT_DOES_NOT_EXIST - the Java project does not exist
+ * </ul>
+ */
+ public IJavaModelStatus verify() {
+ IJavaModelStatus status = super.verify();
+ if (!status.isOK()) {
+ return status;
+ }
+ IClasspathEntry[] cp = this.newRawPath;
+ IJavaProject javaProject = (IJavaProject) getElementToProcess();
+ IPath projectPath = javaProject.getProject().getFullPath();
+
+ IPath outputLocation;
+ try {
+ outputLocation = javaProject.getOutputLocation();
+ } catch (JavaModelException e) {
+ return e.getJavaModelStatus();
+ }
+ for (int i = 0; i < cp.length; i++) {
+ if (cp[i].getEntryKind() == IClasspathEntry.CPE_SOURCE) {
+ IPath entry = cp[i].getPath();
+ if (!entry.equals(projectPath)
+ && !entry.equals(outputLocation)
+ && (outputLocation.isPrefixOf(entry) || entry.isPrefixOf(outputLocation))) {
+ return new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, entry);
+ }
+ }
+ }
+ return JavaModelStatus.VERIFIED_OK;
+ }
+
+ /**
+ * Update projects which are affected by this classpath change:
+ * those which refers to the current project as source
+ */
+ protected void updateAffectedProjects(IPath prerequisiteProjectPath) {
+
+ try {
+ IJavaModel model = JavaModelManager.getJavaModelManager().getJavaModel();
+ IJavaProject[] projects = model.getJavaProjects();
+ for (int i = 0, projectCount = projects.length; i < projectCount; i++) {
+ try {
+ JavaProject project = (JavaProject) projects[i];
+ IClasspathEntry[] classpath = project.getRawClasspath();
+ for (int j = 0, entryCount = classpath.length; j < entryCount; j++) {
+ IClasspathEntry entry = classpath[j];
+ if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT
+ && entry.getPath().equals(prerequisiteProjectPath)) {
+ project.updateClassPath();
+ break;
+ }
+ }
+ } catch (JavaModelException e) {
+ }
+ }
+ } catch (JavaModelException e) {
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetOutputLocationOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetOutputLocationOperation.java
new file mode 100644
index 0000000000..dc2c0f6896
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetOutputLocationOperation.java
@@ -0,0 +1,228 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+
+import org.eclipse.jdt.core.*;
+
+import java.io.File;
+import java.util.*;
+
+/**
+ * This operation sets an <code>IJavaProject</code>'s output location.
+ *
+ * @see IJavaProject
+ */
+public class SetOutputLocationOperation extends JavaModelOperation {
+ /**
+ * The new output location for the Java project
+ */
+ protected IPath fOutputLocation;
+ /**
+ * When executed, this operation sets the output location of the given project.
+ * The output location is where the builder writes <code>.class</code> files.
+ */
+ public SetOutputLocationOperation(IJavaProject project, IPath outputLocation) {
+ super(new IJavaElement[] { project });
+ fOutputLocation = outputLocation;
+ }
+
+ /**
+ * Recursively adds all subfolders of <code>folder</code> to the given collection.
+ */
+ protected void collectAllSubfolders(IFolder folder, Vector collection)
+ throws JavaModelException {
+ try {
+ IResource[] members = folder.members();
+ for (int i = 0, max = members.length; i < max; i++) {
+ IResource r = members[i];
+ if (r.getType() == IResource.FOLDER) {
+ collection.addElement(r);
+ collectAllSubfolders((IFolder) r, collection);
+ }
+ }
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ }
+ }
+
+ /**
+ * Returns a collection of package fragments that have been added/removed
+ * as the result of changing the output location to/from the given
+ * location. The collection is empty if no package fragments are
+ * affected.
+ */
+ protected Vector determineAffectedPackageFragments(IPath location)
+ throws JavaModelException {
+ Vector fragments = new Vector();
+ JavaProject project = ((JavaProject) getElementsToProcess()[0]);
+
+ // see if this will cause any package fragments to be affected
+ IWorkspace workspace = getWorkspace();
+ IResource resource = null;
+ if (location != null) {
+ resource = workspace.getRoot().findMember(location);
+ }
+ if (resource != null && resource.getType() == IResource.FOLDER) {
+ IFolder folder = (IFolder) resource;
+ // only changes if it actually existed
+ IClasspathEntry[] classpath = project.getResolvedClasspath(true);
+ for (int i = 0; i < classpath.length; i++) {
+ IClasspathEntry entry = classpath[i];
+ IPath path = classpath[i].getPath();
+ if (entry.getEntryKind() != IClasspathEntry.CPE_PROJECT
+ && path.isPrefixOf(location)
+ && !path.equals(location)) {
+ IPackageFragmentRoot[] roots = project.getPackageFragmentRoots(classpath[i]);
+ IPackageFragmentRoot root = roots[0];
+ // now the output location becomes a package fragment - along with any subfolders
+ Vector folders = new Vector();
+ folders.addElement(folder);
+ collectAllSubfolders(folder, folders);
+ Enumeration elements = folders.elements();
+ int segments = path.segmentCount();
+ while (elements.hasMoreElements()) {
+ IFolder f = (IFolder) elements.nextElement();
+ IPath relativePath = f.getFullPath().removeFirstSegments(segments);
+ String name = relativePath.toOSString();
+ name = name.replace(File.pathSeparatorChar, '.');
+ if (name.endsWith(".")) {
+ name = name.substring(0, name.length() - 1);
+ }
+ IPackageFragment pkg = root.getPackageFragment(name);
+ fragments.addElement(pkg);
+ }
+ }
+ }
+ }
+ return fragments;
+ }
+
+ /**
+ * Sets the output location of the pre-specified project.
+ *
+ * <p>This can cause changes in package fragments - i.e. if the
+ * old and new output location folder could be considered as
+ * a package fragment.
+ */
+ protected void executeOperation() throws JavaModelException {
+ beginTask("Setting output location...", 2);
+ JavaProject project = ((JavaProject) getElementsToProcess()[0]);
+
+ IPath oldLocation = project.getOutputLocation();
+ IPath newLocation = fOutputLocation;
+
+ // see if this will cause any package fragments to be added
+ boolean deltaToFire = false;
+ JavaElementDelta delta = newJavaElementDelta();
+ Vector added = determineAffectedPackageFragments(oldLocation);
+ Enumeration pkgs = added.elements();
+ while (pkgs.hasMoreElements()) {
+ IPackageFragment frag = (IPackageFragment) pkgs.nextElement();
+ ((IPackageFragmentRoot) frag.getParent()).close();
+ delta.added(frag);
+ deltaToFire = true;
+ }
+
+ // see if this will cause any package fragments to be removed
+ Vector removed = determineAffectedPackageFragments(newLocation);
+ pkgs = removed.elements();
+ while (pkgs.hasMoreElements()) {
+ IPackageFragment frag = (IPackageFragment) pkgs.nextElement();
+ ((IPackageFragmentRoot) frag.getParent()).close();
+ delta.removed(frag);
+ deltaToFire = true;
+ }
+
+ project.setOutputLocation0(fOutputLocation);
+ if (deltaToFire) {
+ addDelta(delta);
+ }
+ worked(1);
+ project.saveClasspath();
+ worked(1);
+
+ // loose all built state - next build will be a full one
+ JavaModelManager.getJavaModelManager().setLastBuiltState(
+ project.getProject(),
+ null);
+ done();
+ }
+
+ /**
+ * Possible failures: <ul>
+ * <li>NO_ELEMENTS_TO_PROCESS - the project supplied to the operation is
+ * <code>null</code>.
+ * <li>NULL_PATH - the output location path supplied to the operation
+ * is <code>null</code>.
+ * <li>PATH_OUTSIDE_PROJECT - the output location path supplied to the operation
+ * is outside of the project supplied to this operation.
+ * <li>DEVICE_PATH - the path supplied to this operation must not specify a
+ * device
+ * <li>RELATIVE_PATH - the path supplied to this operation must be
+ * an absolute path
+ * <li>INVALID_PATH - the output location cannot overlap any package fragment
+ * root, except the project folder.
+ * <li>ELEMENT_DOES_NOT_EXIST - the Java project does not exist
+ * </ul>
+ */
+ public IJavaModelStatus verify() {
+ IJavaModelStatus status = super.verify();
+ if (!status.isOK()) {
+ return status;
+ }
+ if (fOutputLocation == null) {
+ return new JavaModelStatus(IJavaModelStatusConstants.NULL_PATH);
+ }
+
+ if (fOutputLocation.isAbsolute()) {
+ IProject project = ((IJavaProject) fElementsToProcess[0]).getProject();
+
+ if (project.getFullPath().isPrefixOf(fOutputLocation)) {
+ //project relative path
+ String projectName = fOutputLocation.segment(0);
+ if (!projectName.equals(fElementsToProcess[0].getElementName())) {
+ //a workspace relative path outside of this project
+ return new JavaModelStatus(
+ IJavaModelStatusConstants.PATH_OUTSIDE_PROJECT,
+ fOutputLocation);
+ }
+ } else {
+ return new JavaModelStatus(
+ IJavaModelStatusConstants.DEVICE_PATH,
+ fOutputLocation);
+ }
+ } else {
+ return new JavaModelStatus(
+ IJavaModelStatusConstants.RELATIVE_PATH,
+ fOutputLocation);
+ }
+
+ IClasspathEntry[] cp = null;
+ IJavaProject javaProject = (IJavaProject) getElementToProcess();
+ try {
+ cp = javaProject.getResolvedClasspath(true);
+ } catch (JavaModelException e) {
+ return e.getJavaModelStatus();
+ }
+ IPath projectPath = javaProject.getProject().getFullPath();
+ for (int i = 0; i < cp.length; i++) {
+ IPath entry = cp[i].getPath();
+ if (!entry.equals(projectPath)
+ && !entry.equals(fOutputLocation)
+ && (fOutputLocation.isPrefixOf(entry) || entry.isPrefixOf(fOutputLocation))) {
+ return new JavaModelStatus(
+ IJavaModelStatusConstants.INVALID_PATH,
+ fOutputLocation);
+ }
+ }
+
+ return JavaModelStatus.VERIFIED_OK;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SingleTypeRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SingleTypeRequestor.java
new file mode 100644
index 0000000000..5218023cdc
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SingleTypeRequestor.java
@@ -0,0 +1,81 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+
+/**
+ * The SingleTypeRequestor is an IJavaElementRequestor that
+ * only accepts one result element and then cancels.
+ */
+/* package */
+class SingleTypeRequestor implements IJavaElementRequestor {
+ /**
+ * The single accepted element
+ */
+ protected IType fElement = null;
+ /**
+ * @see IJavaElementRequestor
+ */
+ public void acceptField(IField field) {
+ }
+
+ /**
+ * @see IJavaElementRequestor
+ */
+ public void acceptInitializer(IInitializer initializer) {
+ }
+
+ /**
+ * @see IJavaElementRequestor
+ */
+ public void acceptMemberType(IType type) {
+ fElement = type;
+ }
+
+ /**
+ * @see IJavaElementRequestor
+ */
+ public void acceptMethod(IMethod method) {
+ }
+
+ /**
+ * @see IJavaElementRequestor
+ */
+ public void acceptPackageFragment(IPackageFragment packageFragment) {
+ }
+
+ /**
+ * @see IJavaElementRequestor
+ */
+ public void acceptType(IType type) {
+ fElement = type;
+ }
+
+ /**
+ * Returns the type accepted by this requestor, or <code>null</code>
+ * if no type has been accepted.
+ */
+ public IType getType() {
+ return fElement;
+ }
+
+ /**
+ * @see IJavaElementRequestor
+ */
+ public boolean isCanceled() {
+ return fElement != null;
+ }
+
+ /**
+ * Reset the state of this requestor
+ */
+ public void reset() {
+ fElement = null;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceField.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceField.java
new file mode 100644
index 0000000000..ae6a731e4c
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceField.java
@@ -0,0 +1,74 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.jdom.IDOMNode;
+
+/**
+ * @see IField
+ */
+
+/* package */
+class SourceField extends Member implements IField {
+
+ /**
+ * Constructs a handle to the field with the given name in the specified type.
+ */
+ protected SourceField(IType parent, String name) {
+ super(FIELD, parent, name);
+ }
+
+ /**
+ * @see JavaElement#equalsDOMNode
+ */
+ protected boolean equalsDOMNode(IDOMNode node) throws JavaModelException {
+ return (node.getNodeType() == IDOMNode.FIELD) && super.equalsDOMNode(node);
+ }
+
+ /**
+ * @see IField
+ */
+ public Object getConstant() throws JavaModelException {
+ SourceFieldElementInfo info = (SourceFieldElementInfo) getElementInfo();
+ return convertConstant(info.getConstant());
+ }
+
+ /**
+ * @see JavaElement#getHandleMemento()
+ */
+ protected char getHandleMementoDelimiter() {
+ return JavaElement.JEM_FIELD;
+ }
+
+ /**
+ * @see IField
+ */
+ public String getTypeSignature() throws JavaModelException {
+ SourceFieldElementInfo info = (SourceFieldElementInfo) getElementInfo();
+ return info.getTypeSignature();
+ }
+
+ /**
+ * @private Debugging purposes
+ */
+ protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+ if (info == null) {
+ buffer.append(getElementName());
+ buffer.append(" (not open)");
+ } else {
+ try {
+ buffer.append(Signature.toString(this.getTypeSignature()));
+ buffer.append(" ");
+ buffer.append(this.getElementName());
+ } catch (JavaModelException e) {
+ buffer.append("<JavaModelException in toString of " + getElementName());
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceFieldElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceFieldElementInfo.java
new file mode 100644
index 0000000000..71bf433509
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceFieldElementInfo.java
@@ -0,0 +1,77 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.env.ISourceField;
+import org.eclipse.jdt.core.Signature;
+
+/**
+ * Element info for IField elements.
+ */
+
+/* package */
+class SourceFieldElementInfo
+ extends MemberElementInfo
+ implements ISourceField {
+
+ /**
+ * The type name of this field.
+ */
+ protected char[] fTypeName;
+
+ /**
+ * The field's constant value
+ */
+ protected Constant fConstant;
+ /**
+ * Constructs an info object for the given field.
+ */
+ protected SourceFieldElementInfo() {
+ fConstant = Constant.NotAConstant;
+ }
+
+ /**
+ * Returns the constant associated with this field or
+ * Constant.NotAConstant if the field is not constant.
+ */
+ public Constant getConstant() {
+ return fConstant;
+ }
+
+ /**
+ * Returns the type name of the field.
+ */
+ public char[] getTypeName() {
+ return fTypeName;
+ }
+
+ /**
+ * Returns the type signature of the field.
+ *
+ * @see Signature
+ */
+ protected String getTypeSignature() {
+ return Signature.createTypeSignature(fTypeName, false);
+ }
+
+ /**
+ * Returns the constant associated with this field or
+ * Constant.NotAConstant if the field is not constant.
+ */
+ public void setConstant(Constant constant) {
+ fConstant = constant;
+ }
+
+ /**
+ * Sets the type name of the field.
+ */
+ protected void setTypeName(char[] typeName) {
+ fTypeName = typeName;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.java
new file mode 100644
index 0000000000..9ab52b83f9
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.java
@@ -0,0 +1,656 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.resources.*;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.*;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipEntry;
+
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.core.util.ReferenceInfoAdapter;
+
+/**
+ * A SourceMapper maps source code in a ZIP file to binary types in
+ * a JAR. The SourceMapper uses the fuzzy parser to identify source
+ * fragments in a .java file, and attempts to match the source code
+ * with children in a binary type. A SourceMapper is associated
+ * with a JarPackageFragment by an AttachSourceOperation.
+ *
+ * @see AttachSourceOperation
+ * @see JarPackageFragment
+ */
+public class SourceMapper
+ extends ReferenceInfoAdapter
+ implements ISourceElementRequestor {
+
+ /**
+ * The binary type source is being mapped for
+ */
+ protected BinaryType fType;
+
+ /**
+ * The location of the zip file containing source.
+ */
+ protected IPath fZipPath;
+ /**
+ * Specifies the location of the package fragment root within
+ * the zip (empty specifies the default root). <code>null</code> is
+ * not a valid root path.
+ */
+ protected String fRootPath;
+
+ /**
+ * The Java Model this source mapper is working for.
+ */
+ protected JavaModel fJavaModel;
+
+ /**
+ * Used for efficiency
+ */
+ protected static String[] fgEmptyStringArray = new String[0];
+
+ /**
+ * Table that maps a binary element to its <code>SourceRange</code>s.
+ * Keys are the element handles, entries are <code>SourceRange[]</code> which
+ * is a two element array; the first being source range, the second
+ * being name range.
+ */
+ protected Hashtable fSourceRanges;
+
+ /**
+ * The unknown source range {-1, 0}
+ */
+ protected static SourceRange fgUnknownRange = new SourceRange(-1, 0);
+
+ /**
+ * The position within the source of the start of the
+ * current member element, or -1 if we are outside a member.
+ */
+ protected int fMemberDeclarationStart = -1;
+ /**
+ * The <code>SourceRange</code> of the name of the current member element.
+ */
+ protected SourceRange fMemberNameRange;
+ /**
+ * The name of the current member element.
+ */
+ protected String fMemberName;
+ /**
+ * The parameter types for the current member method element.
+ */
+ protected char[][] fMethodParameterTypes;
+
+ /**
+ * The element searched for
+ */
+ protected IJavaElement searchedElement;
+
+ /**
+ * Enclosing type information
+ */
+ IType[] types;
+ int[] typeDeclarationStarts;
+ SourceRange[] typeNameRanges;
+ int typeDepth;
+ /**
+ * Creates a <code>SourceMapper</code> that locates source in the zip file
+ * at the given location in the specified package fragment root.
+ */
+ public SourceMapper(IPath zipPath, String rootPath, JavaModel model) {
+ fZipPath = zipPath;
+ fRootPath = rootPath.replace('\\', '/');
+ if (fRootPath.endsWith("/")) {
+ fRootPath = fRootPath.substring(0, fRootPath.lastIndexOf('/'));
+ }
+ fJavaModel = model;
+ fSourceRanges = new Hashtable();
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void acceptImport(
+ int declarationStart,
+ int declarationEnd,
+ char[] name,
+ boolean onDemand) {
+ //do nothing
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void acceptInitializer(
+ int modifiers,
+ int declarationSourceStart,
+ int declarationSourceEnd) {
+ //do nothing
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void acceptLineSeparatorPositions(int[] positions) {
+ //do nothing
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void acceptPackage(
+ int declarationStart,
+ int declarationEnd,
+ char[] name) {
+ //do nothing
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void acceptProblem(IProblem problem) {
+ //do nothing
+ }
+
+ /**
+ * Closes this <code>SourceMapper</code>'s zip file. Once this is done, this
+ * <code>SourceMapper</code> cannot be used again.
+ */
+ public void close() throws JavaModelException {
+ fSourceRanges = null;
+ }
+
+ /**
+ * Converts these type names to signatures.
+ * @see Signature.
+ */
+ public String[] convertTypeNamesToSigs(char[][] typeNames) {
+ if (typeNames == null)
+ return fgEmptyStringArray;
+ int n = typeNames.length;
+ if (n == 0)
+ return fgEmptyStringArray;
+ String[] typeSigs = new String[n];
+ for (int i = 0; i < n; ++i) {
+ typeSigs[i] = Signature.createTypeSignature(typeNames[i], false);
+ }
+ return typeSigs;
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterClass(
+ int declarationStart,
+ int modifiers,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[] superclass,
+ char[][] superinterfaces) {
+
+ this.typeDepth++;
+ if (this.typeDepth == this.types.length) { // need to grow
+ System.arraycopy(
+ this.types,
+ 0,
+ this.types = new IType[this.typeDepth * 2],
+ 0,
+ this.typeDepth);
+ System.arraycopy(
+ this.typeNameRanges,
+ 0,
+ this.typeNameRanges = new SourceRange[this.typeDepth * 2],
+ 0,
+ this.typeDepth);
+ System.arraycopy(
+ this.typeDeclarationStarts,
+ 0,
+ this.typeDeclarationStarts = new int[this.typeDepth * 2],
+ 0,
+ this.typeDepth);
+ }
+ this.types[typeDepth] = this.getType(new String(name));
+ this.typeNameRanges[typeDepth] =
+ new SourceRange(nameSourceStart, nameSourceEnd - nameSourceStart + 1);
+ this.typeDeclarationStarts[typeDepth] = declarationStart;
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterCompilationUnit() {
+ // do nothing
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterConstructor(
+ int declarationStart,
+ int modifiers,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[][] parameterTypes,
+ char[][] parameterNames,
+ char[][] exceptionTypes) {
+ enterMethod(
+ declarationStart,
+ modifiers,
+ null,
+ name,
+ nameSourceStart,
+ nameSourceEnd,
+ parameterTypes,
+ parameterNames,
+ exceptionTypes);
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterField(
+ int declarationStart,
+ int modifiers,
+ char[] type,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd) {
+ if (typeDepth >= 0
+ && fMemberDeclarationStart == -1) {
+ // don't allow nested member (can only happen with anonymous inner classes)
+ fMemberDeclarationStart = declarationStart;
+ fMemberNameRange =
+ new SourceRange(nameSourceStart, nameSourceEnd - nameSourceStart + 1);
+ fMemberName = new String(name);
+ }
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterInterface(
+ int declarationStart,
+ int modifiers,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[][] superinterfaces) {
+ enterClass(
+ declarationStart,
+ modifiers,
+ name,
+ nameSourceStart,
+ nameSourceEnd,
+ null,
+ superinterfaces);
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void enterMethod(
+ int declarationStart,
+ int modifiers,
+ char[] returnType,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[][] parameterTypes,
+ char[][] parameterNames,
+ char[][] exceptionTypes) {
+ if (typeDepth >= 0
+ && fMemberDeclarationStart == -1) {
+ // don't allow nested member (can only happen with anonymous inner classes)
+ fMemberName = new String(name);
+ fMemberNameRange =
+ new SourceRange(nameSourceStart, nameSourceEnd - nameSourceStart + 1);
+ fMemberDeclarationStart = declarationStart;
+ fMethodParameterTypes = parameterTypes;
+ }
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitClass(int declarationEnd) {
+ if (typeDepth >= 0) {
+ IType currentType = this.types[typeDepth];
+ setSourceRange(
+ currentType,
+ new SourceRange(
+ this.typeDeclarationStarts[typeDepth],
+ declarationEnd - this.typeDeclarationStarts[typeDepth] + 1),
+ this.typeNameRanges[typeDepth]);
+ this.typeDepth--;
+ }
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitCompilationUnit(int declarationEnd) {
+ //do nothing
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitConstructor(int declarationEnd) {
+ exitMethod(declarationEnd);
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitField(int declarationEnd) {
+ if (typeDepth >= 0 && fMemberDeclarationStart != -1) {
+ IType currentType = this.types[typeDepth];
+ setSourceRange(
+ currentType.getField(fMemberName),
+ new SourceRange(
+ fMemberDeclarationStart,
+ declarationEnd - fMemberDeclarationStart + 1),
+ fMemberNameRange);
+ fMemberDeclarationStart = -1;
+ }
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitInterface(int declarationEnd) {
+ exitClass(declarationEnd);
+ }
+
+ /**
+ * @see ISourceElementRequestor
+ */
+ public void exitMethod(int declarationEnd) {
+ if (typeDepth >= 0 && fMemberDeclarationStart != -1) {
+ IType currentType = this.types[typeDepth];
+ SourceRange sourceRange =
+ new SourceRange(
+ fMemberDeclarationStart,
+ declarationEnd - fMemberDeclarationStart + 1);
+ setSourceRange(
+ currentType.getMethod(
+ fMemberName,
+ convertTypeNamesToSigs(fMethodParameterTypes)),
+ sourceRange,
+ fMemberNameRange);
+ fMemberDeclarationStart = -1;
+ }
+ }
+
+ /**
+ * Locates and returns source code for the given (binary) type, in this
+ * SourceMapper's ZIP file, or returns <code>null</code> if source
+ * code cannot be found.
+ */
+ public char[] findSource(IType type) {
+ if (!type.isBinary()) {
+ return null;
+ }
+ BinaryType parent = (BinaryType) type.getDeclaringType();
+ BinaryType declType = (BinaryType) type;
+ while (parent != null) {
+ declType = parent;
+ parent = (BinaryType) declType.getDeclaringType();
+ }
+ IBinaryType info = null;
+ try {
+ info = (IBinaryType) declType.getRawInfo();
+ } catch (JavaModelException e) {
+ return null;
+ }
+ return this.findSource(type, info);
+ }
+
+ /**
+ * Locates and returns source code for the given (binary) type, in this
+ * SourceMapper's ZIP file, or returns <code>null</code> if source
+ * code cannot be found.
+ */
+ public char[] findSource(IType type, IBinaryType info) {
+ String name = null;
+ // see 1FVVWZT
+ if (info instanceof ClassFileReader) {
+ char[] sourceFileName = ((ClassFileReader) info).sourceFileName();
+ if (sourceFileName == null)
+ return null; // no source file attribute
+ name = new String(sourceFileName);
+ } else {
+ return null;
+ }
+
+ IPackageFragment pkgFrag = type.getPackageFragment();
+ if (!pkgFrag.isDefaultPackage()) {
+ String pkg = type.getPackageFragment().getElementName().replace('.', '/');
+ name = pkg + '/' + name;
+ }
+ // try to get the entry
+ ZipEntry entry = null;
+ ZipFile zip = null;
+ char[] source = null;
+ try {
+ String fullName;
+ //add the root path if specified
+ if (!fRootPath.equals(IPackageFragmentRoot.DEFAULT_PACKAGEROOT_PATH)) {
+ fullName = fRootPath + '/' + name;
+ } else {
+ fullName = name;
+ }
+ zip = getZip();
+ entry = zip.getEntry(fullName);
+ if (entry != null) {
+ // now read the source code
+ byte[] bytes = readEntry(zip, entry);
+ if (bytes != null) {
+ try {
+ source = BufferManager.bytesToChar(bytes);
+ } catch (JavaModelException e) {
+ source = null;
+ }
+ }
+ }
+ } catch (CoreException e) {
+ return null;
+ } finally {
+ if (zip != null) {
+ try {
+ zip.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ return source;
+ }
+
+ /**
+ * Returns the SourceRange for the name of the given element, or
+ * {-1, -1} if no source range is known for the name of the element.
+ */
+ public SourceRange getNameRange(IJavaElement element) {
+ if (element.getElementType() == IJavaElement.METHOD
+ && ((IMember) element).isBinary()) {
+ element = getUnqualifiedMethodHandle((IMethod) element);
+ }
+ SourceRange[] ranges = (SourceRange[]) fSourceRanges.get(element);
+ if (ranges == null) {
+ return fgUnknownRange;
+ } else {
+ return ranges[1];
+ }
+ }
+
+ /**
+ * Returns the <code>SourceRange</code> for the given element, or
+ * {-1, -1} if no source range is known for the element.
+ */
+ public SourceRange getSourceRange(IJavaElement element) {
+ if (element.getElementType() == IJavaElement.METHOD
+ && ((IMember) element).isBinary()) {
+ element = getUnqualifiedMethodHandle((IMethod) element);
+ }
+ SourceRange[] ranges = (SourceRange[]) fSourceRanges.get(element);
+ if (ranges == null) {
+ return fgUnknownRange;
+ } else {
+ return ranges[0];
+ }
+ }
+
+ /**
+ * Returns the type with the given <code>typeName</code>. Returns inner classes
+ * as well.
+ */
+ protected IType getType(String typeName) {
+ if (fType.getElementName().equals(typeName))
+ return fType;
+ else
+ return fType.getType(typeName);
+ }
+
+ /**
+ * Creates a handle that has parameter types that are not
+ * fully qualified so that the correct source is found.
+ */
+ protected IJavaElement getUnqualifiedMethodHandle(IMethod method) {
+
+ String[] qualifiedParameterTypes = method.getParameterTypes();
+ String[] unqualifiedParameterTypes = new String[qualifiedParameterTypes.length];
+ for (int i = 0; i < qualifiedParameterTypes.length; i++) {
+ StringBuffer unqualifiedName = new StringBuffer();
+ String qualifiedName = qualifiedParameterTypes[i];
+ int count = 0;
+ while (qualifiedName.charAt(count) == Signature.C_ARRAY) {
+ unqualifiedName.append(Signature.C_ARRAY);
+ ++count;
+ }
+ if (qualifiedName.charAt(count) == Signature.C_RESOLVED) {
+ unqualifiedName.append(Signature.C_UNRESOLVED);
+ unqualifiedName.append(Signature.getSimpleName(qualifiedName));
+ } else {
+ unqualifiedName.append(qualifiedName.substring(count, qualifiedName.length()));
+ }
+ unqualifiedParameterTypes[i] = unqualifiedName.toString();
+ }
+ return ((IType) method.getParent()).getMethod(
+ method.getElementName(),
+ unqualifiedParameterTypes);
+ }
+
+ /**
+ * Returns the <code>ZipFile</code> that source is located in.
+ */
+ public ZipFile getZip() throws CoreException {
+ return fJavaModel.fgJavaModelManager.getZipFile(fZipPath);
+ }
+
+ /**
+ * Maps the given source code to the given binary type and its children.
+ */
+ public void mapSource(IType type, char[] contents) {
+ this.mapSource(type, contents, null);
+ }
+
+ /**
+ * Maps the given source code to the given binary type and its children.
+ * If a non-null java element is passed, finds the name range for the
+ * given java element without storing it.
+ */
+ public ISourceRange mapSource(
+ IType type,
+ char[] contents,
+ IJavaElement searchedElement) {
+ fType = (BinaryType) type;
+
+ this.searchedElement = searchedElement;
+ this.types = new IType[1];
+ this.typeDeclarationStarts = new int[1];
+ this.typeNameRanges = new SourceRange[1];
+ this.typeDepth = -1;
+
+ Hashtable oldSourceRanges = (Hashtable) fSourceRanges.clone();
+ try {
+ IProblemFactory factory = new ProblemFactory();
+ SourceElementParser parser = new SourceElementParser(this, factory);
+ parser.parseCompilationUnit(
+ new BasicCompilationUnit(contents, type.getElementName() + ".java"),
+ false);
+ if (searchedElement != null) {
+ ISourceRange range = this.getNameRange(searchedElement);
+ return range;
+ } else {
+ return null;
+ }
+ } finally {
+ if (searchedElement != null) {
+ fSourceRanges = oldSourceRanges;
+ }
+ fType = null;
+ this.searchedElement = null;
+ this.types = null;
+ this.typeDeclarationStarts = null;
+ this.typeNameRanges = null;
+ this.typeDepth = -1;
+ }
+ }
+
+ /**
+ * Returns the contents of the specified zip entry
+ */
+ protected byte[] readEntry(ZipFile zip, ZipEntry entry) {
+ InputStream stream = null;
+ try {
+ stream = zip.getInputStream(entry);
+ int remaining = (int) entry.getSize();
+ byte[] bytes = new byte[remaining];
+ int offset = 0;
+ while (remaining > 0) {
+ int read = stream.read(bytes, offset, remaining);
+ if (read == -1)
+ break;
+ remaining -= read;
+ offset += read;
+ }
+ return bytes;
+ } catch (IOException e) {
+ return null;
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return null;
+ } finally {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (IOException ioe) {
+ }
+ }
+ }
+ }
+
+ /**
+ * Sets the mapping for this element to its source ranges for its source range
+ * and name range.
+ *
+ * @see fSourceRanges
+ */
+ protected void setSourceRange(
+ IJavaElement element,
+ SourceRange sourceRange,
+ SourceRange nameRange) {
+ fSourceRanges.put(element, new SourceRange[] { sourceRange, nameRange });
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethod.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethod.java
new file mode 100644
index 0000000000..2d2c31d8b8
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethod.java
@@ -0,0 +1,248 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.jdom.IDOMMethod;
+import org.eclipse.jdt.core.jdom.IDOMNode;
+
+/**
+ * @see IMethod
+ */
+
+/* package */
+class SourceMethod extends Member implements IMethod {
+
+ /**
+ * The parameter type signatures of the method - stored locally
+ * to perform equality test. <code>null</code> indicates no
+ * parameters.
+ */
+ protected String[] fParameterTypes;
+
+ /**
+ * An empty list of Strings
+ */
+ protected static final String[] fgEmptyList = new String[] {
+ };
+
+ protected SourceMethod(IType parent, String name, String[] parameterTypes) {
+ super(METHOD, parent, name);
+ Assert.isTrue(name.indexOf('.') == -1);
+ if (parameterTypes == null) {
+ fParameterTypes = fgEmptyList;
+ } else {
+ fParameterTypes = parameterTypes;
+ }
+ }
+
+ public boolean equals(Object o) {
+ return super.equals(o)
+ && Util.equalArraysOrNull(fParameterTypes, ((SourceMethod) o).fParameterTypes);
+ }
+
+ /**
+ * @see JavaElement#equalsDOMNode
+ */
+ protected boolean equalsDOMNode(IDOMNode node) throws JavaModelException {
+ if (node.getNodeType() == IDOMNode.METHOD) {
+ IDOMMethod m = (IDOMMethod) node;
+ if (isConstructor()) {
+ return (
+ m.isConstructor()
+ || m.getName().equals(
+ this.getElementName()) /* case of a constructor that is being renamed */)
+ && signatureEquals(m);
+ } else {
+ return super.equalsDOMNode(node) && signatureEquals(m);
+ }
+ } else {
+ return false;
+ }
+
+ }
+
+ /**
+ * @see IMethod
+ */
+ public String[] getExceptionTypes() throws JavaModelException {
+ SourceMethodElementInfo info = (SourceMethodElementInfo) getElementInfo();
+ char[][] exs = info.getExceptionTypeNames();
+ return CompilationUnitStructureRequestor.convertTypeNamesToSigs(exs);
+ }
+
+ /**
+ * @see JavaElement#getHandleMemento()
+ */
+ public String getHandleMemento() {
+ StringBuffer buff =
+ new StringBuffer(((JavaElement) getParent()).getHandleMemento());
+ buff.append(getHandleMementoDelimiter());
+ buff.append(getElementName());
+ for (int i = 0; i < fParameterTypes.length; i++) {
+ buff.append(getHandleMementoDelimiter());
+ buff.append(fParameterTypes[i]);
+ }
+ return buff.toString();
+ }
+
+ /**
+ * @see JavaElement#getHandleMemento()
+ */
+ protected char getHandleMementoDelimiter() {
+ return JavaElement.JEM_METHOD;
+ }
+
+ /**
+ * @see IMethod
+ */
+ public int getNumberOfParameters() {
+ return fParameterTypes == null ? 0 : fParameterTypes.length;
+ }
+
+ /**
+ * @see IMethod
+ */
+ public String[] getParameterNames() throws JavaModelException {
+ SourceMethodElementInfo info = (SourceMethodElementInfo) getElementInfo();
+ char[][] names = info.getArgumentNames();
+ if (names == null || names.length == 0) {
+ return fgEmptyList;
+ }
+ String[] strings = new String[names.length];
+ for (int i = 0; i < names.length; i++) {
+ strings[i] = new String(names[i]);
+ }
+ return strings;
+ }
+
+ /**
+ * @see IMethod
+ */
+ public String[] getParameterTypes() {
+ return fParameterTypes;
+ }
+
+ /**
+ * @see IMethod
+ */
+ public String getReturnType() throws JavaModelException {
+ SourceMethodElementInfo info = (SourceMethodElementInfo) getElementInfo();
+ return Signature.createTypeSignature(info.getReturnTypeName(), false);
+ }
+
+ /**
+ * @see IMethod
+ */
+ public String getSignature() throws JavaModelException {
+ SourceMethodElementInfo info = (SourceMethodElementInfo) getElementInfo();
+ return info.getSignature();
+ }
+
+ /**
+ * @see IMethod
+ */
+ public boolean isConstructor() throws JavaModelException {
+ SourceMethodElementInfo info = (SourceMethodElementInfo) getElementInfo();
+ return info.isConstructor();
+ }
+
+ /**
+ */
+ public String readableName() {
+
+ StringBuffer buffer = new StringBuffer(super.readableName());
+ buffer.append("(");
+ String[] parameterTypes = this.getParameterTypes();
+ int length;
+ if (parameterTypes != null && (length = parameterTypes.length) > 0) {
+ for (int i = 0; i < length; i++) {
+ buffer.append(Signature.toString(parameterTypes[i]));
+ if (i < length - 1) {
+ buffer.append(", ");
+ }
+ }
+ }
+ buffer.append(")");
+ return buffer.toString();
+ }
+
+ /**
+ * Returns <code>true</code> if the signature of this <code>SourceMethod</code> matches that of the given
+ * <code>IDOMMethod</code>, otherwise <code>false</code>.
+ */
+ protected boolean signatureEquals(IDOMMethod method)
+ throws JavaModelException {
+ String[] otherTypes = method.getParameterTypes();
+ String[] types = getParameterTypes();
+ boolean ok = true;
+
+ // ensure the number of parameters match
+ if (otherTypes == null || otherTypes.length == 0) {
+ ok = (types == null || types.length == 0);
+ } else
+ if (types != null) {
+ ok = (otherTypes.length == types.length);
+ } else {
+ return false;
+ }
+
+ // ensure the parameter type signatures match
+ if (ok) {
+ if (types != null) {
+ int i;
+ for (i = 0; i < types.length; i++) {
+ String otherType =
+ Signature.createTypeSignature(otherTypes[i].toCharArray(), false);
+ if (!types[i].equals(otherType)) {
+ ok = false;
+ break;
+ }
+ }
+ }
+ }
+
+ return ok;
+ }
+
+ /**
+ * @private Debugging purposes
+ */
+ protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+ if (info == null) {
+ buffer.append(getElementName());
+ buffer.append(" (not open)");
+ } else {
+ try {
+ if (Flags.isStatic(this.getFlags())) {
+ buffer.append("static ");
+ }
+ if (!this.isConstructor()) {
+ buffer.append(Signature.toString(this.getReturnType()));
+ buffer.append(" ");
+ }
+ buffer.append(this.getElementName());
+ buffer.append("(");
+ String[] parameterTypes = this.getParameterTypes();
+ int length;
+ if (parameterTypes != null && (length = parameterTypes.length) > 0) {
+ for (int i = 0; i < length; i++) {
+ buffer.append(Signature.toString(parameterTypes[i]));
+ if (i < length - 1) {
+ buffer.append(", ");
+ }
+ }
+ }
+ buffer.append(")");
+ } catch (JavaModelException e) {
+ buffer.append("<JavaModelException in toString of " + getElementName());
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethodElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethodElementInfo.java
new file mode 100644
index 0000000000..b6dffd43a1
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethodElementInfo.java
@@ -0,0 +1,114 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.internal.compiler.env.ISourceMethod;
+import org.eclipse.jdt.core.Signature;
+
+/**
+ * Element info for IMethod elements.
+ */
+/* package */
+class SourceMethodElementInfo
+ extends MemberElementInfo
+ implements ISourceMethod {
+
+ /**
+ * For a source method (i.e. method contained in a comilation unit)
+ * this is a collection of the names of the parameters for this method,
+ * in the order the parameters are delcared. For a binary method (i.e.
+ * method declared in a binary type), these names are invented as
+ * "arg"i where i starts at 1. This is an empty array if this method
+ * has no parameters.
+ */
+ protected char[][] argumentNames;
+
+ /**
+ * Collection of type names for the arguments in this
+ * method, in the order they are declared. This is an empty
+ * array for a method with no arguments. A name is a simple
+ * name or a qualified, dot separated name.
+ * For example, Hashtable or java.util.Hashtable.
+ */
+ protected char[][] argumentTypeNames;
+
+ /**
+ * Return type name for this method. The return type of
+ * constructors is equivalent to void.
+ */
+ protected char[] returnType;
+
+ /**
+ * A collection of type names of the exceptions this
+ * method throws, or an empty collection if this method
+ * does not declare to throw any exceptions. A name is a simple
+ * name or a qualified, dot separated name.
+ * For example, Hashtable or java.util.Hashtable.
+ */
+ protected char[][] exceptionTypes;
+
+ /**
+ * Constructor flag.
+ */
+ protected boolean isConstructor = false;
+ public char[][] getArgumentNames() {
+ return this.argumentNames;
+ }
+
+ public char[][] getArgumentTypeNames() {
+ return this.argumentTypeNames;
+ }
+
+ public char[][] getExceptionTypeNames() {
+ return this.exceptionTypes;
+ }
+
+ public char[] getReturnTypeName() {
+ return this.returnType;
+ }
+
+ public char[] getSelector() {
+ return this.name;
+ }
+
+ protected String getSignature() {
+
+ String[] paramSignatures = new String[this.argumentTypeNames.length];
+ for (int i = 0; i < this.argumentTypeNames.length; ++i) {
+ paramSignatures[i] =
+ Signature.createTypeSignature(this.argumentTypeNames[i], false);
+ }
+ return Signature.createMethodSignature(
+ paramSignatures,
+ Signature.createTypeSignature(this.returnType, false));
+ }
+
+ public boolean isConstructor() {
+ return this.isConstructor;
+ }
+
+ protected void setArgumentNames(char[][] names) {
+ this.argumentNames = names;
+ }
+
+ protected void setArgumentTypeNames(char[][] types) {
+ this.argumentTypeNames = types;
+ }
+
+ protected void setConstructor(boolean isConstructor) {
+ this.isConstructor = isConstructor;
+ }
+
+ protected void setExceptionTypeNames(char[][] types) {
+ this.exceptionTypes = types;
+ }
+
+ protected void setReturnType(char[] type) {
+ this.returnType = type;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRange.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRange.java
new file mode 100644
index 0000000000..e1e20ee13f
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRange.java
@@ -0,0 +1,48 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+
+/**
+ * @see ISourceRange
+ */
+/* package */
+class SourceRange implements ISourceRange {
+
+ protected int offset, length;
+
+ protected SourceRange(int offset, int length) {
+ this.offset = offset;
+ this.length = length;
+ }
+
+ /**
+ * @see ISourceRange
+ */
+ public int getLength() {
+ return this.length;
+ }
+
+ /**
+ * @see ISourceRange
+ */
+ public int getOffset() {
+ return this.offset;
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("[offset=");
+ buffer.append(this.offset);
+ buffer.append(", length=");
+ buffer.append(this.length);
+ buffer.append("]");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRefElement.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRefElement.java
new file mode 100644
index 0000000000..dfca0a9c18
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRefElement.java
@@ -0,0 +1,230 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.jdt.core.*;
+
+/**
+ * Abstract class for Java elements which implement ISourceReference.
+ */
+
+/* package */
+abstract class SourceRefElement
+ extends JavaElement
+ implements ISourceReference {
+
+ protected SourceRefElement(int type, IJavaElement parent, String name) {
+ super(type, parent, name);
+ }
+
+ /**
+ * @see ISourceManipulation
+ */
+ public void copy(
+ IJavaElement container,
+ IJavaElement sibling,
+ String rename,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ if (container == null) {
+ throw new IllegalArgumentException("conatiner cannot be null");
+ }
+ IJavaElement[] elements = new IJavaElement[] { this };
+ IJavaElement[] containers = new IJavaElement[] { container };
+ IJavaElement[] siblings = null;
+ if (sibling != null) {
+ siblings = new IJavaElement[] { sibling };
+ }
+ String[] renamings = null;
+ if (rename != null) {
+ renamings = new String[] { rename };
+ }
+ getJavaModel().copy(elements, containers, siblings, renamings, force, monitor);
+ }
+
+ /**
+ * @see ISourceManipulation
+ */
+ public void delete(boolean force, IProgressMonitor monitor)
+ throws JavaModelException {
+ IJavaElement[] elements = new IJavaElement[] { this };
+ getJavaModel().delete(elements, force, monitor);
+ }
+
+ /**
+ * @see IMember
+ */
+ public ICompilationUnit getCompilationUnit() {
+ return ((JavaElement) getParent()).getCompilationUnit();
+ }
+
+ /**
+ * Elements within compilation units and class files have no
+ * corresponding resource.
+ *
+ * @see IJavaElement
+ */
+ public IResource getCorrespondingResource() throws JavaModelException {
+ return null;
+ }
+
+ /**
+ * Return the first instance of IOpenable in the hierarchy of this
+ * type (going up the hierarchy from this type);
+ */
+ public IOpenable getOpenableParent() {
+ IJavaElement parent = getParent();
+ if (parent instanceof IOpenable)
+ return (IOpenable) parent;
+ return ((JavaElement) parent).getOpenableParent();
+ }
+
+ /**
+ * @see ISourceReference
+ */
+ public String getSource() throws JavaModelException {
+ IOpenable openable = getOpenableParent();
+ IBuffer buffer = openable.getBuffer();
+ if (buffer == null) {
+ return null;
+ }
+ ISourceRange range = getSourceRange();
+ int offset = range.getOffset();
+ int length = range.getLength();
+ if (offset == -1 || length == 0) {
+ return null;
+ }
+ return buffer.getText(offset, length);
+ }
+
+ /**
+ * @see ISourceReference
+ */
+ public ISourceRange getSourceRange() throws JavaModelException {
+ SourceRefElementInfo info = (SourceRefElementInfo) getElementInfo();
+ return info.getSourceRange();
+ }
+
+ /**
+ * @see IJavaElement
+ */
+ public IResource getUnderlyingResource() throws JavaModelException {
+ return getParent().getUnderlyingResource();
+ }
+
+ /**
+ * @see ISourceManipulation
+ */
+ public void move(
+ IJavaElement container,
+ IJavaElement sibling,
+ String rename,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ if (container == null) {
+ throw new IllegalArgumentException("conatiner cannot be null");
+ }
+ IJavaElement[] elements = new IJavaElement[] { this };
+ IJavaElement[] containers = new IJavaElement[] { container };
+ IJavaElement[] siblings = null;
+ if (sibling != null) {
+ siblings = new IJavaElement[] { sibling };
+ }
+ String[] renamings = null;
+ if (rename != null) {
+ renamings = new String[] { rename };
+ }
+ getJavaModel().move(elements, containers, siblings, renamings, force, monitor);
+ }
+
+ /**
+ * Changes the source end index of this element, all children (following
+ * <code>child</code>), and all following elements.
+ */
+ public void offsetSourceEndAndChildren(int amount, IJavaElement child) {
+ try {
+ SourceRefElementInfo info = (SourceRefElementInfo) getRawInfo();
+ info.setSourceRangeEnd(info.getDeclarationSourceEnd() + amount);
+ IJavaElement[] children = getChildren();
+ boolean afterChild = false;
+ for (int i = 0; i < children.length; i++) {
+ IJavaElement aChild = children[i];
+ if (afterChild) {
+ ((JavaElement) aChild).offsetSourceRange(amount);
+ } else {
+ afterChild = aChild.equals(child);
+ }
+ }
+ ((JavaElement) getParent()).offsetSourceEndAndChildren(amount, this);
+ } catch (JavaModelException npe) {
+ return;
+ }
+ }
+
+ /**
+ * Changes the source indexes of this element and all children elements.
+ */
+ public void offsetSourceRange(int amount) {
+ try {
+ SourceRefElementInfo info = (SourceRefElementInfo) getRawInfo();
+ info.setSourceRangeStart(info.getDeclarationSourceStart() + amount);
+ info.setSourceRangeEnd(info.getDeclarationSourceEnd() + amount);
+ IJavaElement[] children = getChildren();
+ for (int i = 0; i < children.length; i++) {
+ IJavaElement aChild = children[i];
+ ((JavaElement) aChild).offsetSourceRange(amount);
+ }
+ } catch (JavaModelException npe) {
+ return;
+ }
+ }
+
+ /**
+ * @see ISourceManipulation
+ */
+ public void rename(String name, boolean force, IProgressMonitor monitor)
+ throws JavaModelException {
+ if (name == null) {
+ throw new IllegalArgumentException("name cannot be null");
+ }
+ IJavaElement[] elements = new IJavaElement[] { this };
+ IJavaElement[] dests = new IJavaElement[] { this.getParent()};
+ String[] renamings = new String[] { name };
+ getJavaModel().rename(elements, dests, renamings, force, monitor);
+ }
+
+ /**
+ * Updates the end source index for this element, and all following elements.
+ */
+ public void triggerSourceEndOffset(int amount, int nameStart, int nameEnd) {
+ try {
+ SourceRefElementInfo info = (SourceRefElementInfo) getRawInfo();
+ info.setSourceRangeEnd(info.getDeclarationSourceEnd() + amount);
+ ((JavaElement) getParent()).offsetSourceEndAndChildren(amount, this);
+ } catch (JavaModelException npe) {
+ return;
+ }
+ }
+
+ /**
+ * Updates the source indexes of this element and all following elements.
+ */
+ public void triggerSourceRangeOffset(int amount, int nameStart, int nameEnd) {
+ try {
+ SourceRefElementInfo info = (SourceRefElementInfo) getRawInfo();
+ info.setSourceRangeStart(info.getDeclarationSourceStart() + amount);
+ info.setSourceRangeEnd(info.getDeclarationSourceEnd() + amount);
+ ((JavaElement) getParent()).offsetSourceEndAndChildren(amount, this);
+ } catch (JavaModelException npe) {
+ return;
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRefElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRefElementInfo.java
new file mode 100644
index 0000000000..4a8e8af785
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRefElementInfo.java
@@ -0,0 +1,53 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+
+/**
+ * Element info for ISourceReference elements.
+ */
+/* package */
+class SourceRefElementInfo extends JavaElementInfo {
+ protected int fSourceRangeStart, fSourceRangeEnd;
+ protected SourceRefElementInfo() {
+ setIsStructureKnown(true);
+ }
+
+ /**
+ * @see ISourceType
+ * @see ISourceMethod
+ * @see ISourceField
+ */
+ public int getDeclarationSourceEnd() {
+ return fSourceRangeEnd;
+ }
+
+ /**
+ * @see ISourceType
+ * @see ISourceMethod
+ * @see ISourceField
+ */
+ public int getDeclarationSourceStart() {
+ return fSourceRangeStart;
+ }
+
+ protected ISourceRange getSourceRange() {
+ return new SourceRange(
+ fSourceRangeStart,
+ fSourceRangeEnd - fSourceRangeStart + 1);
+ }
+
+ protected void setSourceRangeEnd(int end) {
+ fSourceRangeEnd = end;
+ }
+
+ protected void setSourceRangeStart(int start) {
+ fSourceRangeStart = start;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceType.java
new file mode 100644
index 0000000000..aa9a3fccac
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceType.java
@@ -0,0 +1,419 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.core.resources.*;
+import java.util.Vector;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.codeassist.*;
+import org.eclipse.jdt.internal.compiler.env.ISourceType;
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.compiler.IProblem;
+import org.eclipse.jdt.internal.compiler.ConfigurableOption;
+import org.eclipse.jdt.core.jdom.IDOMNode;
+
+/**
+ * Handle for a source type. Info object is a SourceTypeElementInfo.
+ *
+ * Note: Parent is either an IClassFile, an ICompilationUnit or an IType.
+ *
+ * @see IType
+ */
+
+public class SourceType extends Member implements IType {
+ /**
+ * An empty list of Strings
+ */
+ protected static final String[] fgEmptyList = new String[] {
+ };
+
+ protected SourceType(IJavaElement parent, String name) {
+ super(TYPE, parent, name);
+ Assert.isTrue(name.indexOf('.') == -1);
+ }
+
+ /**
+ * @see IType
+ */
+ public IField createField(
+ String contents,
+ IJavaElement sibling,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ CreateFieldOperation op = new CreateFieldOperation(this, contents, force);
+ if (sibling != null) {
+ op.createBefore(sibling);
+ }
+ runOperation(op, monitor);
+ return (IField) op.getResultElements()[0];
+ }
+
+ /**
+ * @see IType
+ */
+ public IInitializer createInitializer(
+ String contents,
+ IJavaElement sibling,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ CreateInitializerOperation op = new CreateInitializerOperation(this, contents);
+ if (sibling != null) {
+ op.createBefore(sibling);
+ }
+ runOperation(op, monitor);
+ return (IInitializer) op.getResultElements()[0];
+ }
+
+ /**
+ * @see IType
+ */
+ public IMethod createMethod(
+ String contents,
+ IJavaElement sibling,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ CreateMethodOperation op = new CreateMethodOperation(this, contents, force);
+ if (sibling != null) {
+ op.createBefore(sibling);
+ }
+ runOperation(op, monitor);
+ return (IMethod) op.getResultElements()[0];
+ }
+
+ /**
+ * @see IType
+ */
+ public IType createType(
+ String contents,
+ IJavaElement sibling,
+ boolean force,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ CreateTypeOperation op = new CreateTypeOperation(this, contents, force);
+ if (sibling != null) {
+ op.createBefore(sibling);
+ }
+ runOperation(op, monitor);
+ return (IType) op.getResultElements()[0];
+ }
+
+ /**
+ * @see JavaElement#equalsDOMNode
+ */
+ protected boolean equalsDOMNode(IDOMNode node) throws JavaModelException {
+ return (node.getNodeType() == IDOMNode.TYPE) && super.equalsDOMNode(node);
+ }
+
+ /**
+ * @see IMember
+ */
+ public IType getDeclaringType() {
+ IJavaElement parent = getParent();
+ while (parent != null) {
+ if (parent.getElementType() == IJavaElement.TYPE) {
+ return (IType) parent;
+ } else
+ if (parent instanceof IMember) {
+ parent = parent.getParent();
+ } else {
+ return null;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @see IType#getField
+ */
+ public IField getField(String name) {
+ return new SourceField(this, name);
+ }
+
+ /**
+ * @see IType
+ */
+ public IField[] getFields() throws JavaModelException {
+ Vector v = getChildrenOfType(FIELD);
+ IField[] array = new IField[v.size()];
+ v.copyInto(array);
+ return array;
+ }
+
+ /**
+ * @see IType
+ */
+ public String getFullyQualifiedName() {
+ String packageName = getPackageFragment().getElementName();
+ if (packageName.equals(IPackageFragment.DEFAULT_PACKAGE_NAME)) {
+ return getTypeQualifiedName();
+ }
+ return packageName + '.' + getTypeQualifiedName();
+ }
+
+ /**
+ * @see IType
+ */
+ public IInitializer getInitializer(int occurrenceCount) {
+ return new Initializer(this, occurrenceCount);
+ }
+
+ /**
+ * @see IType
+ */
+ public IInitializer[] getInitializers() throws JavaModelException {
+ Vector v = getChildrenOfType(INITIALIZER);
+ IInitializer[] array = new IInitializer[v.size()];
+ v.copyInto(array);
+ return array;
+ }
+
+ /**
+ * @see IType#getMethod
+ */
+ public IMethod getMethod(String name, String[] parameterTypeSignatures) {
+ return new SourceMethod(this, name, parameterTypeSignatures);
+ }
+
+ /**
+ * @see IType
+ */
+ public IMethod[] getMethods() throws JavaModelException {
+ Vector v = getChildrenOfType(METHOD);
+ IMethod[] array = new IMethod[v.size()];
+ v.copyInto(array);
+ return array;
+ }
+
+ /**
+ * @see IType
+ */
+ public IPackageFragment getPackageFragment() {
+ IJavaElement parent = fParent;
+ while (parent != null) {
+ if (parent.getElementType() == IJavaElement.PACKAGE_FRAGMENT) {
+ return (IPackageFragment) parent;
+ } else {
+ parent = parent.getParent();
+ }
+ }
+ Assert.isTrue(false); // should not happen
+ return null;
+ }
+
+ /**
+ * @see IType
+ */
+ public String getSuperclassName() throws JavaModelException {
+ SourceTypeElementInfo info = (SourceTypeElementInfo) getElementInfo();
+ char[] superclassName = info.getSuperclassName();
+ if (superclassName == null) {
+ return null;
+ }
+ return new String(superclassName);
+ }
+
+ /**
+ * @see IType
+ */
+ public String[] getSuperInterfaceNames() throws JavaModelException {
+ SourceTypeElementInfo info = (SourceTypeElementInfo) getElementInfo();
+ char[][] names = info.getInterfaceNames();
+ if (names == null) {
+ return fgEmptyList;
+ }
+ String[] strings = new String[names.length];
+ for (int i = 0; i < names.length; i++) {
+ strings[i] = new String(names[i]);
+ }
+ return strings;
+ }
+
+ /**
+ * @see IType
+ */
+ public IType getType(String name) {
+ return new SourceType(this, name);
+ }
+
+ /**
+ * @see IType
+ */
+ public String getTypeQualifiedName() {
+ if (fParent.getElementType() == IJavaElement.COMPILATION_UNIT) {
+ return fName;
+ } else {
+ return ((IType) fParent).getTypeQualifiedName() + '$' + fName;
+ }
+ }
+
+ /**
+ * @see IType
+ */
+ public IType[] getTypes() throws JavaModelException {
+ Vector v = getChildrenOfType(TYPE);
+ IType[] array = new IType[v.size()];
+ v.copyInto(array);
+ return array;
+ }
+
+ /**
+ * @see IParent
+ */
+ public boolean hasChildren() throws JavaModelException {
+ return getChildren().length > 0;
+ }
+
+ /**
+ * @see IType
+ */
+ public boolean isClass() throws JavaModelException {
+ return !isInterface();
+ }
+
+ /**
+ * @see IType
+ */
+ public boolean isInterface() throws JavaModelException {
+ SourceTypeElementInfo info = (SourceTypeElementInfo) getElementInfo();
+ return info.isInterface();
+ }
+
+ /**
+ * @see IType
+ */
+ public ITypeHierarchy newSupertypeHierarchy(IProgressMonitor monitor)
+ throws JavaModelException {
+ CreateTypeHierarchyOperation op =
+ new CreateTypeHierarchyOperation(
+ this,
+ SearchEngine.createWorkspaceScope(),
+ false);
+ runOperation(op, monitor);
+ return op.getResult();
+ }
+
+ /**
+ * @see IType
+ */
+ public ITypeHierarchy newTypeHierarchy(IProgressMonitor monitor)
+ throws JavaModelException {
+ CreateTypeHierarchyOperation op =
+ new CreateTypeHierarchyOperation(
+ this,
+ SearchEngine.createWorkspaceScope(),
+ true);
+ runOperation(op, monitor);
+ return op.getResult();
+ }
+
+ /**
+ * @see IType
+ */
+ public ITypeHierarchy newTypeHierarchy(
+ IJavaProject project,
+ IProgressMonitor monitor)
+ throws JavaModelException {
+ if (project == null) {
+ throw new IllegalArgumentException("project argument cannot be null");
+ }
+
+ CreateTypeHierarchyOperation op =
+ new CreateTypeHierarchyOperation(
+ this,
+ SearchEngine.createJavaSearchScope(new IResource[] { project.getProject()}),
+ true);
+ runOperation(op, monitor);
+ return op.getResult();
+ }
+
+ /**
+ * See ISourceType.resolveType(...)
+ */
+
+ public String[][] resolveType(String typeName) throws JavaModelException {
+ ISourceType info = (ISourceType) this.getElementInfo();
+ ISearchableNameEnvironment environment =
+ ((JavaProject) getJavaProject()).getSearchableNameEnvironment();
+
+ class TypeResolveRequestor implements ISelectionRequestor {
+ String[][] answers = null;
+ void acceptType(String[] answer) {
+ if (answers == null)
+ answers = new String[][] { answer };
+ // grow
+ int length = answers.length;
+ System.arraycopy(answers, 0, answers = new String[length + 1][], 0, length);
+ answers[length] = answer;
+ }
+ public void acceptClass(
+ char[] packageName,
+ char[] className,
+ boolean needQualification) {
+ acceptType(new String[] { new String(packageName), new String(className)});
+ }
+
+ public void acceptInterface(
+ char[] packageName,
+ char[] interfaceName,
+ boolean needQualification) {
+ acceptType(new String[] { new String(packageName), new String(interfaceName)});
+ }
+
+ public void acceptError(IProblem error) {
+ }
+ public void acceptField(
+ char[] declaringTypePackageName,
+ char[] declaringTypeName,
+ char[] name) {
+ }
+ public void acceptMethod(
+ char[] declaringTypePackageName,
+ char[] declaringTypeName,
+ char[] selector,
+ char[][] parameterPackageNames,
+ char[][] parameterTypeNames) {
+ }
+ public void acceptPackage(char[] packageName) {
+ }
+
+ }
+ TypeResolveRequestor requestor = new TypeResolveRequestor();
+ SelectionEngine engine =
+ new SelectionEngine(
+ environment,
+ requestor,
+ JavaModelManager.convertConfigurableOptions(JavaCore.getOptions()));
+
+ engine.selectType(info, typeName.toCharArray());
+ return requestor.answers;
+ }
+
+ /**
+ * @private Debugging purposes
+ */
+ protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+ if (info == null) {
+ buffer.append(this.getElementName());
+ buffer.append(" (not open)");
+ } else {
+ try {
+ if (this.isInterface()) {
+ buffer.append("interface ");
+ } else {
+ buffer.append("class ");
+ }
+ buffer.append(this.getElementName());
+ } catch (JavaModelException e) {
+ buffer.append("<JavaModelException in toString of " + getElementName());
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceTypeElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceTypeElementInfo.java
new file mode 100644
index 0000000000..e38ef83eb7
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceTypeElementInfo.java
@@ -0,0 +1,321 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.core.*;
+
+/**
+ * Element info for an IType element that originated from source.
+ */
+public class SourceTypeElementInfo
+ extends MemberElementInfo
+ implements ISourceType {
+ /**
+ * The name of the superclass for this type. This name
+ * is fully qualified for binary types and is NOT
+ * fully qualified for source types.
+ */
+ protected char[] fSuperclassName;
+
+ /**
+ * The names of the interfaces this type implements or
+ * extends. These names are fully qualified in the case
+ * of a binary type, and are NOT fully qualified in the
+ * case of a source type
+ */
+ protected char[][] fSuperInterfaceNames;
+
+ /**
+ * The enclosing type name for this type.
+ *
+ * @see getEnclosingTypeName
+ */
+ protected char[] fEnclosingTypeName = null;
+
+ /**
+ * The name of the source file this type is declared in.
+ */
+ protected char[] fSourceFileName = null;
+
+ /**
+ * The name of the package this type is contained in.
+ */
+ protected char[] fPackageName = null;
+
+ /**
+ * The qualified name of this type.
+ */
+ protected char[] fQualifiedName = null;
+
+ /**
+ * The fields declared in this type
+ */
+ protected ISourceField[] fFields = null;
+
+ /**
+ * The methods declared in this type
+ */
+ protected ISourceMethod[] fMethods = null;
+
+ /**
+ * The types declared in this type
+ */
+ protected ISourceType[] fMemberTypes = null;
+
+ /**
+ * The imports in this type's compilation unit
+ */
+ protected char[][] fImports = null;
+
+ /**
+ * Backpointer to my type handle - useful for translation
+ * from info to handle.
+ */
+ protected IType fHandle = null;
+
+ /**
+ * Empty list of methods
+ */
+ protected static ISourceMethod[] fgEmptyMethods = new ISourceMethod[] {
+ };
+
+ /**
+ * Empty list of types
+ */
+ protected static ISourceType[] fgEmptyTypes = new ISourceType[] {
+ };
+
+ /**
+ * Empty list of fields
+ */
+ protected static ISourceField[] fgEmptyFields = new ISourceField[] {
+ };
+
+ /**
+ * Empty list of imports
+ */
+ protected static char[][] fgEmptyImports = new char[][] {
+ };
+
+ /**
+ * Adds the given field to this type's collection of fields
+ */
+ protected void addField(ISourceField field) {
+ if (fFields == null) {
+ fFields = fgEmptyFields;
+ }
+ ISourceField[] copy = new ISourceField[fFields.length + 1];
+ System.arraycopy(fFields, 0, copy, 0, fFields.length);
+ copy[fFields.length] = field;
+ fFields = copy;
+ }
+
+ /**
+ * Adds the given field to this type's collection of fields
+ */
+ protected void addImport(char[] i) {
+ if (fImports == null) {
+ fImports = fgEmptyImports;
+ }
+ char[][] copy = new char[fImports.length + 1][];
+ System.arraycopy(fImports, 0, copy, 0, fImports.length);
+ copy[fImports.length] = i;
+ fImports = copy;
+ }
+
+ /**
+ * Adds the given type to this type's collection of member types
+ */
+ protected void addMemberType(ISourceType type) {
+ if (fMemberTypes == null) {
+ fMemberTypes = fgEmptyTypes;
+ }
+ ISourceType[] copy = new ISourceType[fMemberTypes.length + 1];
+ System.arraycopy(fMemberTypes, 0, copy, 0, fMemberTypes.length);
+ copy[fMemberTypes.length] = type;
+ fMemberTypes = copy;
+ }
+
+ /**
+ * Adds the given method to this type's collection of methods
+ */
+ protected void addMethod(ISourceMethod method) {
+ if (fMethods == null) {
+ fMethods = fgEmptyMethods;
+ }
+ ISourceMethod[] copy = new ISourceMethod[fMethods.length + 1];
+ System.arraycopy(fMethods, 0, copy, 0, fMethods.length);
+ copy[fMethods.length] = method;
+ fMethods = copy;
+ }
+
+ /**
+ * Returns the ISourceType that is the enclosing type for this
+ * type, or <code>null</code> if this type is a top level type.
+ */
+ public ISourceType getEnclosingType() {
+ IJavaElement parent = fHandle.getParent();
+ if (parent != null && parent.getElementType() == IJavaElement.TYPE) {
+ try {
+ return (ISourceType) ((JavaElement) parent).getElementInfo();
+ } catch (JavaModelException e) {
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * @see ISourceType
+ */
+ public char[] getEnclosingTypeName() {
+ return fEnclosingTypeName;
+ }
+
+ /**
+ * @see ISourceType
+ */
+ public ISourceField[] getFields() {
+ return fFields;
+ }
+
+ /**
+ * @see ISourceType
+ */
+ public char[] getFileName() {
+ return fSourceFileName;
+ }
+
+ /**
+ * Returns the handle for this type info
+ */
+ public IType getHandle() {
+ return fHandle;
+ }
+
+ /**
+ * @see ISourceType
+ */
+ public char[][] getImports() {
+ return fImports;
+ }
+
+ /**
+ * @see ISourceType
+ */
+ public char[][] getInterfaceNames() {
+ return fSuperInterfaceNames;
+ }
+
+ /**
+ * @see ISourceType
+ */
+ public ISourceType[] getMemberTypes() {
+ return fMemberTypes;
+ }
+
+ /**
+ * @see ISourceType
+ */
+ public ISourceMethod[] getMethods() {
+ return fMethods;
+ }
+
+ /**
+ * @see ISourceType
+ */
+ public char[] getPackageName() {
+ return fPackageName;
+ }
+
+ /**
+ * @see ISourceType
+ */
+ public char[] getQualifiedName() {
+ return fQualifiedName;
+ }
+
+ /**
+ * @see ISourceType
+ */
+ public char[] getSuperclassName() {
+ return fSuperclassName;
+ }
+
+ /**
+ * @see ISourceType
+ */
+ public boolean isBinaryType() {
+ return false;
+ }
+
+ /**
+ * @see ISourceType
+ */
+ public boolean isClass() {
+ return (this.flags & IConstants.AccInterface) == 0;
+ }
+
+ /**
+ * @see ISourceType
+ */
+ public boolean isInterface() {
+ return (this.flags & IConstants.AccInterface) != 0;
+ }
+
+ /**
+ * Sets the (unqualified) name of the type that encloses this type.
+ */
+ protected void setEnclosingTypeName(char[] enclosingTypeName) {
+ fEnclosingTypeName = enclosingTypeName;
+ }
+
+ /**
+ * Sets the handle for this type info
+ */
+ protected void setHandle(IType handle) {
+ fHandle = handle;
+ }
+
+ /**
+ * Sets the name of the package this type is declared in.
+ */
+ protected void setPackageName(char[] name) {
+ fPackageName = name;
+ }
+
+ /**
+ * Sets this type's qualified name.
+ */
+ protected void setQualifiedName(char[] name) {
+ fQualifiedName = name;
+ }
+
+ /**
+ * Sets the name of the source file this type is declared in.
+ */
+ protected void setSourceFileName(char[] name) {
+ fSourceFileName = name;
+ }
+
+ /**
+ * Sets the (unqualified) name of this type's superclass
+ */
+ protected void setSuperclassName(char[] superclassName) {
+ fSuperclassName = superclassName;
+ }
+
+ /**
+ * Sets the (unqualified) names of the interfaces this type implements or extends
+ */
+ protected void setSuperInterfaceNames(char[][] superInterfaceNames) {
+ fSuperInterfaceNames = superInterfaceNames;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeVector.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeVector.java
new file mode 100644
index 0000000000..9d45479fff
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeVector.java
@@ -0,0 +1,124 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.core.IType;
+
+public final class TypeVector {
+ static int INITIAL_SIZE = 10;
+
+ public int size;
+ int maxSize;
+ IType[] elements;
+ public TypeVector() {
+ maxSize = INITIAL_SIZE;
+ size = 0;
+ elements = new IType[maxSize];
+ }
+
+ public TypeVector(IType[] types) {
+ this.size = types.length;
+ this.maxSize = this.size + 1;
+ // when an element is added, it assumes that the length is > 0
+ elements = new IType[this.maxSize];
+ System.arraycopy(types, 0, elements, 0, this.size);
+ }
+
+ public TypeVector(IType type) {
+ this.maxSize = INITIAL_SIZE;
+ this.size = 1;
+ elements = new IType[this.maxSize];
+ elements[0] = type;
+ }
+
+ public void add(IType newElement) {
+ if (size == maxSize) // knows that size starts <= maxSize
+ System.arraycopy(elements, 0, (elements = new IType[maxSize *= 2]), 0, size);
+ elements[size++] = newElement;
+ }
+
+ public void addAll(IType[] newElements) {
+ if (size + newElements.length >= maxSize) {
+ maxSize = size + newElements.length; // assume no more elements will be added
+ System.arraycopy(elements, 0, (elements = new IType[maxSize]), 0, size);
+ }
+ System.arraycopy(newElements, 0, elements, size, newElements.length);
+ size += newElements.length;
+ }
+
+ public boolean contains(IType element) {
+ for (int i = size; --i >= 0;)
+ if (element.equals(elements[i]))
+ return true;
+ return false;
+ }
+
+ public TypeVector copy() {
+ TypeVector clone = new TypeVector();
+ int length = this.elements.length;
+ System.arraycopy(
+ this.elements,
+ 0,
+ clone.elements = new IType[length],
+ 0,
+ length);
+ clone.size = this.size;
+ clone.maxSize = this.maxSize;
+ return clone;
+ }
+
+ public IType elementAt(int index) {
+ return elements[index];
+ }
+
+ public IType[] elements() {
+ if (this.size < this.maxSize) {
+ maxSize = size;
+ System.arraycopy(
+ this.elements,
+ 0,
+ (this.elements = new IType[maxSize]),
+ 0,
+ size);
+ }
+ return this.elements;
+ }
+
+ public IType find(IType element) {
+ for (int i = size; --i >= 0;)
+ if (element == elements[i])
+ return elements[i];
+ return null;
+ }
+
+ public IType remove(IType element) {
+ // assumes only one occurrence of the element exists
+ for (int i = size; --i >= 0;)
+ if (element == elements[i]) {
+ // shift the remaining elements down one spot
+ System.arraycopy(elements, i + 1, elements, i, --size - i);
+ elements[size] = null;
+ return element;
+ }
+ return null;
+ }
+
+ public void removeAll() {
+ for (int i = size; --i >= 0;)
+ elements[i] = null;
+ size = 0;
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer("[");
+ for (int i = 0; i < size; i++) {
+ buffer.append("\n");
+ buffer.append(elements[i]);
+ }
+ buffer.append("\n]");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Util.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Util.java
new file mode 100644
index 0000000000..e7ab522a32
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Util.java
@@ -0,0 +1,847 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+
+import java.io.*;
+
+/**
+ * Provides convenient utility methods to other types in this package.
+ */
+public class Util {
+
+ public interface Comparable {
+ /**
+ * Returns 0 if this and c are equal, >0 if this is greater than c,
+ * or <0 if this is less than c.
+ */
+ int compareTo(Comparable c);
+ }
+
+ public interface Comparer {
+ /**
+ * Returns 0 if a and b are equal, >0 if a is greater than b,
+ * or <0 if a is less than b.
+ */
+ int compare(Object a, Object b);
+ }
+
+ public static final String[] fgEmptyStringArray = new String[0];
+
+ /**
+ * Are we running JDK 1.1?
+ */
+ private static boolean JDK1_1 = false;
+
+ static {
+ String ver = System.getProperty("java.version");
+ JDK1_1 = ((ver != null) && ver.startsWith("1.1"));
+ }
+
+ /**
+ * Checks the type signature in String sig,
+ * starting at start and ending before end (end is not included).
+ * Returns the index of the character immediately after the signature if valid,
+ * or -1 if not valid.
+ */
+ private static int checkTypeSignature(
+ String sig,
+ int start,
+ int end,
+ boolean allowVoid) {
+ if (start >= end)
+ return -1;
+ int i = start;
+ char c = sig.charAt(i++);
+ int nestingDepth = 0;
+ while (c == '[') {
+ ++nestingDepth;
+ if (i >= end)
+ return -1;
+ c = sig.charAt(i++);
+ }
+ switch (c) {
+ case 'B' :
+ case 'C' :
+ case 'D' :
+ case 'F' :
+ case 'I' :
+ case 'J' :
+ case 'S' :
+ case 'Z' :
+ break;
+ case 'V' :
+ if (!allowVoid)
+ return -1;
+ // array of void is not allowed
+ if (nestingDepth != 0)
+ return -1;
+ break;
+ case 'L' :
+ int semicolon = sig.indexOf(';', i);
+ // Must have at least one character between L and ;
+ if (semicolon <= i || semicolon >= end)
+ return -1;
+ i = semicolon + 1;
+ break;
+ default :
+ return -1;
+ }
+ return i;
+ }
+
+ /**
+ * Combines two hash codes to make a new one.
+ */
+ public static int combineHashCodes(int hashCode1, int hashCode2) {
+ return hashCode1 * 17 + hashCode2;
+ }
+
+ /**
+ * Compares two byte arrays.
+ * Returns <0 if a byte in a is less than the corresponding byte in b, or if a is shorter, or if a is null.
+ * Returns >0 if a byte in a is greater than the corresponding byte in b, or if a is longer, or if b is null.
+ * Returns 0 if they are equal or both null.
+ */
+ public static int compare(byte[] a, byte[] b) {
+ if (a == b)
+ return 0;
+ if (a == null)
+ return -1;
+ if (b == null)
+ return 1;
+ int len = Math.min(a.length, b.length);
+ for (int i = 0; i < len; ++i) {
+ int diff = a[i] - b[i];
+ if (diff != 0)
+ return diff;
+ }
+ if (a.length > len)
+ return 1;
+ if (b.length > len)
+ return -1;
+ return 0;
+ }
+
+ /**
+ * Compares two char arrays lexicographically.
+ * The comparison is based on the Unicode value of each character in
+ * the char arrays.
+ * @return the value <code>0</code> if a is equal to
+ * b; a value less than <code>0</code> if a
+ * is lexicographically less than b; and a
+ * value greater than <code>0</code> if a is
+ * lexicographically greater than b.
+ */
+ public static int compare(char[] v1, char[] v2) {
+ int len1 = v1.length;
+ int len2 = v2.length;
+ int n = Math.min(len1, len2);
+ int i = 0;
+ while (n-- != 0) {
+ if (v1[i] != v2[i]) {
+ return v1[i] - v2[i];
+ }
+ ++i;
+ }
+ return len1 - len2;
+ }
+
+ /**
+ * Concatenate two strings with a char in between.
+ * @see concat(String, String)
+ */
+ public static String concat(String s1, char c, String s2) {
+ if (s1 == null)
+ s1 = "null";
+ if (s2 == null)
+ s2 = "null";
+ int l1 = s1.length();
+ int l2 = s2.length();
+ char[] buf = new char[l1 + 1 + l2];
+ s1.getChars(0, l1, buf, 0);
+ buf[l1] = c;
+ s2.getChars(0, l2, buf, l1 + 1);
+ return new String(buf);
+ }
+
+ /**
+ * Concatenate two strings.
+ * Much faster than using +, which:
+ * - creates a StringBuffer,
+ * - which is synchronized,
+ * - of default size, so the resulting char array is
+ * often larger than needed.
+ * This implementation creates an extra char array, since the
+ * String constructor copies its argument, but there's no way around this.
+ */
+ public static String concat(String s1, String s2) {
+ if (s1 == null)
+ s1 = "null";
+ if (s2 == null)
+ s2 = "null";
+ int l1 = s1.length();
+ int l2 = s2.length();
+ char[] buf = new char[l1 + l2];
+ s1.getChars(0, l1, buf, 0);
+ s2.getChars(0, l2, buf, l1);
+ return new String(buf);
+ }
+
+ /**
+ * Concatenate three strings.
+ * @see concat(String, String)
+ */
+ public static String concat(String s1, String s2, String s3) {
+ if (s1 == null)
+ s1 = "null";
+ if (s2 == null)
+ s2 = "null";
+ if (s3 == null)
+ s3 = "null";
+ int l1 = s1.length();
+ int l2 = s2.length();
+ int l3 = s3.length();
+ char[] buf = new char[l1 + l2 + l3];
+ s1.getChars(0, l1, buf, 0);
+ s2.getChars(0, l2, buf, l1);
+ s3.getChars(0, l3, buf, l1 + l2);
+ return new String(buf);
+ }
+
+ /**
+ * Converts a type signature from the IBinaryType representation to the DC representation.
+ */
+ public static String convertTypeSignature(char[] sig) {
+ return new String(sig).replace('/', '.');
+ }
+
+ /**
+ * Compares two arrays using equals() on the elements.
+ * Either or both arrays may be null.
+ * Returns true if both are null.
+ * Returns false if only one is null.
+ * If both are arrays, returns true iff they have the same length and
+ * all elements are equal.
+ */
+ public static boolean equalArraysOrNull(int[] a, int[] b) {
+ if (a == b)
+ return true;
+ if (a == null || b == null)
+ return false;
+ int len = a.length;
+ if (len != b.length)
+ return false;
+ for (int i = 0; i < len; ++i) {
+ if (a[i] != b[i])
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Compares two arrays using equals() on the elements.
+ * Either or both arrays may be null.
+ * Returns true if both are null.
+ * Returns false if only one is null.
+ * If both are arrays, returns true iff they have the same length and
+ * all elements compare true with equals.
+ */
+ public static boolean equalArraysOrNull(Object[] a, Object[] b) {
+ if (a == b)
+ return true;
+ if (a == null || b == null)
+ return false;
+
+ int len = a.length;
+ if (len != b.length)
+ return false;
+ for (int i = 0; i < len; ++i) {
+ if (!a[i].equals(b[i]))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Compares two String arrays using equals() on the elements.
+ * The arrays are first sorted.
+ * Either or both arrays may be null.
+ * Returns true if both are null.
+ * Returns false if only one is null.
+ * If both are arrays, returns true iff they have the same length and
+ * iff, after sorting both arrays, all elements compare true with equals.
+ * The original arrays are left untouched.
+ */
+ public static boolean equalArraysOrNullSortFirst(String[] a, String[] b) {
+ if (a == b)
+ return true;
+ if (a == null || b == null)
+ return false;
+ int len = a.length;
+ if (len != b.length)
+ return false;
+ if (len >= 2) { // only need to sort if more than two items
+ a = sortCopy(a);
+ b = sortCopy(b);
+ }
+ for (int i = 0; i < len; ++i) {
+ if (!a[i].equals(b[i]))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Compares two arrays using equals() on the elements.
+ * The arrays are first sorted.
+ * Either or both arrays may be null.
+ * Returns true if both are null.
+ * Returns false if only one is null.
+ * If both are arrays, returns true iff they have the same length and
+ * iff, after sorting both arrays, all elements compare true with equals.
+ * The original arrays are left untouched.
+ */
+ public static boolean equalArraysOrNullSortFirst(
+ Comparable[] a,
+ Comparable[] b) {
+ if (a == b)
+ return true;
+ if (a == null || b == null)
+ return false;
+ int len = a.length;
+ if (len != b.length)
+ return false;
+ if (len >= 2) { // only need to sort if more than two items
+ a = sortCopy(a);
+ b = sortCopy(b);
+ }
+ for (int i = 0; i < len; ++i) {
+ if (!a[i].equals(b[i]))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Compares two objects using equals().
+ * Either or both array may be null.
+ * Returns true if both are null.
+ * Returns false if only one is null.
+ * Otherwise, return the result of comparing with equals().
+ */
+ public static boolean equalOrNull(Object a, Object b) {
+ if (a == b) {
+ return true;
+ }
+ if (a == null || b == null) {
+ return false;
+ }
+ return a.equals(b);
+ }
+
+ /**
+ * Given a qualified name, extract the last component.
+ * If the input is not qualified, the same string is answered.
+ */
+ public static String extractLastName(String qualifiedName) {
+ int i = qualifiedName.lastIndexOf('.');
+ if (i == -1)
+ return qualifiedName;
+ return qualifiedName.substring(i + 1);
+ }
+
+ /**
+ * Extracts the parameter types from a method signature.
+ */
+ public static String[] extractParameterTypes(char[] sig) {
+ int count = getParameterCount(sig);
+ String[] result = new String[count];
+ if (count == 0)
+ return result;
+ int i = CharOperation.indexOf('(', sig) + 1;
+ count = 0;
+ int len = sig.length;
+ int start = i;
+ for (;;) {
+ if (i == len)
+ break;
+ char c = sig[i];
+ if (c == ')')
+ break;
+ if (c == '[') {
+ ++i;
+ } else
+ if (c == 'L') {
+ i = CharOperation.indexOf(';', sig, i + 1) + 1;
+ Assert.isTrue(i != 0);
+ result[count++] = convertTypeSignature(CharOperation.subarray(sig, start, i));
+ start = i;
+ } else {
+ ++i;
+ result[count++] = convertTypeSignature(CharOperation.subarray(sig, start, i));
+ start = i;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Extracts the return type from a method signature.
+ */
+ public static String extractReturnType(String sig) {
+ int i = sig.lastIndexOf(')');
+ Assert.isTrue(i != -1);
+ return sig.substring(i + 1);
+ }
+
+ /**
+ * Returns the number of parameter types in a method signature.
+ */
+ public static int getParameterCount(char[] sig) {
+ int i = CharOperation.indexOf('(', sig) + 1;
+ Assert.isTrue(i != 0);
+ int count = 0;
+ int len = sig.length;
+ for (;;) {
+ if (i == len)
+ break;
+ char c = sig[i];
+ if (c == ')')
+ break;
+ if (c == '[') {
+ ++i;
+ } else
+ if (c == 'L') {
+ ++count;
+ i = CharOperation.indexOf(';', sig, i + 1) + 1;
+ Assert.isTrue(i != 0);
+ } else {
+ ++count;
+ ++i;
+ }
+ }
+ return count;
+ }
+
+ /**
+ * Returns true if the given method signature is valid,
+ * false if it is not.
+ */
+ public static boolean isValidMethodSignature(String sig) {
+ int len = sig.length();
+ if (len == 0)
+ return false;
+ int i = 0;
+ char c = sig.charAt(i++);
+ if (c != '(')
+ return false;
+ if (i >= len)
+ return false;
+ while (sig.charAt(i) != ')') {
+ // Void is not allowed as a parameter type.
+ i = checkTypeSignature(sig, i, len, false);
+ if (i == -1)
+ return false;
+ if (i >= len)
+ return false;
+ }
+ ++i;
+ i = checkTypeSignature(sig, i, len, true);
+ return i == len;
+ }
+
+ /**
+ * Returns true if the given type signature is valid,
+ * false if it is not.
+ */
+ public static boolean isValidTypeSignature(String sig, boolean allowVoid) {
+ int len = sig.length();
+ return checkTypeSignature(sig, 0, len, allowVoid) == len;
+ }
+
+ /**
+ * Sort the objects in the given collection using the given sort order.
+ */
+ private static void quickSort(
+ Object[] sortedCollection,
+ int left,
+ int right,
+ int[] sortOrder) {
+ int original_left = left;
+ int original_right = right;
+ int mid = sortOrder[(left + right) / 2];
+ do {
+ while (sortOrder[left] < mid) {
+ left++;
+ }
+ while (mid < sortOrder[right]) {
+ right--;
+ }
+ if (left <= right) {
+ Object tmp = sortedCollection[left];
+ sortedCollection[left] = sortedCollection[right];
+ sortedCollection[right] = tmp;
+ int tmp2 = sortOrder[left];
+ sortOrder[left] = sortOrder[right];
+ sortOrder[right] = tmp2;
+ left++;
+ right--;
+ }
+ }
+ while (left <= right);
+ if (original_left < right) {
+ quickSort(sortedCollection, original_left, right, sortOrder);
+ }
+ if (left < original_right) {
+ quickSort(sortedCollection, left, original_right, sortOrder);
+ }
+ }
+
+ /**
+ * Sort the objects in the given collection using the given comparer.
+ */
+ private static void quickSort(
+ Object[] sortedCollection,
+ int left,
+ int right,
+ Comparer comparer) {
+ int original_left = left;
+ int original_right = right;
+ Object mid = sortedCollection[(left + right) / 2];
+ do {
+ while (comparer.compare(sortedCollection[left], mid) < 0) {
+ left++;
+ }
+ while (comparer.compare(mid, sortedCollection[right]) < 0) {
+ right--;
+ }
+ if (left <= right) {
+ Object tmp = sortedCollection[left];
+ sortedCollection[left] = sortedCollection[right];
+ sortedCollection[right] = tmp;
+ left++;
+ right--;
+ }
+ }
+ while (left <= right);
+ if (original_left < right) {
+ quickSort(sortedCollection, original_left, right, comparer);
+ }
+ if (left < original_right) {
+ quickSort(sortedCollection, left, original_right, comparer);
+ }
+ }
+
+ /**
+ * Sort the strings in the given collection.
+ */
+ private static void quickSort(String[] sortedCollection, int left, int right) {
+ int original_left = left;
+ int original_right = right;
+ String mid = sortedCollection[(left + right) / 2];
+ do {
+ while (sortedCollection[left].compareTo(mid) < 0) {
+ left++;
+ }
+ while (mid.compareTo(sortedCollection[right]) < 0) {
+ right--;
+ }
+ if (left <= right) {
+ String tmp = sortedCollection[left];
+ sortedCollection[left] = sortedCollection[right];
+ sortedCollection[right] = tmp;
+ left++;
+ right--;
+ }
+ }
+ while (left <= right);
+ if (original_left < right) {
+ quickSort(sortedCollection, original_left, right);
+ }
+ if (left < original_right) {
+ quickSort(sortedCollection, left, original_right);
+ }
+ }
+
+ /**
+ * Sort the comparable objects in the given collection.
+ */
+ private static void quickSort(
+ Comparable[] sortedCollection,
+ int left,
+ int right) {
+ int original_left = left;
+ int original_right = right;
+ Comparable mid = sortedCollection[(left + right) / 2];
+ do {
+ while (sortedCollection[left].compareTo(mid) < 0) {
+ left++;
+ }
+ while (mid.compareTo(sortedCollection[right]) < 0) {
+ right--;
+ }
+ if (left <= right) {
+ Comparable tmp = sortedCollection[left];
+ sortedCollection[left] = sortedCollection[right];
+ sortedCollection[right] = tmp;
+ left++;
+ right--;
+ }
+ }
+ while (left <= right);
+ if (original_left < right) {
+ quickSort(sortedCollection, original_left, right);
+ }
+ if (left < original_right) {
+ quickSort(sortedCollection, left, original_right);
+ }
+ }
+
+ /**
+ * Sort the strings in the given collection in reverse alphabetical order.
+ */
+ private static void quickSortReverse(
+ String[] sortedCollection,
+ int left,
+ int right) {
+ int original_left = left;
+ int original_right = right;
+ String mid = sortedCollection[(left + right) / 2];
+ do {
+ while (sortedCollection[left].compareTo(mid) > 0) {
+ left++;
+ }
+ while (mid.compareTo(sortedCollection[right]) > 0) {
+ right--;
+ }
+ if (left <= right) {
+ String tmp = sortedCollection[left];
+ sortedCollection[left] = sortedCollection[right];
+ sortedCollection[right] = tmp;
+ left++;
+ right--;
+ }
+ }
+ while (left <= right);
+ if (original_left < right) {
+ quickSortReverse(sortedCollection, original_left, right);
+ }
+ if (left < original_right) {
+ quickSortReverse(sortedCollection, left, original_right);
+ }
+ }
+
+ public static byte[] readContentsAsBytes(InputStream input)
+ throws IOException {
+ BufferedInputStream bufferedInputStream = null;
+ try {
+ final int BUF_SIZE = 8192;
+ byte[] buf = new byte[BUF_SIZE];
+ int read;
+ int totalRead = 0;
+ bufferedInputStream = new BufferedInputStream(input);
+ while (totalRead < BUF_SIZE
+ && (read = bufferedInputStream.read(buf, totalRead, BUF_SIZE - totalRead))
+ != -1) {
+ totalRead += read;
+ }
+ if (totalRead < BUF_SIZE) {
+ byte[] result = new byte[totalRead];
+ System.arraycopy(buf, 0, result, 0, totalRead);
+ return result;
+ }
+ ByteArrayOutputStream out = new ByteArrayOutputStream(BUF_SIZE * 2);
+ out.write(buf);
+ while ((read = bufferedInputStream.read(buf, 0, BUF_SIZE)) != -1) {
+ out.write(buf, 0, read);
+ }
+ return out.toByteArray();
+ } finally {
+ try {
+ if (bufferedInputStream != null) {
+ bufferedInputStream.close();
+ }
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+
+ /**
+ * Sorts an array of objects in place, using the sort order given for each item.
+ */
+ public static void sort(Object[] objects, int[] sortOrder) {
+ if (objects.length > 1)
+ quickSort(objects, 0, objects.length - 1, sortOrder);
+ }
+
+ /**
+ * Sorts an array of objects in place.
+ * The given comparer compares pairs of items.
+ */
+ public static void sort(Object[] objects, Comparer comparer) {
+ if (objects.length > 1)
+ quickSort(objects, 0, objects.length - 1, comparer);
+ }
+
+ /**
+ * Sorts an array of strings in place using quicksort.
+ */
+ public static void sort(String[] strings) {
+ if (strings.length > 1)
+ quickSort(strings, 0, strings.length - 1);
+ }
+
+ /**
+ * Sorts an array of Comparable objects in place.
+ */
+ public static void sort(Comparable[] objects) {
+ if (objects.length > 1)
+ quickSort(objects, 0, objects.length - 1);
+ }
+
+ /**
+ * Sorts an array of Strings, returning a new array
+ * with the sorted items. The original array is left untouched.
+ */
+ public static Object[] sortCopy(Object[] objects, Comparer comparer) {
+ int len = objects.length;
+ Object[] copy = new Object[len];
+ System.arraycopy(objects, 0, copy, 0, len);
+ sort(copy, comparer);
+ return copy;
+ }
+
+ /**
+ * Sorts an array of Strings, returning a new array
+ * with the sorted items. The original array is left untouched.
+ */
+ public static String[] sortCopy(String[] objects) {
+ int len = objects.length;
+ String[] copy = new String[len];
+ System.arraycopy(objects, 0, copy, 0, len);
+ sort(copy);
+ return copy;
+ }
+
+ /**
+ * Sorts an array of Comparable objects, returning a new array
+ * with the sorted items. The original array is left untouched.
+ */
+ public static Comparable[] sortCopy(Comparable[] objects) {
+ int len = objects.length;
+ Comparable[] copy = new Comparable[len];
+ System.arraycopy(objects, 0, copy, 0, len);
+ sort(copy);
+ return copy;
+ }
+
+ /**
+ * Sorts an array of strings in place using quicksort
+ * in reverse alphabetical order.
+ */
+ public static void sortReverseOrder(String[] strings) {
+ if (strings.length > 1)
+ quickSortReverse(strings, 0, strings.length - 1);
+ }
+
+ /**
+ * Converts a String[] to char[][].
+ */
+ public static char[][] toCharArrays(String[] a) {
+ int len = a.length;
+ char[][] result = new char[len][];
+ for (int i = 0; i < len; ++i) {
+ result[i] = toChars(a[i]);
+ }
+ return result;
+ }
+
+ /**
+ * Converts a String to char[].
+ */
+ public static char[] toChars(String s) {
+ int len = s.length();
+ char[] chars = new char[len];
+ s.getChars(0, len, chars, 0);
+ return chars;
+ }
+
+ /**
+ * Converts a String to char[][], where segments are separate by '.'.
+ */
+ public static char[][] toCompoundChars(String s) {
+ int len = s.length();
+ if (len == 0) {
+ return new char[0][];
+ }
+ int segCount = 1;
+ for (int off = s.indexOf('.'); off != -1; off = s.indexOf('.', off + 1)) {
+ ++segCount;
+ }
+ char[][] segs = new char[segCount][];
+ int start = 0;
+ for (int i = 0; i < segCount; ++i) {
+ int dot = s.indexOf('.', start);
+ int end = (dot == -1 ? s.length() : dot);
+ segs[i] = new char[end - start];
+ s.getChars(start, end, segs[i], 0);
+ start = end + 1;
+ }
+ return segs;
+ }
+
+ /**
+ * Converts a char[][] to String, where segments are separated by '.'.
+ */
+ public static String toString(char[][] c) {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0, max = c.length; i < max; ++i) {
+ if (i != 0)
+ sb.append('.');
+ sb.append(c[i]);
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Converts a char[][] and a char[] to String, where segments are separated by '.'.
+ */
+ public static String toString(char[][] c, char[] d) {
+ if (c == null)
+ return new String(d);
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0, max = c.length; i < max; ++i) {
+ sb.append(c[i]);
+ sb.append('.');
+ }
+ sb.append(d);
+ return sb.toString();
+ }
+
+ /**
+ * Converts a char[] to String.
+ */
+ public static String toString(char[] c) {
+ return new String(c);
+ }
+
+ /**
+ * Asserts that the given method signature is valid.
+ */
+ public static void validateMethodSignature(String sig) {
+ Assert.isTrue(isValidMethodSignature(sig));
+ }
+
+ /**
+ * Asserts that the given type signature is valid.
+ */
+ public static void validateTypeSignature(String sig, boolean allowVoid) {
+ Assert.isTrue(isValidTypeSignature(sig, allowVoid));
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ValidateSourceElementOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ValidateSourceElementOperation.java
new file mode 100644
index 0000000000..4f3579348c
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ValidateSourceElementOperation.java
@@ -0,0 +1,67 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+
+/**
+ * This operation is used to find warnings and/or errors in a
+ * source element - i.e. an element that implements <code>ISourceReference</code>.
+ * The result is a collection of <code>IMarkers</code> representing warnings
+ * and errors, or <code>null</code> if no warnings or errors are found.
+ * Errors/warnings are determined in the context of the current built state
+ * of the Java Model. The resulting <code>IMarkers</code> are not attached
+ * to an <code>IResource</code>.
+ */
+public class ValidateSourceElementOperation extends JavaModelOperation {
+ /**
+ * Validate the given Java Model element.
+ */
+ public ValidateSourceElementOperation(IJavaElement element) {
+ super(element);
+ }
+
+ /**
+ * Validate the element - TBD.
+ */
+ protected void executeOperation() throws JavaModelException {
+ }
+
+ /**
+ * Returns the errors and warnings as a set of <code>IMarkers</code>,
+ * or <code>null</code> if no errors or warnings were found.
+ */
+ public IMarker[] getResult() {
+ return null;
+ }
+
+ /**
+ * Possible failures: <ul>
+ * <li>ELEMENTS_TO_PROCESS - an element was not provided
+ * <li>INVALID_ELEMENT_TYPES - the element provided is not a source element
+ * <li>ELEMENT_NOT_PRESENT - the element does not exist
+ * </ul>
+ */
+ public IJavaModelStatus verify() {
+ IJavaModelStatus status = super.verify();
+ if (!status.isOK()) {
+ return status;
+ }
+ if (!(getElementToProcess() instanceof ISourceReference)) {
+ return new JavaModelStatus(
+ IJavaModelStatusConstants.INVALID_ELEMENT_TYPES,
+ getElementToProcess());
+ }
+ if (!getElementToProcess().exists()) {
+ return new JavaModelStatus(
+ IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST,
+ getElementToProcess());
+ }
+ return JavaModelStatus.VERIFIED_OK;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/WorkingCopy.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/WorkingCopy.java
new file mode 100644
index 0000000000..99e8d5095c
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/WorkingCopy.java
@@ -0,0 +1,341 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.jdt.internal.compiler.IProblem;
+import org.eclipse.jdt.core.*;
+
+import java.util.Vector;
+
+/**
+ * Implementation of a working copy compilation unit. A working
+ * copy maintains the timestamp of the resource it was created
+ * from.
+ */
+
+/* package */
+class WorkingCopy extends CompilationUnit {
+
+ /**
+ * A boolean indicating if this working copy has been
+ * destroyed. Once destroyed, it cannot be opened
+ * and non-handle info can not be accessed. This is
+ * never true if this compilation unit is not a working
+ * copy.
+ */
+ protected boolean fDestroyed = false;
+ /**
+ */
+ protected WorkingCopy(IPackageFragment parent, String name) {
+ super(parent, name);
+ }
+
+ /**
+ * @see IWorkingCopy
+ */
+ public void commit(boolean force, IProgressMonitor monitor)
+ throws JavaModelException {
+ CommitWorkingCopyOperation op = new CommitWorkingCopyOperation(this, force);
+ runOperation(op, monitor);
+ }
+
+ /**
+ * Returns a new element info for this element.
+ */
+ protected OpenableElementInfo createElementInfo() {
+ return new WorkingCopyElementInfo();
+ }
+
+ /**
+ * @see IWorkingCopy
+ */
+ public void destroy() {
+ try {
+ close();
+ } catch (JavaModelException e) {
+ // do nothing
+ }
+ fDestroyed = true;
+ }
+
+ /**
+ * Working copies must be identical to be equal.
+ *
+ * @see Object#equals
+ */
+ public boolean equals(Object o) {
+ return this == o;
+ }
+
+ /**
+ * @see IWorkingCopy
+ */
+ public IJavaElement getOriginal(IJavaElement workingCopyElement) {
+ //not a element contained in a compilation unit
+ int javaElementType = workingCopyElement.getElementType();
+ if (javaElementType < COMPILATION_UNIT || javaElementType == CLASS_FILE) {
+ return null;
+ }
+ if (workingCopyElement instanceof BinaryMember) {
+ return null;
+ }
+ IJavaElement parent = workingCopyElement.getParent();
+ Vector hierarchy = new Vector(4);
+
+ while (parent.getElementType() > COMPILATION_UNIT) {
+ hierarchy.addElement(parent);
+ parent = parent.getParent();
+ }
+ if (parent.getElementType() == COMPILATION_UNIT) {
+ hierarchy.addElement(((ICompilationUnit) parent).getOriginalElement());
+ }
+
+ ICompilationUnit cu = (ICompilationUnit) getOriginalElement();
+ if (javaElementType == COMPILATION_UNIT) {
+ parent = workingCopyElement;
+ }
+ if (((ICompilationUnit) parent).isWorkingCopy()
+ && !((ICompilationUnit) parent).getOriginalElement().equals(cu)) {
+ return null;
+ }
+ switch (javaElementType) {
+ case PACKAGE_DECLARATION :
+ return cu.getPackageDeclaration(workingCopyElement.getElementName());
+ case IMPORT_DECLARATION :
+ return cu.getImport(workingCopyElement.getElementName());
+ case TYPE :
+ if (hierarchy.size() == 1) {
+ return cu.getType(workingCopyElement.getElementName());
+ } else {
+ //inner type
+ return getOriginalType(hierarchy).getType(workingCopyElement.getElementName());
+ }
+ case METHOD :
+ IType type;
+ if (hierarchy.size() == 2) {
+ String typeName = ((IJavaElement) hierarchy.elementAt(0)).getElementName();
+ type = cu.getType(typeName);
+ } else {
+ //inner type
+ type = getOriginalType(hierarchy);
+ }
+ return type.getMethod(
+ workingCopyElement.getElementName(),
+ ((IMethod) workingCopyElement).getParameterTypes());
+ case FIELD :
+ if (hierarchy.size() == 2) {
+ String typeName = ((IJavaElement) hierarchy.elementAt(0)).getElementName();
+ type = cu.getType(typeName);
+ } else {
+ //inner type
+ type = getOriginalType(hierarchy);
+ }
+ return type.getField(workingCopyElement.getElementName());
+ case INITIALIZER :
+ if (hierarchy.size() == 2) {
+ String typeName = ((IJavaElement) hierarchy.elementAt(0)).getElementName();
+ type = cu.getType(typeName);
+ } else {
+ //inner type
+ type = getOriginalType(hierarchy);
+ }
+ return type.getInitializer(
+ ((Initializer) workingCopyElement).getOccurrenceCount());
+ case COMPILATION_UNIT :
+ return cu;
+ default :
+ return null;
+ }
+ }
+
+ /**
+ * @see IWorkingCopy
+ */
+ public IJavaElement getOriginalElement() {
+ return new CompilationUnit((IPackageFragment) getParent(), getElementName());
+ }
+
+ protected IType getOriginalType(Vector hierarchy) {
+ int size = hierarchy.size() - 1;
+ ICompilationUnit typeCU = (ICompilationUnit) hierarchy.elementAt(size);
+ String typeName =
+ ((IJavaElement) hierarchy.elementAt(size - 1)).getElementName();
+ IType type = typeCU.getType(typeName);
+ size = size - 2;
+ while (size > -1) {
+ typeName = ((IJavaElement) hierarchy.elementAt(size)).getElementName();
+ type = ((IType) type).getType(typeName);
+ size--;
+ }
+ return type;
+ }
+
+ /**
+ * Returns <code>null<code> - a working copy does not have an underlying resource.
+ *
+ * @see IJavaElement
+ */
+ public IResource getUnderlyingResource() throws JavaModelException {
+ return null;
+ }
+
+ /**
+ * @see IWorkingCopy
+ */
+ public IJavaElement getWorkingCopy() throws JavaModelException {
+ return this;
+ }
+
+ /**
+ * @see IWorkingCopy
+ */
+ public boolean isBasedOn(IResource resource) {
+ if (resource.getType() != IResource.FILE) {
+ return false;
+ }
+ if (fDestroyed) {
+ return false;
+ }
+ try {
+ // if resource got deleted, then #getModificationStamp() will answer IResource.NULL_STAMP, which is always different from the cached
+ // timestamp
+ return ((CompilationUnitElementInfo) getElementInfo()).fTimestamp
+ == ((IFile) resource).getModificationStamp();
+ } catch (JavaModelException e) {
+ return false;
+ }
+ }
+
+ /**
+ * @see IWorkingCopy
+ */
+ public boolean isWorkingCopy() {
+ return true;
+ }
+
+ /**
+ * @see IOpenable
+ * @see IWorkingCopy
+ *
+ * @exception JavaModelException attempting to open a read only element for something other than navigation
+ * or if this is a working copy being opened after it has been destroyed.
+ */
+ public void open(IProgressMonitor pm) throws JavaModelException {
+ if (fDestroyed) {
+ throw newNotPresentException();
+ } else {
+ super.open(pm);
+ }
+ }
+
+ /**
+ * @see Openable
+ */
+ protected IBuffer openBuffer(IProgressMonitor pm) throws JavaModelException {
+ ICompilationUnit original = (ICompilationUnit) this.getOriginalElement();
+ IBuffer buf =
+ getBufferManager().openBuffer(
+ original.getBuffer().getCharacters(),
+ pm,
+ this,
+ isReadOnly());
+ buf.addBufferChangedListener(this);
+ return buf;
+ }
+
+ /**
+ * @see IWorkingCopy
+ */
+ public IMarker[] reconcile() throws JavaModelException {
+ // create the delta builder (this remembers the current content of the cu)
+ JavaElementDeltaBuilder deltaBuilder = new JavaElementDeltaBuilder(this);
+
+ // update the element infos with the content of the working copy
+ this.makeConsistent(null);
+
+ // build the deltas
+ deltaBuilder.buildDeltas();
+
+ // fire the deltas
+ boolean shouldFire = false;
+ JavaModelManager manager = null;
+ if (deltaBuilder.delta != null) {
+ manager = (JavaModelManager) JavaModelManager.getJavaModelManager();
+ if (deltaBuilder.delta.getAffectedChildren().length > 0) {
+ manager.registerJavaModelDelta(deltaBuilder.delta);
+ shouldFire = true;
+ }
+ }
+ if (shouldFire)
+ manager.fire();
+
+ // report syntax problems
+ return null;
+ /* DISABLED because of 1GAJJ3A: ITPJUI:WINNT - Deadlock in Java Editor
+ try {
+ WorkingCopyElementInfo info = (WorkingCopyElementInfo)JavaModelManager.getJavaModelManager().getInfo(this);
+ IProblem[] problems = info.problems;
+ int length;
+ IResource resource = getOriginalElement().getUnderlyingResource();
+
+ // flush previous markers first
+ IMarker[] markers = resource.findMarkers(IJavaModelMarker.TRANSIENT_PROBLEM, true, IResource.DEPTH_ONE);
+ resource.getWorkspace().deleteMarkers(markers);
+
+ // create markers if needed
+ if (problems == null || (length = problems.length) == 0) return null;
+ markers = new IMarker[length];
+ for (int i = 0; i < length; i++) {
+ IProblem problem = problems[i];
+ IMarker marker = resource.createMarker(IJavaModelMarker.TRANSIENT_PROBLEM);
+ marker.setAttribute(IJavaModelMarker.ID, problem.getID());
+ marker.setAttribute(IJavaModelMarker.CHAR_START, problem.getSourceStart());
+ marker.setAttribute(IJavaModelMarker.CHAR_END, problem.getSourceEnd() + 1);
+ marker.setAttribute(IJavaModelMarker.LINE_NUMBER, problem.getSourceLineNumber());
+ marker.setAttribute(IMarker.LOCATION, "#" + problem.getSourceLineNumber());
+ marker.setAttribute(IMarker.MESSAGE, problem.getMessage());
+ marker.setAttribute(IMarker.PRIORITY, (problem.isWarning() ? IMarker.PRIORITY_LOW : IMarker.PRIORITY_HIGH));
+ markers[i] = marker;
+ }
+ return markers;
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ }
+ */
+ }
+
+ /**
+ * @see IWorkingCopy
+ */
+ public void restore() throws JavaModelException {
+ if (!fDestroyed) {
+ CompilationUnit original = (CompilationUnit) getOriginalElement();
+ getBuffer().setContents(original.getContents());
+
+ long timeStamp =
+ ((IFile) original.getUnderlyingResource()).getModificationStamp();
+ if (timeStamp == IResource.NULL_STAMP) {
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.INVALID_RESOURCE));
+ }
+ ((CompilationUnitElementInfo) getElementInfo()).fTimestamp = timeStamp;
+ makeConsistent(null);
+ }
+ }
+
+ /**
+ * @private Debugging purposes
+ */
+ protected void toString(int tab, StringBuffer buffer) {
+ buffer.append(this.tabString(tab));
+ buffer.append("(working copy)\n");
+ super.toString(tab, buffer);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/WorkingCopyElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/WorkingCopyElementInfo.java
new file mode 100644
index 0000000000..99b48dc2d4
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/WorkingCopyElementInfo.java
@@ -0,0 +1,11 @@
+package org.eclipse.jdt.internal.core;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IProblem;
+
+public class WorkingCopyElementInfo extends CompilationUnitElementInfo {
+ IProblem[] problems;
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BinaryBrokerKey.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BinaryBrokerKey.java
new file mode 100644
index 0000000000..2ba61f7dcf
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BinaryBrokerKey.java
@@ -0,0 +1,61 @@
+package org.eclipse.jdt.internal.core.builder;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.jdt.internal.core.Assert;
+
+/**
+ * A BinaryBrokerKey describes the type and CRC for which
+ * binary has been given to the binary broker.
+ *
+ * @see IBinaryBroker
+ */
+public class BinaryBrokerKey {
+ protected IType fType;
+ protected int fCRC;
+
+ /**
+ * Create a binary broker key for the given type and 32-bit CRC.
+ * The type handle must be non-state-specific.
+ */
+ public BinaryBrokerKey(IType type, int crc) {
+ Assert.isTrue(!type.isStateSpecific());
+ fType = type;
+ fCRC = crc;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof BinaryBrokerKey))
+ return false;
+ BinaryBrokerKey k = (BinaryBrokerKey) o;
+ return fCRC == k.fCRC && fType.equals(k.fType);
+ }
+
+ /**
+ * Returns the CRC.
+ */
+ public int getCRC() {
+ return fCRC;
+ }
+
+ /**
+ * Returns the type.
+ */
+ public IType getType() {
+ return fType;
+ }
+
+ /**
+ * Returns the hash code.
+ */
+ public int hashCode() {
+ // The CRC should be unique enough for a hash code.
+ return fCRC;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BuildEvent.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BuildEvent.java
new file mode 100644
index 0000000000..d8eea28d19
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BuildEvent.java
@@ -0,0 +1,68 @@
+package org.eclipse.jdt.internal.core.builder;
+
+public class BuildEvent {
+ protected ISourceFragment fSourceFragment;
+ protected int fNewErrorCount;
+ protected int fFixedErrorCount;
+ protected int fNewWarningCount;
+ protected int fFixedWarningCount;
+ /**
+ * Internal - Constructs a new build event object.
+ */
+ public BuildEvent(
+ ISourceFragment sourceFragment,
+ int newErrorCount,
+ int fixedErrorCount,
+ int newWarningCount,
+ int fixedWarningCount) {
+
+ fSourceFragment = sourceFragment;
+ fNewErrorCount = newErrorCount;
+ fFixedErrorCount = fixedErrorCount;
+ fNewWarningCount = newWarningCount;
+ fFixedWarningCount = fixedWarningCount;
+ }
+
+ /**
+ * Returns the number of errors fixed since
+ * the beginning of the build.
+ */
+ public int getFixedErrorCount() {
+ return fFixedErrorCount;
+ }
+
+ /**
+ * Returns the number of warnings fixed since
+ * the beginning of the build.
+ */
+ public int getFixedWarningCount() {
+ return fFixedWarningCount;
+ }
+
+ /**
+ * Returns the number of new errors found since
+ * the beginning of the build.
+ */
+ public int getNewErrorCount() {
+ return fNewErrorCount;
+ }
+
+ /**
+ * Returns the number of new warnings found since
+ * the beginning of the build.
+ */
+ public int getNewWarningCount() {
+ return fNewWarningCount;
+ }
+
+ /**
+ * Returns the source fragment of the most recently
+ * (re)compiled element. May be null if the notification
+ * is not due to an element being (re)compiled, for example
+ * when an element is removed.
+ */
+ public ISourceFragment getSourceFragment() {
+ return fSourceFragment;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/DeltaKey.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/DeltaKey.java
new file mode 100644
index 0000000000..5abf36fe14
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/DeltaKey.java
@@ -0,0 +1,444 @@
+package org.eclipse.jdt.internal.core.builder;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+
+/**
+ * <code>DeltaKey</code> objects are used to index into hierarchical structures.
+ * They consist of a sequence of local names, which can be
+ * arbitrary objects. A node in the hierarchy is obtained by
+ * traversing down from the root of the hierarchy, using the
+ * localNames to indicate the choice of child at each step along the way.
+ *
+ * <p><code>DeltaKey</code> objects are immutable, as they must consistently describe
+ * a particular branch of a source tree. If branches are addded or deleted
+ * from a <code>DeltaKey</code> object, it is done by creating a copy and modifying
+ * the copy.
+ */
+public class DeltaKey implements IDeltaKey, Serializable {
+
+ /**
+ * Names of the branches of the key
+ */
+ protected Object[] fLocalNames;
+
+ /**
+ * Singleton root node instance.
+ */
+ protected static DeltaKey NodeRoot = new DeltaKey(0);
+
+ /** Version UID for serialization purposes (as of LF 143)
+ */
+ protected static final long serialVersionUID = 1379863541613390307L;
+
+ /**
+ * Sets the names of the key
+ */
+ public DeltaKey(Object[] names) {
+ fLocalNames = names;
+ }
+
+ /**
+ * Creates a new key of the given length.
+ */
+ protected DeltaKey(int length) {
+ fLocalNames = new Object[length];
+ }
+
+ /**
+ * Returns a new key describing the key's child with the given local name.
+ * This replaces the "/" syntax in the Smalltalk implementation
+ */
+ public DeltaKey add(Object localName) {
+
+ /* Calculate length of new key */
+ int length = this.size();
+
+ DeltaKey newKey = new DeltaKey(length + 1);
+
+ /* Copy names from receiver to new key */
+ newKey.replaceFromToWithStartingAt(0, length - 1, this, 0);
+
+ /* Add new local name at end of new key */
+ newKey.fLocalNames[length] = localName;
+
+ return newKey;
+ }
+
+ /**
+ * Returns the local name at the given index in the receiver
+ */
+ public Object at(int index) {
+ return fLocalNames[index];
+ }
+
+ /**
+ * Returns true if the receiver has the exact same local names as anObject.
+ * Returns false otherwise.
+ * Returns false if anObject is not an instance of NodeKey
+ */
+ public boolean equals(Object anObject) {
+
+ DeltaKey aKey;
+ int result;
+
+ /* return true if the same object */
+ if (this == anObject) {
+ return true;
+ }
+
+ /* return false if different class of object */
+ if (anObject instanceof DeltaKey) {
+ aKey = (DeltaKey) anObject;
+ } else {
+ return false;
+ }
+
+ /* return false if not the same number of names */
+ if (this.size() != aKey.size()) {
+ return false;
+ }
+
+ /* not equal if any local names are not equal */
+ for (int i = this.size() - 1; i >= 0; i--) {
+ if (!this.at(i).equals(aKey.at(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns the receiver's local name (the name of the last child). If the
+ * receiver is a root key, answer null
+ */
+ public Object getLocalName() {
+ if (this.size() == 0) {
+ return null;
+ } else {
+ return fLocalNames[fLocalNames.length - 1];
+ }
+ }
+
+ /**
+ * Returns the local names of the key
+ */
+ protected Object[] getLocalNames() {
+ return fLocalNames;
+ }
+
+ /**
+ * Returns the singleton root node instance.
+ */
+ public static DeltaKey getRoot() {
+ return NodeRoot;
+ }
+
+ /**
+ * Returns the hash value of the receiver. Objects which are equal have
+ * the same hash value.
+ */
+ public int hashCode() {
+
+ int hash, selfSize;
+
+ selfSize = this.size();
+ if (selfSize == 0) {
+ return 0;
+ }
+
+ /* Hash the first element */
+ hash = this.at(0).hashCode();
+ if (selfSize == 1) {
+ return hash;
+ }
+
+ /* Hash the last element */
+ hash ^= this.at(selfSize - 1).hashCode();
+ if (selfSize == 2) {
+ return hash & 32767;
+ }
+
+ /* Hash the middle element for good luck */
+ hash ^= this.at(selfSize / 2).hashCode();
+ return hash & 32767;
+ }
+
+ /**
+ * Returns true if the receiver is a prefix of the given key, false otherwise.
+ * Keys which are equal are considered to be prefixes of each other (so
+ * true is answered in this case).
+ */
+ public boolean isPrefixOf(DeltaKey key) {
+
+ int size;
+
+ /**
+ * Capitalize on the property that compound keys are usually paths,
+ * where a common prefix is more likely than a common suffix.
+ * Compare last elements before comparing the rest.
+ */
+
+ size = this.size();
+ if (size > key.size()) {
+ return false;
+ }
+ if (size == 0) {
+ return true;
+ }
+
+ /* Check the last element first. */
+ size--;
+ if (this.fLocalNames[size] != key.fLocalNames[size]) {
+ return false;
+ }
+ if (--size <= 0) {
+ return true;
+ }
+
+ /* Check the first element next */
+ if (this.fLocalNames[0] != key.fLocalNames[0]) {
+ return false;
+ }
+ if (size == 1) {
+ return true;
+ }
+
+ /* Unroll the loop for increased performance */
+ if (this.fLocalNames[size] != key.fLocalNames[size]) {
+ return false;
+ }
+ if (--size == 1) {
+ return true;
+ }
+
+ if (this.fLocalNames[size] != key.fLocalNames[size]) {
+ return false;
+ }
+ if (--size == 1) {
+ return true;
+ }
+
+ if (this.fLocalNames[size] != key.fLocalNames[size]) {
+ return false;
+ }
+ if (--size == 1) {
+ return true;
+ }
+
+ if (this.fLocalNames[size] != key.fLocalNames[size]) {
+ return false;
+ }
+ if (--size == 1) {
+ return true;
+ }
+
+ if (this.fLocalNames[size] != key.fLocalNames[size]) {
+ return false;
+ }
+ if (--size == 1) {
+ return true;
+ }
+
+ if (this.fLocalNames[size] != key.fLocalNames[size]) {
+ return false;
+ }
+ if (--size == 1) {
+ return true;
+ }
+
+ if (this.fLocalNames[size] != key.fLocalNames[size]) {
+ return false;
+ }
+ if (--size == 1) {
+ return true;
+ }
+
+ if (this.fLocalNames[size] != key.fLocalNames[size]) {
+ return false;
+ }
+ if (--size == 1) {
+ return true;
+ }
+
+ if (this.fLocalNames[size] != key.fLocalNames[size]) {
+ return false;
+ }
+ if (--size == 1) {
+ return true;
+ }
+
+ while (size > 1) {
+ if (this.fLocalNames[size] != key.fLocalNames[size]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns true if the receiver is the root key, false otherwise
+ */
+ public boolean isRoot() {
+ return (this.size() == 0);
+ }
+
+ /**
+ * Returns the key describing the receiver's parent, or null if the receiver
+ * is the root key.
+ */
+ public DeltaKey parent() {
+
+ int size = this.size() - 1;
+ DeltaKey newKey;
+
+ if (size < 0) {
+ return null;
+ } else {
+ newKey = new DeltaKey(size);
+
+ /* copy children from receiver */
+ newKey.replaceFromToWithStartingAt(0, size - 1, this, 0);
+ return newKey;
+ }
+ }
+
+ /**
+ * Returns a new key containing the first few local names in the
+ * receiver.
+ *
+ * @param count
+ * number of local names to copy (length of prefix)
+ * @exception IllegalArgumentException
+ * receiver contains fewer than count local names, or count is
+ * negative."
+ */
+ public DeltaKey prefix(int count) {
+
+ DeltaKey newNode;
+
+ if (count < 0 || this.size() < count) {
+ throw new IllegalArgumentException(new Integer(count).toString());
+ }
+
+ newNode = new DeltaKey(count);
+
+ /* copy children */
+ newNode.replaceFromToWithStartingAt(0, count - 1, this, 0);
+ return newNode;
+ }
+
+ private void readObject(ObjectInputStream in)
+ throws IOException, ClassNotFoundException {
+ int l = in.readInt();
+ fLocalNames = new String[l];
+ for (int i = 0; i < l; ++i) {
+ fLocalNames[i] = in.readObject();
+ }
+ }
+
+ /**
+ * Replaces the elements of the receiver between the given indices
+ * with the elements of the supplied key starting at a particular point.
+ *
+ * Fail if start is not an Integer. Fail if stop is not an
+ * Integer. Fail if repStart is not an Integer. Fail if start
+ * is < 1. Fail if start is > size of the receiver. Fail if
+ * stop is < 1. Fail if repStart < 1. Fail if repStart > size
+ * of replacementKey."
+ *
+ * @param start
+ * index in the receiver to start copying at
+ * @param stop
+ * index in the receiver to stop copying at
+ * @param replacementKey
+ * key to be copied
+ * @param repStart
+ * index to start copying from in the replacement key
+ * @return the modified key
+ */
+ private DeltaKey replaceFromToWithStartingAt(
+ int start,
+ int stop,
+ DeltaKey replacementKey,
+ int repStart) {
+
+ int repCount = repStart;
+
+ for (int i = start; i <= stop; i++, repCount++) {
+ this.fLocalNames[i] = replacementKey.fLocalNames[repCount];
+ }
+ return this;
+ }
+
+ /**
+ * Sets the local names of the key
+ */
+ protected void setLocalNames(String[] names) {
+ fLocalNames = names;
+ }
+
+ /**
+ * Returns the branch length of the key
+ */
+ public int size() {
+ return fLocalNames.length;
+ }
+
+ /**
+ * Returns a unicode representation of the receiver. This method is used
+ * for debugging purposes only (no NLS needed)
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("DeltaKey(");
+
+ for (int i = 0; i < this.fLocalNames.length; i++) {
+ buffer.append(this.fLocalNames[i]);
+ if (i < this.fLocalNames.length - 1) {
+ buffer.append("/");
+ }
+ }
+ buffer.append(")");
+
+ return buffer.toString();
+ }
+
+ /**
+ * Returns a new key containing everything but the first few local
+ * names in the receiver.
+ *
+ * @param count
+ * number of local names in the key to leave out (length of prefix to cut)
+ * @exception IllegalArgumentException
+ * receiver contains fewer than count local names, or count is
+ * negative.
+ */
+ public DeltaKey withoutPrefix(int count) {
+
+ DeltaKey newNode;
+ int newSize;
+
+ if (count < 0 || this.size() < count) {
+ throw new IllegalArgumentException(new Integer(count).toString());
+ }
+
+ newSize = this.size() - count;
+ newNode = new DeltaKey(newSize);
+ newNode.replaceFromToWithStartingAt(0, newSize - 1, this, count);
+ return newNode;
+ }
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ int l = fLocalNames.length;
+ out.writeInt(l);
+ for (int i = 0; i < l; ++i) {
+ out.writeObject(fLocalNames[i]);
+ }
+ }
+
+} // end class definition
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IBinaryBroker.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IBinaryBroker.java
new file mode 100644
index 0000000000..da89292bd9
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IBinaryBroker.java
@@ -0,0 +1,66 @@
+package org.eclipse.jdt.internal.core.builder;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.Hashtable;
+
+/**
+ * A binary broker is responsible for maintaining the binaries produced by the image builder.
+ * The image builder itself does not store or otherwise hang on to binaries it produces, but
+ * delegates this responsibility to a binary broker.
+ * <p>
+ * The binary broker provides methods for storing and retrieving the binary for a given type.
+ * The put and get methods are passed a key consisting of a non-state-specific type handle
+ * and a 32-bit CRC.
+ * <p>
+ * The CRC is used to identify the binary independently of the state which produced it,
+ * and is remembered by the image builder.
+ * <p>
+ * The broker is not required to remember all binaries for all time, but should make a good effort
+ * to remember many for as long as possible. If the broker cannot supply the binary back to the
+ * image builder, the builder must recompile the compilation unit which produced the type, which is
+ * expensive.
+ * <p>
+ * Note that, due to lazy builds, the broker may receive put messages for some state after the build
+ * for that state has ended.
+ * <p>
+ * Although not included in this interface, the broker may provide methods for
+ * the environment to notify it when it is changing in interesting ways. For example, new states
+ * being created, states being dropped, etc. It is of limited value to add these to the interface
+ * between the broker and the builder since the builder cannot provide sufficient information
+ * for the broker to manage its storage more effectively than a simple LRU cache.
+ * Only higher level components know when a state is being dropped.
+ * Even with such notifications, storage management is not trivial, however,
+ * since the binaries for types from a dropped state may still be needed for other states
+ * derived from it. It may be that a simple LRU cache is the best as well as the simplest strategy.
+ *
+ * @see IDevelopmentContext#setBinaryBroker()
+ * @see IType#getBinary()
+ * @see IHandle#nonStateSpecific()
+ */
+public interface IBinaryBroker {
+ /**
+ * Ensures that all state kept by the binary broker has been saved.
+ * Subsequent operations are permitted after a close.
+ */
+ void close();
+ /**
+ * Removes unused binaries from the binary broker, given a set
+ * of BinaryBrokerKeys that are still in use.
+ *
+ * @param keysInUse <Hashtable(<BinaryBrokerKey> -> <BinaryBrokerKey>)>
+ */
+ void garbageCollect(Hashtable keysInUse);
+ /**
+ * Retrieve the binary for the given key (type and CRC).
+ * Return the binary if successful, or null if the binary could
+ * not be retrieved.
+ */
+ byte[] getBinary(BinaryBrokerKey key);
+ /**
+ * Remember the binary for the given key (type and CRC).
+ */
+ void putBinary(BinaryBrokerKey key, byte[] bytes);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IBuildListener.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IBuildListener.java
new file mode 100644
index 0000000000..e4e53040f6
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IBuildListener.java
@@ -0,0 +1,19 @@
+package org.eclipse.jdt.internal.core.builder;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.EventListener;
+
+/**
+ * An IBuildListener is a listener which is notified of builder-specific
+ * information during a batch or incremental build.
+ */
+public interface IBuildListener extends EventListener {
+
+ /**
+ * Notifification that builder information has changed.
+ */
+ public void buildUpdate(BuildEvent event);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IBuildMonitor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IBuildMonitor.java
new file mode 100644
index 0000000000..652126fba0
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IBuildMonitor.java
@@ -0,0 +1,20 @@
+package org.eclipse.jdt.internal.core.builder;
+
+public interface IBuildMonitor {
+ /**
+ * Signals that a new build has begun
+ */
+ void beginBuild(String message);
+ /**
+ * Records the event of a compilation unit called "jcu" being compiled
+ */
+ void compiled(String jcu);
+ /**
+ * Signals that a build has finished.
+ */
+ void endBuild(String message);
+ /**
+ * Returns the names of the classes that have been compiled so far this build.
+ */
+ String[] getCompiledClasses();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IConstructor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IConstructor.java
new file mode 100644
index 0000000000..5cfbd42452
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IConstructor.java
@@ -0,0 +1,64 @@
+package org.eclipse.jdt.internal.core.builder;
+
+public interface IConstructor extends IMember {
+
+ /**
+ * Compares this Constructor handle against the specified object.
+ * Returns true if the objects are the same. Two Constructor
+ * handles are the same if they were declared by the same class
+ * and have the same formal parameter types.
+ * See Handle.equals() for more details.
+ *
+ * @see IHandle#equals
+ * @see IHandle#hashCode
+ */
+ boolean equals(Object obj);
+ /**
+ * Returns an array of Type objects that represent the types of
+ * the checked exceptions thrown by the underlying constructor
+ * represented by this Constructor object.
+ * Unchecked exceptions are not included in the result, even if
+ * they are declared in the source.
+ * Returns an array of length 0 if the constructor throws no checked
+ * exceptions.
+ * The resulting Types are in no particular order.
+ *
+ * @exception NotPresentException if the constructor is not present.
+ */
+ IType[] getExceptionTypes() throws NotPresentException;
+ /**
+ * Returns an array of Type objects that represent the formal
+ * parameter types, in declaration order, of the constructor
+ * represented by this Constructor object.
+ * Returns an array of length 0 if the underlying constructor
+ * takes no parameters.
+ * This is a handle-only method.
+ */
+ IType[] getParameterTypes();
+ /**
+ * A constructor is present if:
+ * <ul>
+ * <li>its declaring class is present, and
+ * <li>the class declares a constructor with the same parameter types
+ * </ul>
+ * It is not necessary that the parameter types be present.
+ * See Handle.isPresent() for more details.
+ *
+ * @see #getParameterTypes
+ * @see IHandle#isPresent
+ * @see IMember#getDeclaringClass
+ */
+ boolean isPresent();
+ /**
+ * Return a string describing this Constructor. The string is
+ * formatted as the fully-qualified name of the declaring class,
+ * followed by a parenthesized, comma-separated list of the
+ * constructor's formal parameter types. For example:
+ * <pre>
+ * java.util.Hashtable(int,float)
+ * </pre>
+ *
+ * @see IHandle#toString
+ */
+ String toString();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IDelta.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IDelta.java
new file mode 100644
index 0000000000..d145fcbe94
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IDelta.java
@@ -0,0 +1,206 @@
+package org.eclipse.jdt.internal.core.builder;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.Enumeration;
+
+/**
+ * A Delta describes the differences between one State and another,
+ * for some part of the Image.
+ * Deltas are unusual in that they are inherently wedded to
+ * a <em>pair</em> of states. Deltas are navigated using DeltaKey objects.
+ *
+ * <p>The basic approach is similar to that used by Check objects,
+ * except that the status of a Delta has four possible values:
+ * (Same, Changed, Added, or Removed).
+ *
+ * @see DeltaKey
+ * @see ICheck
+ */
+public interface IDelta {
+ /*
+ * The constants below for known statuses are assigned different
+ * bits, rather than consecutive values, to allow sets
+ * of statuses to be represented by bitwise ORing the status values.
+ */
+
+ /** Constant indicating that the object has not changed. */
+ int SAME = 1;
+
+ /**
+ * Constant indicating that the object has changed; this
+ * represents only a true change, not an addition or removal.
+ */
+ int CHANGED = 2;
+
+ /** Constant indicating that the object has been added. */
+ int ADDED = 4;
+
+ /** Constant indicating that the object has been removed. */
+ int REMOVED = 8;
+
+ /** Constant indicating that the status of a delta is unknown. */
+ int UNKNOWN = -1;
+
+ /**
+ * Returns positive, negative, or zero, depending on whether aKey is greater than,
+ * less than or equal to the receiver, respectively.
+ *
+ * This comparison is used for sorting deltas, and therefore the only criterion is that
+ * it compares deltas in a consistent manner that allows for sorting.
+ */
+ int compareTo(IDelta anotherDelta);
+ /**
+ * Returns the delta reached by navigating the given
+ * relative path from this object.
+ * It is an error if the delta could never have such a descendent.
+ * <pre>
+ * - navigation off a checklist with the wrong child name
+ * is always bad
+ * - navigation off a batch delta is common when you don't
+ * yet know whether the object is present; this is allowed
+ * - navigation off a leaf delta is always bad
+ * </pre>
+ *
+ * @param path the path to follow
+ * @exception InvalidKeyException if an invalid key is given.
+ */
+ IDelta follow(IDeltaKey path) throws InvalidKeyException;
+ /**
+ * Returns the immediate subdeltas of this delta that are additions
+ * (i.e. their status is Added).
+ */
+ IDelta[] getAddedSubdeltas();
+ /**
+ * Returns the immediate subdeltas of this delta that are
+ * not the same (i.e. their status is either Added, Removed, or Changed).
+ */
+ IDelta[] getAffectedSubdeltas();
+ /**
+ * Returns the immediate subdeltas of this delta that are true
+ * changes, not additions or removals (i.e. their status is Changed).
+ */
+ IDelta[] getChangedSubdeltas();
+ /**
+ * Returns the ImageContext that the delta is restricted to.
+ *
+ * @see IImageBuilder#getImageDelta
+ */
+ IImageContext getImageContext();
+ /**
+ * Returns the delta key for this delta.
+ * Delta keys often contain non-state-specific handles, but
+ * never state-specific ones.
+ *
+ * @see DeltaKey
+ */
+ IDeltaKey getKey();
+ /**
+ * Returns the name of the aspect being compared in this delta.
+ */
+ String getName();
+ /**
+ * Returns the object in the new state that is the focus of this delta.
+ * It only make sense to talk about the 'new object' if the object
+ * that is the focus of this delta is a Handle. If it is not, this
+ * returns null.
+ *
+ * @return the state-specific handle of the object in the new state.
+ */
+ IHandle getNewObject();
+ /**
+ * Returns the new state to which this delta pertains.
+ */
+ IState getNewState();
+ /**
+ * Returns the object that is the focus of this delta.
+ * The result is often a Handle, but in
+ * some cases it is another type of object.
+ * When it is a Handle, it is non-state-specific.
+ */
+ Object getObject();
+ /**
+ * Returns the object in the new state that is the focus of this delta.
+ * It only make sense to talk about the 'old object' if the object
+ * that is the focus of this delta is a Handle. If it is not, this
+ * returns null.
+ *
+ * @return the state-specific handle of the object in the old state.
+ */
+ IHandle getOldObject();
+ /**
+ * Returns the old state to which this delta pertains.
+ */
+ IState getOldState();
+ /**
+ * Returns the parent delta of this delta, or null if it has no parent.
+ */
+ IDelta getParent();
+ /**
+ * Returns the immediate subdeltas of this delta that are removals
+ * (i.e. their status is Removed).
+ */
+ IDelta[] getRemovedSubdeltas();
+ /**
+ * Returns the root delta of the tree containing this delta.
+ */
+ IDelta getRoot();
+ /**
+ * Returns the status of this delta. If this delta
+ * is not applicable, it always returns SAME.
+ * If the status is not currently known, it is computed
+ * (UNKNOWN is never returned).
+ *
+ * @see #getStatusIfKnown
+ * @see SAME
+ * @see CHANGED
+ * @see ADDED
+ * @see REMOVED
+ */
+ int getStatus();
+ /**
+ * Returns the status of this delta if it is known.
+ * Returns UNKNOWN if it is not known whether the object has changed.
+ *
+ * @see #getStatus
+ * @see SAME
+ * @see CHANGED
+ * @see ADDED
+ * @see REMOVED
+ * @see UNKNOWN
+ */
+ int getStatusIfKnown();
+ /**
+ * Returns an array of Delta objects that are children of this delta.
+ * Returns an array of length 0 if this delta has no children,
+ * or if it is not composite.
+ */
+ IDelta[] getSubdeltas();
+ /**
+ * Returns whether this delta is a composite delta that is further
+ * broken down into subdeltas.
+ */
+ boolean hasSubdeltas();
+ /**
+ * Return a string of either the form:
+ * status this.data.name this.data.oldState ==> this.data.newState
+ * OR
+ * status / this.data.name
+ *
+ * status will be one of the following:
+ * + if status is ADDED
+ * - if status is REMOVED
+ * " " if status is CHANGED
+ * = if status is SAME
+ * ? if status is UNKNOWN
+ * The first string will be returned from a delta check which
+ * relates specifically to the image, all other delta checks
+ * will return the second string.
+ * The string returned is only for debugging purposes,
+ * and the contents of the string may change in the future.
+ * @return java.lang.String
+ */
+ public String toString();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IDeltaKey.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IDeltaKey.java
new file mode 100644
index 0000000000..e0892ee34d
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IDeltaKey.java
@@ -0,0 +1,59 @@
+package org.eclipse.jdt.internal.core.builder;
+
+public interface IDeltaKey {
+ /**
+ * Returns a new key describing the key's child with the given local name.
+ * This replaces the "/" syntax in the Smalltalk implementation
+ */
+ DeltaKey add(Object localName);
+ /**
+ * Returns the local name at the given index in the receiver
+ */
+ Object at(int index);
+ /**
+ * Returns the receiver's local name (the name of the last child). If the
+ * receiver is a root key, answer null
+ */
+ Object getLocalName();
+ /**
+ * Returns true if the receiver is a prefix of the given key, false otherwise.
+ * Keys which are equal are considered to be prefixes of each other (so
+ * true is answered in this case).
+ */
+ boolean isPrefixOf(DeltaKey key);
+ /**
+ * Returns true if the receiver is the root key, false otherwise
+ */
+ boolean isRoot();
+ /**
+ * Returns the key describing the receiver's parent, or null if the receiver
+ * is the root key.
+ */
+ DeltaKey parent();
+ /**
+ * Returns a new key containing the first few local names in the
+ * receiver.
+ *
+ * @param count
+ * number of local names to copy (length of prefix)
+ * @exception IllegalArgumentException
+ * receiver contains fewer than count local names, or count is
+ * negative."
+ */
+ DeltaKey prefix(int count);
+ /**
+ * Returns the branch length of the key
+ */
+ int size();
+ /**
+ * Returns a new key containing everything but the first few local
+ * names in the receiver.
+ *
+ * @param count
+ * number of local names in the key to leave out (length of prefix to cut)
+ * @exception IllegalArgumentException
+ * receiver contains fewer than count local names, or count is
+ * negative.
+ */
+ DeltaKey withoutPrefix(int count);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IDependencyGraph.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IDependencyGraph.java
new file mode 100644
index 0000000000..acf201bac1
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IDependencyGraph.java
@@ -0,0 +1,16 @@
+package org.eclipse.jdt.internal.core.builder;
+
+public interface IDependencyGraph {
+ /**
+ * Returns the namespaces on which the given type depends.
+ */
+ IPackage[] getNamespaceDependencies(IType type);
+ /**
+ * Returns the state whose dependencies this graph describes.
+ */
+ IState getState();
+ /**
+ * Returns the types on which the given type depends, if known, or null if not known.
+ */
+ IType[] getTypeDependencies(IType type);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IDevelopmentContext.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IDevelopmentContext.java
new file mode 100644
index 0000000000..893087ef91
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IDevelopmentContext.java
@@ -0,0 +1,218 @@
+package org.eclipse.jdt.internal.core.builder;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * This maintains a description of an image. It has the following responsibilities:
+ * <dl>
+ * <dd> - given the source for a system, build a representation of the image which it describes
+ * <dd> - provide navigational access over the image
+ * <dd> - check the consistency of the system and report any problems in the form of a 'report card'
+ * <dd> - given a source delta describing changes to the source, incrementally build
+ * an updated representation of the image and report card
+ * <dd> - when a delta is applied, also output an image delta describing changes to the image
+ * </dl>
+ *
+ */
+public interface IDevelopmentContext {
+
+ /**
+ * Adds an IBuildListener which is notified of builder-specific
+ * information during a batch or incremental build.
+ */
+ public void addBuildListener(IBuildListener buildListener);
+ /**
+ * Builds a new state representing the image described by a project.
+ * Returns an <code>ImageBuilder</code> that will build a representation
+ * of the image and answer a new state.
+ * The current state is not affected.
+ * A build context is given, representing the subset of the
+ * image which is important to have built as early as possible.
+ *
+ * <p> N.B. The image builder may read from the project at any time,
+ * not just when a build is initiated. Any exceptions encountered during
+ * reading are propagated to the client by the image builder.
+ * The image builder guarantees that its internal structures
+ * are not corrupted by such occurrences.
+ *
+ * <p> There are a few operations in the image builder API that are
+ * independent of the workspace:
+ * <dl>
+ * <dd> handle-only methods on <code>IHandle</code> and subclasses
+ * <dd> <code>equal()</code>,
+ * <code>toString()</code>
+ * and <code>hashCode()</code> methods
+ * <dd> <code>DeltaKey</code> operations
+ * <dd> <code>IImageContext</code> operations
+ * <dd> <code>ISourceFragment</code> operations
+ * <dd> <code>IState.getCurrentState()</code>,
+ * <code>setCurrentState()</code>
+ * and <code>getImage()</code>
+ * </dl>
+ * Clients must assume that this exception could be thrown at any time by
+ * any other operation defined in the image builder API.
+ *
+ * @param project the project which provides source for the state
+ * @see IState#applySourceDelta
+ * @see IState#getBuildContext
+ */
+ IImageBuilder createState(IProject project, IImageContext buildContext);
+ /**
+ * Builds a new state representing the image described by a project.
+ * Returns an <code>ImageBuilder</code> that will build a representation
+ * of the image and answer a new state.
+ * The current state is not affected.
+ * A build context is given, representing the subset of the
+ * image which is important to have built as early as possible.
+ *
+ * <p> N.B. The image builder may read from the project at any time,
+ * not just when a build is initiated. Any exceptions encountered during
+ * reading are propagated to the client by the image builder.
+ * The image builder guarantees that its internal structures
+ * are not corrupted by such occurrences.
+ *
+ * <p> Compilation and build problems encountered during the image building
+ * are reported using the given <code>IProblemReporter</code>. The report
+ * card will use this problem reporter.
+ *
+ * <p> There are a few operations in the image builder API that are
+ * independent of the workspace:
+ * <dl>
+ * <dd> handle-only methods on <code>IHandle</code> and subclasses
+ * <dd> <code>equal()</code>,
+ * <code>toString()</code>
+ * and <code>hashCode()</code> methods
+ * <dd> <code>DeltaKey</code> operations
+ * <dd> <code>IImageContext</code> operations
+ * <dd> <code>ISourceFragment</code> operations
+ * <dd> <code>IState.getCurrentState()</code>,
+ * <code>setCurrentState()</code>
+ * and <code>getImage()</code>
+ * </dl>
+ * Clients must assume that this exception could be thrown at any time by
+ * any other operation defined in the image builder API.
+ *
+ * @param project the project which provides source for the state
+ * @see IState#applySourceDelta
+ * @see IState#getBuildContext
+ */
+ IImageBuilder createState(
+ IProject project,
+ IImageContext buildContext,
+ IProblemReporter problemReporter);
+ /**
+ * Compare two Objects for equality. Returns true iff they represent the
+ * same development context.
+ */
+ boolean equals(Object obj);
+ /**
+ * Garbage collect any resources maintained by the development
+ * context which are no longer needed, given the states which
+ * are still in use.
+ *
+ * This releases any binaries in the binary broker
+ * which aren't needed for the given states.
+ */
+ void garbageCollect(IState[] statesInUse);
+ /**
+ * Returns the binary broker which maintains the binaries for types which are built
+ * by this development context.
+ */
+ IBinaryBroker getBinaryBroker();
+ /**
+ * Returns the build monitor.
+ */
+ IBuildMonitor getBuildMonitor();
+ /**
+ * Returns the current state of the development context.
+ *
+ * @exception NotPresentException when no current state has been set. */
+ IState getCurrentState() throws NotPresentException;
+ /**
+ * Returns the image described by the current state.
+ * The result is non-state-specific.
+ *
+ * @see IState
+ */
+ IImage getImage();
+ /**
+ * Returns the progress monitor set by setProgressMonitor(...) or null
+ * if none has been set.
+ */
+ public IProgressMonitor getProgressMonitor();
+ /**
+ * Removes a IBuildListener which is notified of builder-specific
+ * information during a batch or incremental build.
+ */
+ public void removeBuildListener(IBuildListener buildListener);
+ /**
+ * Returns a new state of this development context by restoring a
+ * previously-saved one from the given input. Since
+ * development context states are saved without their project,
+ * the correct project also must be supplied.
+ * The results are undefined if this project does not have
+ * the same content as the one from which the state was built.
+ * Note: the restored state is -not- made to be the current state.
+ * The current state of the development context is unaffected.
+ *
+ * @exception IOException If there are problems reading or
+ * restoring the object
+ * @see #saveState
+ */
+ IState restoreState(IProject project, java.io.DataInputStream in)
+ throws java.io.IOException;
+ /**
+ * Save the contents of the given state of this development context
+ * to the given output. The state's workspace must be saved
+ * separately, and reassociated with the state when it is restored.
+ * Because of this quirk, this class does not implement
+ * <code>java.io.Externalizable</code>.
+ * @exception NotPresentException when no current state has been set.
+ * @exception java.io.IOException Includes any I/O exceptions that may occur
+ * @see #restoreState
+ */
+ void saveState(IState state, java.io.DataOutputStream out)
+ throws java.io.IOException;
+ /**
+ * Sets the binary broker which maintains the binaries for types which are built
+ * by this development context.
+ */
+ void setBinaryBroker(IBinaryBroker broker);
+ /**
+ * Sets the build monitor.
+ */
+ void setBuildMonitor(IBuildMonitor monitor);
+ /**
+ * Sets the current state of the development context.
+ *
+ * @param state the state to set as the current state
+ */
+ void setCurrentState(IState state);
+ /**
+ * Sets the build progress monitor for this development context.
+ * If monitor is <code>null</code>, deregister any existing one.
+ * The build progress monitor is notified of the image building
+ * activities done on any state of this development context.
+ *
+ * For batch builds and incremental builds, the builder periodically
+ * checks the <code>isCanceled()</code> status on the progress monitor.
+ * If set, it stops the build and throws <code>BuildCanceledException</code>.
+ * It does not check the <code>isCanceled()</code> status for background or
+ * lazy builds.
+ */
+ public void setProgressMonitor(IProgressMonitor monitor);
+ /**
+ * Return a string of the form:
+ * JDC#?
+ * where ? is the instance number of the DevelopmentContext.
+ * The string returned is only for debugging purposes,
+ * and the contents of the string may change in the future.
+ * @return java.lang.String
+ */
+ public String toString();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IField.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IField.java
new file mode 100644
index 0000000000..0db82c6690
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IField.java
@@ -0,0 +1,47 @@
+package org.eclipse.jdt.internal.core.builder;
+
+public interface IField extends IMember {
+
+ /**
+ * Compares this Field handle against the specified object. Returns
+ * true if the objects are the same. Two Field handles are the same if
+ * they have the same declaring class and have the same field name.
+ * See IHandle.equals() for more details.
+ *
+ * @see IHandle#equals
+ * @see IHandle#hashCode
+ */
+ boolean equals(Object obj);
+ /**
+ * Returns a Type object that identifies the declared type for
+ * the field represented by this Field object.
+ *
+ * @exception NotPresentException if the field is not present.
+ */
+ IType getType() throws NotPresentException;
+ /**
+ * A field is present if:
+ * <ul>
+ * <li>its declaring class is present, and
+ * <li>the class declares a field of the same name
+ * </ul>
+ * See Handle.isPresent() for more details.
+ *
+ * @see IHandle#isPresent
+ * @see IMember#getDeclaringClass
+ */
+ boolean isPresent();
+ /**
+ * Return a string describing this Field. The format is
+ * the fully-qualified name of the class declaring the field,
+ * followed by a period, followed by the name of the field.
+ * For example:
+ * <pre>
+ * java.lang.Thread.MIN_PRIORITY
+ * java.io.FileDescriptor.fd
+ * </pre>
+ *
+ * @see IHandle#toString
+ */
+ String toString();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IHandle.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IHandle.java
new file mode 100644
index 0000000000..022c08ac2f
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IHandle.java
@@ -0,0 +1,107 @@
+package org.eclipse.jdt.internal.core.builder;
+
+public interface IHandle {
+ int K_JAVA_IMAGE = 1;
+ int K_JAVA_PACKAGE = 2;
+ int K_JAVA_TYPE = 3;
+ int K_JAVA_FIELD = 4;
+ int K_JAVA_METHOD = 5;
+ int K_JAVA_CONSTRUCTOR = 6;
+
+ /**
+ * Compares this handle against the specified object.
+ * Returns true if the objects are the same. Two handles are
+ * the same if they both represent the same object according
+ * to the identity criteria described above, and they are
+ * either both non-state-specific, or are both state-specific
+ * on the same state.
+ * This is a handle-only method.
+ * Extending interfaces provide more details.
+ *
+ * @see Object#equals
+ */
+ boolean equals(Object obj);
+ /**
+ * Returns this object's development context.
+ * This is a handle-only method.
+ */
+ IDevelopmentContext getDevelopmentContext();
+ /**
+ * Returns the state in which the object appears. The handle
+ * must be state-specific.
+ * This is a handle-only method.
+ *
+ * @exception StateSpecificException if this object is not state-specific.
+ */
+ IState getState() throws StateSpecificException;
+ /**
+ * Returns a hashcode for this handle, consistent with the identity
+ * criteria described above.
+ * This is a handle-only method.
+ *
+ * @see Object#hashCode
+ */
+ int hashCode();
+ /**
+ * Returns a state-specific object which refers to the same object
+ * as this object, but restricted to the given state. This object
+ * must be non-state-specific.
+ * It is an error to invoke this on a state-specific object.
+ * This is a handle-only method; the object may or may not be present
+ * in the given state.
+ *
+ * @param state the state to use.
+ * @exception StateSpecificException if this object is already state-specific.
+ */
+ IHandle inState(IState s) throws StateSpecificException;
+ /**
+ * Returns true if the object represented by the receiver is 'fictional'.
+ * That is, it was created by the development context for error repair
+ * purposes, such as to fill a missing reference in the source.
+ * A fictional object is not the same as a synthetic object.
+ *
+ * @exception NotPresentException if the object is not present.
+ *
+ * @see IMember#isSynthetic
+ */
+ boolean isFictional() throws NotPresentException;
+ /**
+ * Returns true if the object represented by the receiver is present
+ * in the development context, false otherwise. If the receiver is
+ * state-specific, checks whether it is present in this object's state.
+ * If the receiver is non-state-specific, checks whether it is present
+ * in the current state of the development context. In the latter case,
+ * if there is no current state, <code>NotPresentException</code> is thrown.
+ */
+ boolean isPresent();
+ /**
+ * Returns true if this object represents an object in a specific
+ * state, false otherwise.
+ * This is a handle-only method.
+ *
+ * @see IState
+ */
+ boolean isStateSpecific();
+ /**
+ * Returns a constant indicating what kind of handle this is.
+ * See the constants below.
+ */
+ int kind();
+ /**
+ * Returns a non-state-specific handle corresponding to this object.
+ * The object must be state-specific.
+ * This is a handle-only method.
+ *
+ * @exception StateSpecificException if this object is already non-state-specific.
+ * @see IState
+ */
+ IHandle nonStateSpecific() throws StateSpecificException;
+ /**
+ * Return a string describing this handle.
+ * This is a handle-only method.
+ * Extending interfaces provide more details.
+ *
+ * @see Object#toString
+ */
+ String toString();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IImage.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IImage.java
new file mode 100644
index 0000000000..9e406a8e7a
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IImage.java
@@ -0,0 +1,168 @@
+package org.eclipse.jdt.internal.core.builder;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * The <code>IImage</code> represents a Java image.
+ *
+ * <p>An image contains zero or more packages.
+ * All types (classes and interfaces) declared in the image's
+ * packages are also contained in the image.
+ * Classes and interfaces contained in a image
+ * can refer only to other classes and interfaces contained
+ * in the same image.
+ *
+ * <p>The assumption is that images contain a very large number of
+ * packages (conceptually, an infinite number of packages), most
+ * of which are irrelevant for the purposes at hand.
+ *
+ * <p>Methods never throw NotPresentException for an Image since the
+ * Image is considered to be always present.
+ */
+
+public interface IImage extends IHandle {
+
+ /*
+ * The following methods are needed for the following reasons:
+ * - unlike java.lang, we don't have separate classes
+ * to hold the TYPE constants as in java.lang.Boolean.TYPE, etc.,
+ * - they can't be constants because primitive types are tied to a DC
+ * and can actually be state-specific, since they are instances
+ * of Type which extends Handle.
+ */
+
+ /** Returns the IType representing the primitive type boolean. */
+ IType booleanType();
+ /** Returns the Type representing the primitive type byte. */
+ IType byteType();
+ /** Returns the Type representing the primitive type char. */
+ IType charType();
+ /*
+ * ImageContext stuff.
+ */
+
+ /**
+ * Returns an ImageContext consisting of the given packages.
+ * This object and the packages must be non-state-specific.
+ * This is a handle-only operation. The packages need not
+ * be present in the image.
+ *
+ * @exception StateSpecificException
+ * if this object or any of the packages are state-specific.
+ * @see #getPackages
+ * @see #getAllClasses
+ */
+ IImageContext createImageContext(IPackage[] packages)
+ throws StateSpecificException;
+ /** Returns the Type representing the primitive type double. */
+ IType doubleType();
+ /**
+ * Compares this Image handle against the specified object. Returns
+ * true if the objects are the same. Two Image handles are the same if
+ * they belong to the same development context, and if they are both
+ * non-state-specific or are both state-specific on the same state.
+ * See Handle.equals() for more details.
+ *
+ * @see IHandle#equals
+ * @see IHandle#hashCode
+ */
+ boolean equals(Object obj);
+ /** Returns the Type representing the primitive type float. */
+ IType floatType();
+ /**
+ * Returns an array containing Type objects representing all
+ * classes and interfaces in the given ImageContext.
+ * This includes public and default (package) access top-level
+ * classes, inner classes, and local inner classes.
+ * The result is the intersection of all classes present in this image
+ * and the classes in the ImageContext, so the resulting classes
+ * are all present in the image.
+ * The resulting Types are in no particular order.
+ *
+ * @param context the ImageContext in which to restrict the search.
+ * @see IPackage#getAllClasses()
+ */
+ IType[] getAllClasses(IImageContext context);
+ /**
+ * Returns an array of all packages present in the image. Note that this
+ * method defies the concept of a potentially infinite image, and should only
+ * be used by clients that must operate over the entire image (search, code assist)
+ */
+ IPackage[] getAllPackages();
+ /**
+ * Returns all types which were built from the indicated workspace element.
+ * If the element is a compilation unit, this includes all types declared in
+ * the compilation unit which were successfully built, including member types
+ * and local types.
+ * If the element is a class file, this includes the type represented by the
+ * class file.
+ * If the element is a package, this includes all types produced by compilation
+ * units and class files in the package fragment.
+ * If the element is a project, this includes all types produced by all packages
+ * and zip files in the project.
+ * If the element is a zip file, this includes all types produced by compilation
+ * units and class files in the zip file.
+ * If the element was not built (for example, it is not present in the workspace,
+ * or was not included in the class path), this returns an empty array.
+ */
+ IType[] getBuiltClasses(IPath path);
+ /*
+ * Handle creation stuff.
+ */
+
+ /**
+ * Returns a handle representing the package with the given
+ * name. For named packages, this is the fully qualified
+ * name. For unnamed packages, it is some internal identifying
+ * string.
+ * See <em>The Java Language Specification</em> section 7.4.1 and
+ * 7.4.2 for more details.
+ * This is a handle-only method; the specified package
+ * may or may not actually be present in the image.
+ *
+ * @parameter name the name of the package.
+ * @parameter isUnnamed a boolean indicating whether the package is unnamed.
+ * @see IPackage#getName
+ * @see IHandle
+ */
+ IPackage getPackageHandle(String name, boolean isUnnamed);
+ /**
+ * Returns an array of Package objects representing all
+ * packages contained in the given ImageContext.
+ * The result is the intersection of the packages present in this image
+ * and the packages in the ImageContext, so the resulting packages
+ * are all present in the image.
+ * The resulting Packages are in no particular order.
+ *
+ * @param context the ImageContext in which to restrict the search.
+ */
+ IPackage[] getPackages(IImageContext context);
+ /** Returns the Type representing the primitive type int. */
+ IType intType();
+ /**
+ * Returns true if the object represented by the receiver is present
+ * in the development context, false otherwise. If the receiver is
+ * state-specific, checks whether it is present in this object's state.
+ * If the receiver is non-state-specific, checks whether it is present
+ * in the current state of the development context. In the latter case,
+ * if there is no current state, returns false.
+ */
+ boolean isPresent();
+ /** Returns the Type representing the primitive type long. */
+ IType longType();
+ /** Returns the Type representing the primitive type short. */
+ IType shortType();
+ /**
+ * Returns a string describing this Image handle. The string
+ * representation is the string <code>"image"</code>.
+ *
+ * @see IHandle#toString
+ */
+ String toString();
+ /** Returns the Type representing the keyword void. */
+ IType voidType();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IImageBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IImageBuilder.java
new file mode 100644
index 0000000000..86e966485f
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IImageBuilder.java
@@ -0,0 +1,47 @@
+package org.eclipse.jdt.internal.core.builder;
+
+public interface IImageBuilder {
+
+ /**
+ * If the new state is being built incrementally, returns an object
+ * describing the differences between the old state and the new state,
+ * otherwise returns null. The delta is restricted to the given
+ * ImageContext.
+ * This image delta will include entries for all program elements that are
+ * present in:
+ * <pre>
+ * (oldState UNION newState) INTERSECT imageContext
+ *</pre>
+ * That is, it will include each program element that is present in one or the other
+ * state and also in the given image context.
+ * Any delta objects navigated to from the result are restricted
+ * to the same ImageContext.
+ * Note that there is no necessary relationship between the image context
+ * supplied and the build contexts of the old and new states.
+ */
+ IDelta getImageDelta(IImageContext imageContext);
+ /**
+ * Returns the state being built.
+ */
+ IState getNewState();
+ /**
+ * If the new state is being built incrementally, returns the old state,
+ * otherwise returns null.
+ */
+ IState getOldState();
+ /**
+ * Return a string of the form:
+ * batch image builder for:
+ * new state: this.data.newstate
+ * OR
+ * incremental image builder for:
+ * new state: this.data.newstate
+ * old state: this.data.oldstate
+ * Obviously, which string gets returned depends
+ * on the type of image builder.
+ * The string returned is only for debugging purposes,
+ * and the contents of the string may change in the future.
+ * @return java.lang.String
+ */
+ public String toString();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IImageContext.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IImageContext.java
new file mode 100644
index 0000000000..f3267c4c8a
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IImageContext.java
@@ -0,0 +1,29 @@
+package org.eclipse.jdt.internal.core.builder;
+
+public interface IImageContext {
+
+ /**
+ * Returns the DevelopmentContext for which the ImageContext was created.
+ */
+ IDevelopmentContext getDevelopmentContext();
+ /**
+ * Returns the Packages of which this ImageContext consists.
+ * The resulting Packages are in no particular order.
+ *
+ * @return an array of non-state-specific Package handles.
+ */
+ IPackage[] getPackages();
+ /**
+ * Return a string of the form:
+ * image context with packages:
+ * this.data.package[0]
+ * this.data.package[1]
+ * ...
+ * this.data.package[n-1]
+ *
+ * The string returned is only for debugging purposes,
+ * and the contents of the string may change in the future.
+ * @return java.lang.String
+ */
+ public String toString();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IMember.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IMember.java
new file mode 100644
index 0000000000..f2e0d2441b
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IMember.java
@@ -0,0 +1,64 @@
+package org.eclipse.jdt.internal.core.builder;
+
+public interface IMember extends IHandle {
+
+ /**
+ * Returns the Type object representing the class or interface
+ * that declares the the member represented by this object.
+ * Derived from java.lang.reflect.Member.getDeclaringClass();
+ * This is a handle-only method.
+ */
+ IType getDeclaringClass();
+ /**
+ * Returns the Java language modifiers for the member
+ * represented by this object, as an integer.
+ * The Flags class should be used to decode the modifiers in
+ * the integer.
+ *
+ * @exception NotPresentException if the member is not present.
+ *
+ * @see Flags
+ */
+ int getModifiers() throws NotPresentException;
+ /**
+ * Returns the simple name of the member represented by this object.
+ * If this Member represents a constructor, this returns
+ * the simple name of its declaring class.
+ * This is a handle-only method.
+ */
+ String getName();
+ /**
+ * Return <code>true</code> if this represents a binary member,
+ * <code>false</code> otherwise.
+ * A binary member is one for which the declaring class is in
+ * .class file format in the workspace.
+ *
+ * @return <code>true</code> if this object represents a binary member;
+ * <code>false</code> otherwise.
+ * @exception NotPresentException if this type is not present.
+ */
+ boolean isBinary() throws NotPresentException;
+ /**
+ * Return <code>true</code> if this represents a deprecated member,
+ * <code>false</code> otherwise.
+ * A deprecated object is one that has a 'deprecated' tag in
+ * its doc comment.
+ *
+ * @return <code>true</code> if this object represents a deprecated member;
+ * <code>false</code> otherwise.
+ * @exception NotPresentException if this type is not present.
+ */
+ boolean isDeprecated() throws NotPresentException;
+ /**
+ * Returns true if the member represented by this object is
+ * synthetic, false otherwise. A synthetic object is one that
+ * was invented by the compiler, but was not declared in the source.
+ * See <em>The Inner Classes Specification</em>.
+ * A synthetic object is not the same as a fictional object.
+ *
+ * @exception NotPresentException if the member is not present.
+ *
+ * @see IHandle#isFictional
+ */
+ boolean isSynthetic() throws NotPresentException;
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IMethod.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IMethod.java
new file mode 100644
index 0000000000..489d654e29
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IMethod.java
@@ -0,0 +1,74 @@
+package org.eclipse.jdt.internal.core.builder;
+
+public interface IMethod extends IMember {
+
+ /**
+ * Compares this Method handle against the specified object. Returns
+ * true if the objects are the same. Two Method handles are the same if
+ * they have the same declaring class and have the same method name
+ * and formal parameter types.
+ * See Handle.equals() for more details.
+ *
+ * @see IHandle#equals
+ * @see IHandle#hashCode
+ */
+ boolean equals(Object obj);
+ /**
+ * Returns an array of Type objects that represent the types of
+ * the checked exceptions thrown by the method
+ * represented by this Method object.
+ * Unchecked exceptions are not included in the result, even if
+ * they are declared in the source.
+ * Returns an array of length 0 if the method throws no checked
+ * exceptions.
+ * The resulting Types are in no particular order.
+ *
+ * @exception NotPresentException if the method is not present.
+ */
+ IType[] getExceptionTypes() throws NotPresentException;
+ /**
+ * Returns an array of Type objects that represent the formal
+ * parameter types, in declaration order, of the method
+ * represented by this Method object.
+ * Returns an array of length 0 if the underlying method takes
+ * no parameters.
+ * This is a handle-only method.
+ */
+ IType[] getParameterTypes();
+ /**
+ * Returns a Type object that represents the formal return type
+ * of the method represented by this Method object.
+ *
+ * @exception NotPresentException if the method is not present.
+ */
+ IType getReturnType() throws NotPresentException;
+ /**
+ * A method is present if:
+ * <ul>
+ * <li>its declaring class is present, and
+ * <li>the class declares a method of the same name and parameter types
+ * </ul>
+ * It is not necessary that the parameter types be present.
+ * See Handle.isPresent() for more details.
+ *
+ * @see #getParameterTypes
+ * @see IHandle#isPresent
+ * @see IMember#getDeclaringClass
+ */
+ boolean isPresent();
+ /**
+ * Returns a string describing this Method handle. The string is
+ * formatted as the fully qualified name of the declaring class,
+ * followed by a period, followed by the method name,
+ * followed by a parenthesized, comma-separated list of the method's
+ * formal parameter types.
+ * For example:
+ * <pre>
+ * java.lang.Object.equals(java.lang.Object)
+ * java.lang.Object.wait(long,int)
+ * </pre>
+ *
+ * @see IHandle#toString
+ */
+ String toString();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IPackage.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IPackage.java
new file mode 100644
index 0000000000..b63318ce15
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IPackage.java
@@ -0,0 +1,132 @@
+package org.eclipse.jdt.internal.core.builder;
+
+public interface IPackage extends IHandle {
+
+ /**
+ * Compares this Package handle against the specified object. Returns
+ * true if the objects are the same. Two Package handles are the same if
+ * they both have the same fully qualified name.
+ * See Handle.equals() for more details.
+ *
+ * @see IHandle#equals
+ * @see IHandle#hashCode
+ */
+ boolean equals(Object obj);
+ /**
+ * Returns an array containing Type objects representing all
+ * classes and interfaces in the package represented by this object.
+ * This includes public and default (package) access top-level
+ * classes, inner classes, and local inner classes.
+ * Returns an array of length 0 if this package has no
+ * classes or interfaces.
+ * The Types are in no particular order.
+ *
+ * @exception NotPresentException if this package is not present.
+ */
+ IType[] getAllClasses() throws NotPresentException;
+ /**
+ * Returns a handle representing the class or interface
+ * with the given name. The name is the VM class name,
+ * not including the package name.
+ * For inner classes, the name is as described in the
+ * <em>Inner Classes Specification</em>.
+ * This is a handle-only method; the specified class
+ * may or may not actually be present in the image.
+ *
+ * @see IType#getName
+ * @see IHandle
+ */
+ IType getClassHandle(String name);
+ /**
+ * Returns an array of Type objects representing all the classes
+ * and interfaces declared as members of the package represented by
+ * this object. This includes public and default (package) access
+ * classes and interfaces declared as members of the package.
+ * This does not include inner classes and interfaces.
+ * Returns an array of length 0 if this package declares no classes
+ * or interfaces as members.
+ * The Types are in no particular order.
+ *
+ * @exception NotPresentException if this package is not present.
+ */
+ IType[] getDeclaredClasses() throws NotPresentException;
+ /**
+ * Returns the fully-qualified name of the package represented
+ * by this object, as a String.
+ * If the package is unnamed, returns the internal identifier
+ * string of this unnamed packaged.
+ * This is a handle-only method.
+ *
+ * @return the fully qualified name of the package
+ * represented by this object.
+ */
+ String getName();
+ /**
+ * Returns an array of Package objects representing all other
+ * packages which this package directly references.
+ * This is the union of all packages directly referenced by all
+ * classes and interfaces in this package, including packages
+ * mentioned in import declarations.
+ * <p>
+ * A direct reference in source code is a use of a package's
+ * name other than as a prefix of another package name.
+ * For example, 'java.lang.Object' contains a direct reference
+ * to the package 'java.lang', but not to the package 'java'.
+ * Also note that every package that declares at least one type
+ * contains a direct reference to java.lang in virtue of the
+ * automatic import of java.lang.*.
+ * The result does not include this package (so contrary to the note
+ * above, the result for package java.lang does not include java.lang).
+ * In other words, the result is non-reflexive and typically
+ * non-transitive.
+ * <p>
+ * The resulting packages may or may not be present in the image,
+ * since the classes and interfaces in this package may refer to missing
+ * packages.
+ * The resulting packages are in no particular order.
+ *
+ * @exception NotPresentException if this package is not present.
+ */
+ IPackage[] getReferencedPackages() throws NotPresentException;
+ /**
+ * Returns an array of Package objects representing all packages
+ * in the given image context which directly reference this package.
+ * The result does not include this package.
+ * In other words, the result is non-transitive and non-reflexive.
+ * <p>
+ * The intersection of all packages in the image and those in the
+ * image context are considered, so the resulting packages are
+ * guaranteed to be present in the image.
+ * The resulting packages are in no particular order.
+ *
+ * @param context the ImageContext in which to restrict the search.
+ * @exception NotPresentException if this package is not present.
+ */
+ IPackage[] getReferencingPackages(IImageContext context)
+ throws NotPresentException;
+ /**
+ * Returns an array of SourceFragments describing the source package
+ * fragments from which this built package is derived.
+ * Returns an empty array if this package is not derived directly from source
+ * (e.g. package com.oti.requiem.fictional).
+ * The source coordinates in the results are set to {0, -1}.
+ *
+ * @exception NotPresentException if the package is not present.
+ */
+ ISourceFragment[] getSourceFragments() throws NotPresentException;
+ /**
+ * Returns true if this package is an unnamed package, false
+ * otherwise. See <em>The Java Language Specification</em>,
+ * sections 7.4.1 and 7.4.2, for details.
+ * This is a handle-only method.
+ */
+ boolean isUnnamed();
+ /**
+ * Converts the object to a string.
+ * The string representation is the string "package" followed by a space
+ * and then the fully qualified name of the package.
+ *
+ * @see IHandle#toString
+ */
+ String toString();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IProblemDetail.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IProblemDetail.java
new file mode 100644
index 0000000000..fd1d212a01
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IProblemDetail.java
@@ -0,0 +1,86 @@
+package org.eclipse.jdt.internal.core.builder;
+
+public interface IProblemDetail {
+
+ /**
+ * Constant returned by getKind() indicating that the problem was
+ * encountered during compilation of the body of a method, constructor,
+ * field initializer or other initializer.
+ */
+ static final int K_COMPILATION_PROBLEM = 1;
+
+ /**
+ * Constant returned by getKind() indicating that this object
+ * represents a problem with the principle structure.
+ */
+ static final int K_PRINCIPLE_STRUCTURE_PROBLEM = 2;
+
+ /**
+ * An integer bit mask indicating that the problem is an error.
+ * If this bit is set, the problem is an error, otherwise it is a warning.
+ */
+ static final int S_ERROR = 1;
+
+ /**
+ * Returns the character offset of the end of the problem in its compilation unit,
+ * or -1 if the end offset is not known.
+ */
+ int getEndPos();
+ /**
+ * Returns a constant indicating the type of problem returned by the compiler.
+ * This is one of the constants defined in com.ibm.compiler.java.problem.ProblemIrritants.
+ */
+ int getID();
+ /**
+ * Returns a constant indicating the kind of problem, either K_COMPILATION_PROBLEM or
+ * K_PRINCIPLE_STRUCTURE_PROBLEM.
+ */
+ int getKind();
+ /**
+ * Returns the line number of the problem in its compilation unit,
+ * or -1 if the line number is not known.
+ */
+ int getLineNumber();
+ /**
+ * Returns a human-readable string describing the problem instance.
+ * The message is specific to the actual culprit object.
+ * The string is in the language specified by the current locale of the image builder.
+ */
+ String getMessage();
+ /**
+ * Returns an integer bit mask indicating the severity of the problem.
+ *
+ * @see S_ERROR
+ */
+ int getSeverity();
+ /**
+ * Returns a source fragment indicating the position in the source where the problem
+ * occurs. The element ID of the source fragment refers to the element having the
+ * problem.
+ * The relevant string can be retrieved using:
+ * <code>
+ * ISourceFragment fragment = problemDetail.getSourceFragment();
+ * int start = getStartPos();
+ * int end = getEndPos();
+ * if(end>=start) {// handle problems with binaries and unknown source positions
+ * String source = workspace.getElementContentString(fragment.getElementID());
+ * String sub = source.substring(start, end + 1);
+ * ...
+ * </code>
+ * If the positions within the source are unknown, the source fragment will
+ * contain the most relevant element identifier but the start and end positions will be
+ * (0, -1). The same is true when the problem is with a binary type.
+ * Typically, positions are known only for problems of kind
+ * <code>K_COMPILATION_PROBLEM</code>.
+ * <p>
+ * When this source fragment arises outside the context of a workspace
+ * (e.g, the Java source analyzer) where element identifiers make no sense,
+ * the element identifier is null.
+ */
+ ISourceFragment getSourceFragment();
+ /**
+ * Returns the character offset of the start of the problem in its compilation unit,
+ * or -1 if the start offset is not known.
+ */
+ int getStartPos();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IProblemReporter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IProblemReporter.java
new file mode 100644
index 0000000000..f96154e7e7
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IProblemReporter.java
@@ -0,0 +1,75 @@
+package org.eclipse.jdt.internal.core.builder;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.IProject;
+
+import java.util.Vector;
+import java.util.Enumeration;
+
+/**
+ * An <code>IProblemReporter</code> keeps track of problems reported
+ * by the image builder.
+ */
+public interface IProblemReporter {
+ /**
+ * Creates a copy of this problem reporter.
+ */
+ public IProblemReporter copy();
+ /**
+ * Returns an enumeration of all problems with elements of the image,
+ * but not with the image itself.
+ * Returns an Enumeration of IProblemDetail.
+ */
+ public Enumeration getAllProblems();
+ /**
+ * Returns the problems with the image itself. Returns null if no
+ * problems exist for the image. An example of such a problem is
+ * duplicate types in a package.
+ * Returns an Enumeration of IProblemDetail.
+ */
+ public Enumeration getImageProblems();
+ /**
+ * Returns an enumeration of problem table keys (sourceID objects)
+ */
+ public Enumeration getProblemKeys();
+ /**
+ * Returns an enumeration of problems for a given source.
+ */
+ public Enumeration getProblems(Object sourceID);
+ /**
+ * Returns a vector of problems for a given source,
+ * or null if no problems.
+ */
+ public Vector getProblemVector(Object sourceID);
+ /**
+ * Returns whether the given source has any problems.
+ */
+ public boolean hasProblems(Object sourceID);
+ /**
+ * Adds a problem to this problem reporter for a source with the given ID.
+ * If the problem is a duplicate, it is not added and an error message is
+ * printed to the console.
+ */
+ public void putProblem(Object sourceID, IProblemDetail problem);
+ /**
+ * Removes all problems except syntax errors for the given source.
+ */
+ public void removeNonSyntaxErrors(Object sourceID);
+ /**
+ * Removes all problems for the given source.
+ */
+ public void removeProblems(Object sourceID);
+ /**
+ * Removes all syntax errors for the given source.
+ */
+ public void removeSyntaxErrors(Object sourceID);
+
+ /**
+ * Initializes this problem reporter for the given project.
+ * This is used only when deserializing a state.
+ */
+ public void initialize(IProject project, IDevelopmentContext devContext);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IReportCard.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IReportCard.java
new file mode 100644
index 0000000000..d1ac090a23
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IReportCard.java
@@ -0,0 +1,57 @@
+package org.eclipse.jdt.internal.core.builder;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * Represents a workspace-based report card.
+ */
+public interface IReportCard {
+
+ /**
+ * Calculates the paths for all resources that have a changed problem state between
+ * this report card and previous.
+ */
+ IPath[] changedPaths(IReportCard previous);
+ /**
+ * Returns this report card's image context.
+ */
+ IImageContext getImageContext();
+ /**
+ * Returns the problem details pertaining to built objects having the
+ * given path, or having the path as a prefix of their path.
+ * That is, this returns all problems with the specified element and all its children.
+ * Only objects within the scope of the report card's image context are considered.
+ * If null is passed, all problems within the image context are returned,
+ * as well as problems reported against the image itself (e.g. missing required classes).
+ */
+ IProblemDetail[] getLeafProblemsFor(IPath path);
+ /**
+ * Returns the paths of resources whose built objects have problems.
+ * Only objects having the given path, or having the given path
+ * as a prefix of their path, are considered.
+ * Only objects within the scope of the report card's image context are considered.
+ * If null is passed, all objects within the image context are considered.
+ * Note that problems which have no path, such as problems reported against
+ * the image itself, are not considered.
+ * To get all problems, use <code>getLeafProblemsFor(IPath path)</code> instead.
+ *
+ * @see #getLeafProblemsFor
+ */
+ IPath[] getProblemPaths(IPath path);
+ /**
+ * Returns this report card's state.
+ */
+ IState getState();
+ /**
+ * Returns whether there are problems pertaining to built objects having the
+ * given path, or having the given path as a prefix of their path.
+ * See <code>getLeafProblemsFor(IPath path)</code> for more details.
+ *
+ * @see #getLeafProblemsFor
+ */
+ boolean hasLeafProblems(IPath path);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ISearch.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ISearch.java
new file mode 100644
index 0000000000..bb3e13ec20
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ISearch.java
@@ -0,0 +1,73 @@
+package org.eclipse.jdt.internal.core.builder;
+
+public interface ISearch extends Runnable {
+ /**
+ * Adds the specified action listener to receive progress and result events
+ * from this search. Progress events occur as a search examines the types
+ * and packages in the search scope. Result events occur as a search finds
+ * matches to the search criteria.
+ * @param listener the search listener
+ * @see ISearchListener
+ * @see SearchProgressEvent
+ * @see SearchResultEvent
+ * @see ISearch#removeSearchListener
+ */
+ void addSearchListener(ISearchListener listener);
+ /**
+ * Cancels the search. If the search is not running, this operation has no
+ * effect.
+ */
+ void cancelSearch();
+ /**
+ * Returns whether two ISearch objects are equal or not.
+ * Two ISearch objects are considered to be equal if
+ * they are the same object OR:
+ * <ul>
+ * <li> neither is equal to null AND
+ * <li> both searches have the same kind (i.e.. search for type), name
+ * (i.e., type named 'Foo') return type, number and type of parameters
+ * (even if not used -- as in the case of search for type), and search
+ * context (i.e., ISearchFactory.SEARCH_FOR_DECLS)
+ * <li> their scopes are equal (contain the same IPackage and IType handles, in any order)
+ * </ul>
+ */
+
+ boolean equals(Object obj);
+ /**
+ * Returns the item <i>n</i>th item in the search result. This may be a field,
+ * method, constructor, package, or type object.
+ */
+ IHandle getItem(int n);
+ /**
+ * Returns the number of items in the search scope which matched the
+ * search goal so far. Note that the result may not include all matches
+ * within the search space if the search is still running or was cancelled.
+ */
+ int getItemCount();
+ /**
+ * Returns the positions for the <i>n</i>th item in the search result.
+ * If no positions exist, null is returned.
+ */
+ int[] getPositions(int n);
+ /**
+ * Returns whether a search is currently in progress.
+ */
+ boolean isSearching();
+ /**
+ * Removes the specified action listener so that it no longer
+ * receives progress and result events from the search.
+ * @param listener the search listener
+ * @see ISearchListener
+ * @see SearchProgressEvent
+ * @see SearchResultEvent
+ * @see ISearch#addSearchListener
+ */
+ void removeSearchListener(ISearchListener listener);
+ /**
+ * Performs the search. Upon return the results can be obtained via
+ * <code>getItem</code>. During the search, the results are made available
+ * as they are found, and progress and results are reported to registered
+ * <code>ISearchListener</code>s.
+ */
+ void run();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ISearchFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ISearchFactory.java
new file mode 100644
index 0000000000..485ccd8f25
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ISearchFactory.java
@@ -0,0 +1,231 @@
+package org.eclipse.jdt.internal.core.builder;
+
+public interface ISearchFactory {
+ /* Flags for search context */
+
+ /**
+ * Context flag indicating that declarations are to be searched.
+ * Searches using this flag search over type, inner type,
+ * field, method and constructor declarations.
+ */
+ int SEARCH_FOR_DECLS = 0x01;
+
+ /**
+ * Context flag indicating that references in the principle structure
+ * are to be searched. The only references which are contained in the
+ * principle structure are references to types and packages -- in field
+ * declarations, superclass/superinterface declarations, parameter, exception,
+ * and method return types.
+ */
+ int SEARCH_FOR_PRINCIPLE_STRUCTURE_REFS = 0x02;
+
+ /**
+ * Context flag indicating that references in the source are to be
+ * searched. Only references made within the body of methods/constructors,
+ * in static and instance initializers, or in import declarations are
+ * treated as source references. References such as superclass names and
+ * parameter, exception and method return types, etc. are found in the
+ * principle structure.
+ */
+ int SEARCH_FOR_SOURCE_REFS = 0x04;
+
+ /**
+ * Returns an <code>ISearch</code> that will look for fields with a matching
+ * name.
+ * <p>
+ * <b>Example:</b> Searching for declarations of fields named <code>width</code>
+ * in package <code>java.awt</code>.
+ * <pre><code>
+ * IImage image = dc.getImage();
+ * ISearchFactory sf = image.newSearchFactory();
+ * IHandle[] scope = {image.getPackageHandle("java.awt", false)};
+ * ISearch search =
+ * sf.searchForField(
+ * "width",
+ * scope,
+ * ISearchFactory.SEARCH_FOR_DECLS);
+ * search.run();
+ * </code></pre>
+ * @param fieldName the name of the field to search for, possibly containing
+ * wildcards ("*")
+ * @param scope the packages and types to search in
+ * @param context the context flags. SEARCH_FOR_DECLS, and
+ * SEARCH_FOR_SOURCE_REFS are valid flags for field searches.
+ * SEARCH_FOR_PRINCIPLE_STRUCTURE_REFS will not have any effect on
+ * the search because there are no field references in the principle
+ * structure.
+ *
+ *
+ * @see ISearch
+ */
+ ISearch searchForField(String fieldName, IHandle[] scope, int context);
+ /**
+ * Returns an <code>ISearch</code> that will look for methods or constructors
+ * with matching name, parameter types, and return type.
+ * <p>
+ * When searching for a constructor, the return type is ignored.
+ * <p>
+ * <b>Example:</b> Search for declarations of methods named <code>toString</code>
+ * whose second argument is <code>int</code>. The search will be conducted
+ * in the scope of the <code>hanoiExample</code> package.
+ * <code><pre>
+ * IImage image = dc.getImage();
+ * ISearchFactory factory = image.newSearchFactory();
+ * IHandle[] scope = {image.getPackageHandle("hanoiExample")};
+ * ISearch search =
+ * factory.searchForMethod(
+ * "toString",
+ * new String[] {"*", "int"},
+ * "*",
+ * scope,
+ * SEARCH_FOR_DECLS);
+ * search.run();
+ * </code></pre>
+ * <br>
+ * @param methodName the method name to search for, possibly containing wildcards ("*")
+ * @param paramTypes the names of parameter types the method being searched for must
+ * have, possibly containing wildcards. An empty array indicates a method with
+ * zero parameters.
+ * @param returnType the name of the return type the method being
+ * searched for must have, possibly containing wildcards. A return type
+ * of "*" effectively ignores the return type.
+ * @param scope the packages and types to search in
+ * @param context the context flags. SEARCH_FOR_DECLS make sense as a flag for
+ * this method search. Using SEARCH_FOR_PRINCIPLE_STRUCTURE_REFS will have no effect since methods
+ * cannot be referenced in the principle structure. When searching the source,
+ * SEARCH_FOR_SOURCE_REFS will ignore the return type, and only use the
+ * number of parameters, not the parameter types. This is because at the source
+ * level only the method name and number of parameters are
+ * known.
+ * @see ISearch
+ */
+ ISearch searchForMethod(
+ String methodName,
+ String[] paramTypes,
+ String returnType,
+ IHandle[] scope,
+ int context);
+ /**
+ * Returns an <code>ISearch</code> that will look for methods or constructors
+ * with matching name, number of parameters, and return type. A parameter count
+ * of -1 indicates that the number of parameters doesn't matter.
+ * <p>
+ * When searching for a constructor, the return type is ignored.
+ * <p>
+ * <b>Example 1:</b> Search for declarations and references to methods named <code>add</code>
+ * which have 2 arguments. The search will be conducted in the scope of the <code>hanoiExample</code>
+ * package. Note that the principle structure is not searched for references
+ * since it never contains information about references to methods.
+ * <code><pre>
+ * IImage image = dc.getImage();
+ * ISearchFactory factory = image.newSearchFactory();
+ * IHandle[] scope = {image.getPackageHandle("hanoiExample")};
+ * ISearch search =
+ * factory.searchForMethod(
+ * "add",
+ * 2,
+ * "*",
+ * scope,
+ * SEARCH_FOR_DECLS |
+ * SEARCH_FOR_SOURCE_REFS);
+ * search.run();
+ * </code></pre>
+ * <br>
+ * <b>Example 2:</b> Search for references to a constructor for a class named
+ * <code>Disk</code> which takes any number of arguments. The search will be conducted in
+ * the scope of the <code>hanoiExample</code> package. Note that the principle structure is not searched for references
+ * since it never contains information about references to methods.
+ * <code><pre>
+ * IImage image = dc.getImage();
+ * ISearchFactory factory = image.newSearchFactory();
+ * IHandle[] scope = {image.getPackageHandle("hanoiExample")};
+ * ISearch search =
+ * factory.searchForMethod(
+ * "Disk",
+ * -1,
+ * "", // return type ignored for constructors
+ * scope,
+ * SEARCH_FOR_SOURCE_REFS);
+ * search.run();
+ * </code></pre>
+ *
+ * @param methodName the method name to search for, possibly containing wildcards ("*")
+ * @param parameterCount the number of parameters the method being
+ * searched for has. Use -1 if number of parameters doesn't matter
+ * @param returnType the name of the return type the method being
+ * searched for must have, possibly containing wildcards. A return type of
+ * "*" effectively ignores return type.
+ * @param scope the packages and types to search in
+ * @param context the context flags. SEARCH_FOR_DECLS and
+ * SEARCH_FOR_SOURCE_REFS make sense as flags for this method search.
+ * SEARCH_FOR_PRINCIPLE_STRUCTURE_REFS will not have any effect since
+ * principle structures cannot reference methods.
+ *
+ * @see ISearch
+ */
+ ISearch searchForMethod(
+ String methodName,
+ int parameterCount,
+ String returnType,
+ IHandle[] scope,
+ int context);
+ /**
+ * Returns an <code>ISearch</code> that will look for packages with a matching
+ * name.
+ * <p>
+ * <b>Example:</b><br>
+ * Searching for all references (principle structure and source) to packages
+ * matching <code>java.aw*</code> in the scope of the <code>hanoiExample</code>
+ * package.
+ * <pre><code>
+ * IImage image = dc.getImage();
+ * ISearchFactory sf = image.newSearchFactory();
+ * IHandle[] scope = {image.getPackageHandle("hanoiExample", false)};
+ * ISearch search =
+ * sf.searchForPackage(
+ * "java.aw*",
+ * scope,
+ * ISearchFactory.SEARCH_FOR_PRINCIPLE_STRUCTURE_REFS |
+ * ISearchFactory.SEARCH_FOR_SOURCE_REFS);
+ * search.run();
+ * </code></pre>
+ *
+ * @param packageName the name of the package to search for, possibly
+ * containing wildcards ("*")
+ * @param scope the packages and types to search in
+ * @param context the context flags. SEARCH_FOR_PRINCIPLE_STRUCTURE_REFS,
+ * and SEARCH_FOR_SOURCE_REFS make sense as flags for package
+ * searches. Using SEARCH_FOR_DECLS will not have any effect because
+ * packages are not declared anywhere.
+ *
+ * @see ISearch
+ */
+ ISearch searchForPackage(String packageName, IHandle[] scope, int context);
+ /**
+ * Returns an <code>ISearch</code> that will look for types with a matching
+ * name.
+ * <p>
+ * <b>Example:</b><br>
+ * Searching for all declarations of a type named <code>Post</code> in the scope of
+ * package <code>hanoiExample</code>.
+ * <pre><code>
+ * IImage image = dc.getImage();
+ * ISearchFactory sf = image.newSearchFactory();
+ * IHandle[] scope = {image.getPackageHandle("hanoiExample", false)};
+ * ISearch search =
+ * sf.searchForType(
+ * "Post",
+ * scope,
+ * ISearchFactory.SEARCH_FOR_DECLS);
+ * search.run();
+ * </code></pre>
+ * @param typeName the simple name of the type to search for, possibly
+ * containing wildcards ("*")
+ * @param scope the packages and types to search in
+ * @param context the context flags. SEARCH_FOR_DECLS, SEARCH_FOR_PRINCIPLE_STRUCTURE_REFS,
+ * and SEARCH_FOR_SOURCE_REFS all make sense as flags for type searches.
+ *
+ * @see ISearch
+ */
+ ISearch searchForType(String typeName, IHandle[] scope, int context);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ISearchListener.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ISearchListener.java
new file mode 100644
index 0000000000..68d435dd28
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ISearchListener.java
@@ -0,0 +1,26 @@
+package org.eclipse.jdt.internal.core.builder;
+
+public interface ISearchListener extends java.util.EventListener {
+ /**
+ * Reports that the search has been cancelled and is no longer running.
+ */
+ public void cancelled();
+ /**
+ * Reports that the search has finished.
+ */
+ public void done();
+ /**
+ * Reports that the search has moved to the type or package named
+ * in the event.
+ *
+ * @see SearchProgressEvent
+ */
+ public void progressUpdated(SearchProgressEvent e);
+ /**
+ * Reports that the search has found the result given
+ * in the event.
+ *
+ * @see SearchResultEvent
+ */
+ public void resultsUpdated(SearchResultEvent e);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ISourceFragment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ISourceFragment.java
new file mode 100644
index 0000000000..983bf72d12
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ISourceFragment.java
@@ -0,0 +1,40 @@
+package org.eclipse.jdt.internal.core.builder;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * The <code>ISourceFragment</code> represents a fragment of a source.
+ * It is used for navigating from a DC object back to the source.
+ *
+ * For Type position info, use the indexes. For IProblemDetail
+ * position info, use IProblemDetail.getStartPos() / getEndPos()
+ *
+ * @see IMember#getSourceFragment
+ */
+public interface ISourceFragment {
+
+ /**
+ * Compare two Objects for equality. Returns true iff they represent the same
+ * source fragment (same start positions, end positions, element identifiers, and
+ * zip entry names).
+ */
+ boolean equals(Object obj);
+ /**
+ * Returns the path of the fragment.
+ */
+ IPath getPath();
+ /**
+ * If this object represents a source fragment within a ZIP file,
+ * this method returns the name of the corresponding ZIP entry.
+ * If this represents a package fragment within a ZIP file,
+ * this returns the name of the package in the ZIP file, although
+ * there may not be a corresponding entry (i.e. there may only be entries
+ * for the class files within the package).
+ * Otherwise, this returns null.
+ */
+ String getZipEntryName();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IState.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IState.java
new file mode 100644
index 0000000000..a5f3477d87
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IState.java
@@ -0,0 +1,98 @@
+package org.eclipse.jdt.internal.core.builder;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResourceDelta;
+
+/**
+ * This represents a specific, immutable state of the image described by the Development Context.
+ */
+public interface IState {
+ /**
+ * Performs an incremental build, given a new project
+ * and a delta describing the differences between
+ * the project for this state and the new project.
+ * Returns an ImageBuilder representing the process of building
+ * the new state. The result object can be queried for the
+ * new state and for the image delta between this state and
+ * the new state.
+ *
+ * <p> The given delta must represent the differences
+ * between the project for this state and the new project.
+ *
+ * <p> Optionally, the build context for the new state can be
+ * specified. If null is specified, this state's build context
+ * is given to the new state.
+ *
+ * @see #getBuildContext
+ */
+ IImageBuilder applySourceDelta(
+ IProject newProject,
+ IResourceDelta delta,
+ IImageContext buildContext);
+ /**
+ * Compare two Objects for equality. Returns true iff they represent the same state
+ * in the same development context.
+ *
+ * @see IDevelopmentContext
+ */
+ boolean equals(Object obj);
+ /**
+ * Returns the ImageContext representing the subset of the
+ * image which is important to have built as early
+ * as possible. Although all parts of the image can be navigated
+ * to and queried, possibly using other ImageContexts, the builder
+ * gives higher priority to maintaining the build context subset
+ * than to other parts of the image.
+ *
+ * @see #applySourceDelta
+ */
+ IImageContext getBuildContext();
+ /**
+ * Returns the dependency graph for this state, if supported,
+ * or null if the dependency graph is unknown.
+ */
+ IDependencyGraph getDependencyGraph();
+ /**
+ * Returns this state's development context.
+ */
+ IDevelopmentContext getDevelopmentContext();
+ /**
+ * Answer a unique fingerprint for this state.
+ * It is guaranteed that no other state can have the same
+ * fingerprint.
+ * The result should not be modified.
+ */
+ byte[] getFingerprint();
+ /**
+ * Returns the image described by this state. The result is state-specific.
+ *
+ * @see IDevelopmentContext
+ * @see IDevelopmentContext#getImage
+ */
+ IImage getImage();
+ /**
+ * Returns the project which provides the source for this state.
+ */
+ IProject getProject();
+ /**
+ * Returns a report card for this state., restricted to
+ * the given image context.
+ * Problems are organized by workspace element identifiers.
+ * This method is on <code>IState</code> rather than
+ * <code>IImage</code> to make it clear that
+ * the result is inherently state-specific.
+ * @param imageContext the image context in which to
+ * restrict the report card.
+ */
+ IReportCard getReportCard(IImageContext imageContext);
+ /**
+ * Returns a new image delta representing the differences between the this
+ * state and another one. The delta is naive in that no delta information is initially provided.
+ * Only the portion of the states within the given image context are examined.
+ */
+ IDelta newNaiveDeltaWith(IState otherState, IImageContext imgCtx);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IType.java
new file mode 100644
index 0000000000..17adcf25ad
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IType.java
@@ -0,0 +1,562 @@
+package org.eclipse.jdt.internal.core.builder;
+
+public interface IType extends IMember {
+
+ /**
+ * Compares this Type handle against the specified object. Returns
+ * true if the objects are the same. Two Types handles are the same if
+ * they both represent a class or interface and have the same fully qualified name,
+ * or if they both represent the same primitive type,
+ * or if they both represent an array type and have the same component types.
+ * See Handle.equals() for more details.
+ *
+ * @see Handle#equals
+ * @see Handle#hashCode
+ */
+ boolean equals(Object obj);
+ /**
+ * Returns a Type object representing an array type with
+ * the type represented by this object as its component type.
+ * This is a handle-only method.
+ *
+ * @see #getComponentType()
+ */
+ IType getArrayHandle();
+ /**
+ * If this class represents an array type, returns the Type
+ * object representing the component type of the array; otherwise
+ * returns null. The component type of an array may itself be
+ * an array type.
+ * This is a handle-only method.
+ *
+ * See <em>The Java Language Specification</em>, section 10, for details.
+ */
+ IType getComponentType();
+ /**
+ * Returns a Constructor object that represents the specified
+ * constructor of the class represented by this object.
+ * The parameterTypes parameter is an array of Type objects that
+ * identify the constructor's formal parameter types, in declared
+ * order.
+ * Returns null if this type does not represent a class or interface.
+ * This is a handle-only method; the specified constructor may
+ * or may not actually be present in the class or interface.
+ *
+ * @see IConstructor
+ */
+ IConstructor getConstructorHandle(IType[] parameterTypes);
+ /**
+ * Returns a 32-bit CRC of the binary of the class or interface represented
+ * by this object. The result should be treated as a 32-bit unsigned value.
+ * Returns 0 if this object does not represent a class or interface, or
+ * if the type is present but has no binary (for example, in the case of compiler
+ * errors).
+ *
+ * @exception NotPresentException if this class or interface is not present.
+ */
+ int getCRC() throws NotPresentException;
+ /**
+ * Returns an array of Type objects representing all the classes
+ * and interfaces declared as members of the class represented by
+ * this object. This includes public, protected, default
+ * (package) access, and private classes and interfaces declared
+ * by the class, but excludes inherited classes and interfaces.
+ * Returns an array of length 0 if the class declares no classes
+ * or interfaces as members, or if this object represents an
+ * array type or primitive type.
+ * The resulting Types are in no particular order.
+ *
+ * @exception NotPresentException if this class or interface is not present.
+ *
+ * @see #getDeclaringClass
+ * @see #isPackageMember
+ */
+ IType[] getDeclaredClasses() throws NotPresentException;
+ /**
+ * Returns an array of Constructor objects representing all the
+ * constructors declared by the class represented by this
+ * object. These are public, protected, default (package) access,
+ * and private constructors. Returns an array of length 0 if this
+ * object represents an interface, an array type or a primitive type.
+ * The resulting Constructors are in no particular order.
+ *
+ * <p>See <em>The Java Language Specification</em>, section 8.2.
+ *
+ * @exception NotPresentException if this class or interface is not present.
+ *
+ * @see IMember#getDeclaringClass
+ */
+ IConstructor[] getDeclaredConstructors() throws NotPresentException;
+ /**
+ * Returns an array of Field objects representing all the fields
+ * declared by the class or interface represented by this
+ * object. This includes public, protected, default (package)
+ * access, and private fields, but excludes inherited
+ * fields. Returns an array of length 0 if the class or interface
+ * declares no fields, or if this object represents a
+ * primitive type or an array type (the implicit <code>length</code>
+ * field of array types is not considered to be a declared field).
+ * The resulting Fields are in no particular order.
+ * <p>
+ * See <em>The Java Language Specification</em>, sections 8.2 and
+ * 8.3.
+ *
+ * @exception NotPresentException if this class or interface is not present.
+ *
+ * @see IMember#getDeclaringClass
+ */
+ IField[] getDeclaredFields() throws NotPresentException;
+ /**
+ * Returns an array of Method objects representing all the methods
+ * declared by the class or interface represented by this
+ * object. This includes public, protected, default (package)
+ * access, and private methods, but excludes inherited
+ * methods. Returns an array of length 0 if the class or interface
+ * declares no methods, or if this object represents an
+ * array type or primitive type.
+ * The resulting Methods are in no particular order.
+ *
+ * <p>See <em>The Java Language Specification</em>, section 8.2.
+ *
+ * @exception NotPresentException if this class or interface is not present.
+ *
+ * @see IMember#getDeclaringClass
+ */
+ IMethod[] getDeclaredMethods() throws NotPresentException;
+ /**
+ * Returns the declared Java language modifiers, as specified in the declaration
+ * of this class or interface, encoded in an integer.
+ * The modifiers consist of the Java Virtual Machine's constants
+ * for public, protected, private, and final; they should be decoded
+ * using the methods of class Modifier.
+ * The result may not correspond to the modifiers in the compiled
+ * binary, since the compiler may change them (in particular,
+ * for inner classes). The <code>getModifiers()</code>
+ * method should be used if the compiled modifiers are needed.
+ * Returns 0 if this type does not represent a class or interface.
+ *
+ * <p>The modifier encodings are defined in <em>The Java Virtual
+ * Machine Specification</em>, table 4.1.
+ *
+ * @exception NotPresentException if this class or interface is not present.
+ *
+ * @see #getModifiers
+ * @see Modifier
+ */
+ int getDeclaredModifiers() throws NotPresentException;
+ /**
+ * Returns the declared name of the class or interface represented
+ * by this object, as a String.
+ * The name is the simple, unqualified name used in the source code.
+ * If this represents an inner class, it does not include the names
+ * of any containing classes.
+ * If this represents an anonymous class, it returns a String of length 0.
+ * If this does not represent a class or interface, it returns
+ * a String of length 0.
+ *
+ * @return the declared name of the class or interface
+ * represented by this object.
+ * @exception NotPresentException if this class or interface is not present.
+ */
+ String getDeclaredName() throws NotPresentException;
+ /**
+ * If the class or interface represented by this Type object is
+ * a member of another class or interface (i.e. it is a nested class),
+ * this returns the Type object representing the class or interface
+ * of which it is a member (its <em>declaring class</em>).
+ * If this class or interface is a local class, returns the Type
+ * object representing the class containing the member in which
+ * this class is declared.
+ * Returns null if this class or interface is not a nested class,
+ * or if this type does not represent a class or interface.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ *
+ * @exception NotPresentException if this class or interface is not present.
+ *
+ * @see #getDeclaredClasses
+ * @see #isPackageMember
+ */
+ IType getDeclaringClass() throws NotPresentException;
+ /**
+ * Returns a Field object that represents the specified
+ * member field of the class or interface represented
+ * by this object. The name parameter is a String specifying
+ * the simple name of the desired field.
+ * Returns null if this type does not represent a class or interface.
+ * This is a handle-only method; the specified field may
+ * or may not actually be present in the class or interface.
+ *
+ * @see IField
+ */
+ IField getFieldHandle(String name);
+ /**
+ * Returns an array of Type objects representing the
+ * classes in the given ImageContext which directly implement this interface.
+ * A class is said to directly implement this interface if the interface
+ * appears in the <code>implements</code> clause of the class's declaration.
+ * Although all array types are considered to implement the <code>Cloneable</code>
+ * interface, this method never returns array types, only class types.
+ * Returns an array of length 0 if this object does not represent
+ * an interface.
+ * The resulting Types are in no particular order.
+ * See <em>The Java Language Specification</em> section 8.1.4
+ * for more details.
+ *
+ * @param imageContext the ImageContext in which to restrict the search.
+ * @exception NotPresentException if this interface is not present.
+ */
+ IType[] getImplementingClasses(IImageContext imageContext)
+ throws NotPresentException;
+ /**
+ * Returns an array of Type objects representing the direct
+ * superinterfaces of the class or interface represented by this object.
+ * <p>
+ * If this object represents a class, the return value is an array
+ * containing objects representing all interfaces directly implemented by the
+ * class. The order of the interface objects in the array corresponds
+ * to the order of the interface names in the <code>implements</code>
+ * clause of the declaration of the class represented by this object.
+ * <p>
+ * If this object represents an interface, the array contains
+ * objects representing all interfaces directly extended by the interface.
+ * The order of the interface objects in the array corresponds to the
+ * order of the interface names in the <code>extends</code> clause of
+ * the declaration of the interface represented by this object.
+ * <p>
+ * If the class or interface implements no interfaces, or if this
+ * object represents neither a class nor an interface, this method
+ * returns an array of length 0.
+ *
+ * See <em>The Java Language Specification</em> sections 8.1.4 and 9.1.3
+ * for more details.
+ *
+ * @return an array of interfaces implemented by this class.
+ * @exception NotPresentException if this class or interface is not present.
+ */
+ IType[] getInterfaces() throws NotPresentException;
+ /**
+ * Returns a Method object that represents the specified
+ * member method of the class or interface represented
+ * by this object. The name parameter is a String specifying the
+ * simple name the desired method, and the parameterTypes
+ * parameter is an array of Type objects that identify the
+ * method's formal parameter types, in declared order.
+ * Returns null if this type does not represent a class or interface.
+ * This is a handle-only method; the specified method may
+ * or may not actually be present in the class or interface.
+ *
+ * @see IMethod
+ */
+ IMethod getMethodHandle(String name, IType[] parameterTypes);
+ /**
+ * Returns the compiled Java language modifiers for this class or
+ * interface, encoded in an integer. The modifiers consist of the
+ * Java Virtual Machine's constants for public, protected,
+ * private, and final; they should be decoded using the
+ * methods of class Flags.
+ * The result may not correspond to the modifiers as declared in
+ * the source, since the compiler may change them (in particular,
+ * for inner classes). The <code>getDeclaredModifiers()</code>
+ * method should be used if the original modifiers are needed.
+ * Returns 0 if this type does not represent a class or interface.
+ *
+ * <p>The modifier encodings are defined in <em>The Java Virtual
+ * Machine Specification</em>, table 4.1.
+ *
+ * @exception NotPresentException if this class or interface is not present.
+ *
+ * @see #getDeclaredModifiers
+ * @see Flags
+ */
+ int getModifiers() throws NotPresentException;
+ /**
+ * Returns the fully-qualified name of the type (class, interface,
+ * array, or primitive) represented by this object, as a String.
+ * For classes and interfaces, the name is the VM class name,
+ * including the package name.
+ * For inner classes, the name is as described in the
+ * <em>Inner Classes Specification</em>.
+ * For array types, the name is the name of the component type, followed by "[]".
+ * For primitive types, the name is the keyword for the primitive type.
+ * This is a handle-only method.
+ *
+ * @return the fully qualified name of the type represented by this object.
+ */
+ String getName();
+ /**
+ * Returns the Package in which this class or interface is declared.
+ * Returns null if this object represents a primitive type or array type.
+ * This is a handle-only method.
+ */
+ IPackage getPackage();
+ /**
+ * Returns the simple name of the type (class, interface, array,
+ * or primitive) represented by this object, as a String.
+ * For classes, interfaces, inner classes and anonymous classes,
+ * this is the VM class name, excluding the package name.
+ * For array types, this is the simple name of the component type, followed by "[]".
+ * For primitive types, this is the keyword for the primitive type.
+ * This is a handle-only method.
+ *
+ * @return the simple name of the type represented by this object.
+ */
+ String getSimpleName();
+ /**
+ * Returns a SourceFragment describing the fragment of source
+ * from which this type is derived.
+ * Returns null if this type represent a primitive type or an
+ * array type, or if this type is not derived directly from source
+ * (e.g. a fictional type, which is created by the image builder).
+ *
+ * @exception NotPresentException if the member is not present.
+ */
+ ISourceFragment getSourceFragment() throws NotPresentException;
+ /**
+ * Returns an array of Type objects representing the
+ * classes in the given ImageContext which are direct subclasses of
+ * this class.
+ * Returns an array of length 0 if this object does not represent
+ * a class.
+ * The resulting Types are in no particular order.
+ * See <em>The Java Language Specification</em> sections 8.1.3 and 20.3.4
+ * for more details.
+ *
+ * @param imageContext the ImageContext in which to restrict the search.
+ * @exception NotPresentException if this class is not present.
+ */
+ IType[] getSubclasses(IImageContext imageContext) throws NotPresentException;
+ /**
+ * Returns an array of Type objects representing the
+ * interfaces in the given ImageContext which are direct subinterfaces of
+ * this interface.
+ * Returns an array of length 0 if this object does not represent
+ * an interface.
+ * The resulting Types are in no particular order.
+ * See <em>The Java Language Specification</em> section 9.1.3
+ * for more details.
+ *
+ * @param imageContext the ImageContext in which to restrict the search.
+ * @exception NotPresentException if this interface is not present.
+ */
+ IType[] getSubinterfaces(IImageContext imageContext)
+ throws NotPresentException;
+ /**
+ * If this object represents any class other than the class
+ * <code>java.lang.Object</code>, then the object that represents
+ * the direct superclass of that class is returned.
+ * <p>
+ * If this object represents the class <code>java.lang.Object</code>
+ * or this object represents an interface or a primitive type,
+ * <code>null</code> is returned.
+ * If this object represents an array type, then the Type that represents
+ * class <code>java.lang.Object</code> is returned.
+ * <p>
+ * See <em>The Java Language Specification</em> sections 8.1.3 and 20.3.4
+ * for more details.
+ *
+ * @return the superclass of the class represented by this object.
+ * @exception NotPresentException if this type is not present.
+ */
+ IType getSuperclass() throws NotPresentException;
+ /**
+ * Returns true if this object represents an anonymous class,
+ * false otherwise.
+ * An anonymous class is a local inner class with no declared name.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ *
+ * @exception NotPresentException if this class is not present.
+ *
+ * @see #isLocal()
+ */
+ boolean isAnonymous() throws NotPresentException;
+ /**
+ * If this Type object represents an array type, returns true,
+ * otherwise returns false.
+ * This is a handle-only method.
+ *
+ * @see #isClass
+ * @see #isInterface
+ * @see #isPrimitive
+ */
+ boolean isArray();
+ /**
+ * Return <code>true</code> if this represents a binary class or interface,
+ * <code>false</code> otherwise.
+ * A binary type is one which is in .class file format in the workspace.
+ * Returns <code>false</code> if this represents a primitive type or an array type.
+ *
+ * @return <code>true</code> if this object represents a binary class or interface;
+ * <code>false</code> otherwise.
+ * @exception NotPresentException if this type is not present.
+ */
+ boolean isBinary() throws NotPresentException;
+ /**
+ * Determines if this object represents a class type.
+ * This returns false if this object represents an interface,
+ * an array type, or a primitive type.
+ *
+ * @return <code>true</code> if this object represents a class;
+ * <code>false</code> otherwise.
+ * @exception NotPresentException if this type is not present.
+ *
+ * @see #isArray
+ * @see #isInterface
+ * @see #isPrimitive
+ */
+ boolean isClass() throws NotPresentException;
+ /**
+ * Return <code>true</code> if this represents a deprecated member,
+ * <code>false</code> otherwise.
+ * A deprecated object is one that has a 'deprecated' tag in
+ * its doc comment.
+ * Returns <code>false</code> if this represents a primitive type or an array type.
+ *
+ * @return <code>true</code> if this object represents a deprecated member;
+ * <code>false</code> otherwise.
+ * @exception NotPresentException if this type is not present.
+ */
+ boolean isDeprecated() throws NotPresentException;
+ /**
+ * Returns true if this object represents an inner class or interface,
+ * false otherwise.
+ * An inner class is one which can only be created in the context of
+ * an instance of its outer class. This does not include package member
+ * classes or other top-level classes. Such a class cannot be static.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ *
+ * @exception NotPresentException if this class is not present.
+ *
+ * @see #isTopLevel()
+ */
+ boolean isInnerClass() throws NotPresentException;
+ /**
+ * Determines if this object represents an interface type.
+ * This returns false if this object represents a class,
+ * an array type, or a primitive type.
+ *
+ * @return <code>true</code> if this object represents an interface;
+ * <code>false</code> otherwise.
+ * @exception NotPresentException if this type is not present.
+ *
+ * @see #isArray
+ * @see #isClass
+ * @see #isPrimitive
+ */
+ boolean isInterface() throws NotPresentException;
+ /**
+ * Returns true if this object represents a local inner class,
+ * false otherwise.
+ * A local inner class is an inner class which is defined in the body of
+ * a method or other block, not as a class field.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ *
+ * @exception NotPresentException if this class is not present.
+ *
+ * @see #isInnerClass()
+ */
+ boolean isLocal() throws NotPresentException;
+ /**
+ * Returns true if this object represents a class or interface
+ * which is declared as a package member (i.e. a 'normal' class
+ * as in JDK 1.02). Returns false otherwise.
+ * In particular, this method returns false if this object represents a
+ * top-level class which is declared as a member of a class.
+ * For the sake of consistent terminology, a class which is
+ * not a package member is considered 'nested', whether or not
+ * it is top-level.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ *
+ * @exception NotPresentException if this class is not present.
+ * @see #isTopLevel()
+ */
+ boolean isPackageMember() throws NotPresentException;
+ /**
+ * Primitive types are always present.
+ * A class or interface type is present if:
+ * <ul>
+ * <li>its package is present, and
+ * <li>the package declares a type of the same name
+ * </ul>
+ * An array type is present if and only if its component type is present.
+ * See Handle.isPresent() for more details.
+ *
+ * @see IHandle#isPresent
+ */
+ boolean isPresent();
+ /**
+ * Determines if the specified Type object represents a primitive Java
+ * type.
+ * This is a handle-only method.
+ *
+ * <p>There are nine predefined Type objects to represent the eight
+ * primitive Java types and void. These are created by the Java
+ * Virtual Machine, and have the same names as the primitive types
+ * that they represent, namely boolean, byte, char, short, int,
+ * long, float, and double, and void.
+ *
+ * <p>These objects may only be accessed via the following methods,
+ * and are the only objects for which this method returns true.
+ *
+ * @see #isArray
+ * @see #isClass
+ * @see #isInterface
+ * @see IImage#booleanType()
+ * @see IImage#charType()
+ * @see IImage#byteType()
+ * @see IImage#shortType()
+ * @see IImage#intType()
+ * @see IImage#longType()
+ * @see IImage#floatType()
+ * @see IImage#doubleType()
+ * @see IImage#voidType()
+ */
+ boolean isPrimitive();
+ /**
+ * Returns true if the type represented by this object is
+ * synthetic, false otherwise. A synthetic object is one that
+ * was invented by the compiler, but was not declared in the source.
+ * See <em>The Inner Classes Specification</em>.
+ * A synthetic object is not the same as a fictional object.
+ *
+ * @exception NotPresentException if the type is not present.
+ *
+ * @see Handle#isFictional
+ */
+ boolean isSynthetic() throws NotPresentException;
+ /**
+ * Returns true if this object represents a top-level class or interface,
+ * false otherwise.
+ * A top-level class is declared either as a package member or as a
+ * static member of another top-level class. Unlike inner classes,
+ * instances of top-level classes are not created in the context of
+ * another object.
+ * Given the appropriate access modifiers, a top-level class can be
+ * referred to directly by a qualified name.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ *
+ * @exception NotPresentException if this class is not present.
+ *
+ * @see #isInnerClass()
+ */
+ boolean isTopLevel() throws NotPresentException;
+ /**
+ * Converts the object to a string.
+ * If this represents a class or interface, the string representation
+ * is the string <code>"type"</code> followed by a space and then
+ * the fully qualified name of the class or interface.
+ * If this represents a primitive type, the string representation
+ * is the keyword for the primitive type.
+ * If this represents an array type, the string representation is
+ * that of its component type followed by <code>"[]"</code>.
+ *
+ * @return a string representation of this class object.
+ * @see IHandle#toString
+ */
+ String toString();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/InvalidKeyException.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/InvalidKeyException.java
new file mode 100644
index 0000000000..e243be0236
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/InvalidKeyException.java
@@ -0,0 +1,20 @@
+package org.eclipse.jdt.internal.core.builder;
+
+public class InvalidKeyException extends RuntimeException {
+ /**
+ * Constructs an <code>InvalidKeyException</code> without a detail message.
+ */
+ public InvalidKeyException() {
+ super();
+ }
+
+ /**
+ * Constructs an <code>InvalidKeyException</code> with a detail message.
+ *
+ * @param s the detail message.
+ */
+ public InvalidKeyException(String s) {
+ super(s);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/MemoryBinaryBroker.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/MemoryBinaryBroker.java
new file mode 100644
index 0000000000..bfedf09853
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/MemoryBinaryBroker.java
@@ -0,0 +1,65 @@
+package org.eclipse.jdt.internal.core.builder;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.Assert;
+import java.util.*;
+
+/**
+ * A <code>MemoryBinaryBroker</code> caches binaries in memory only.
+ * It is complete, in that it never forgets binaries which it has been given.
+ */
+public class MemoryBinaryBroker implements IBinaryBroker {
+
+ Hashtable fTable = new Hashtable();
+ /**
+ * @see IBinaryBroker
+ */
+ public synchronized void close() {
+ // NOP
+ }
+
+ /**
+ * @see IBinaryBroker
+ */
+ public synchronized void garbageCollect(Hashtable keysInUse) {
+ Vector toRemove = new Vector();
+ for (Enumeration e = fTable.keys(); e.hasMoreElements();) {
+ BinaryBrokerKey key = (BinaryBrokerKey) e.nextElement();
+ if (!keysInUse.containsKey(key)) {
+ toRemove.addElement(key);
+ }
+ }
+ for (Enumeration e = toRemove.elements(); e.hasMoreElements();) {
+ BinaryBrokerKey key = (BinaryBrokerKey) e.nextElement();
+ fTable.remove(key);
+ }
+ }
+
+ /**
+ * @see IBinaryBroker
+ */
+ public synchronized byte[] getBinary(BinaryBrokerKey key) {
+ return (byte[]) fTable.get(key);
+ }
+
+ /**
+ * @see IBinaryBroker
+ */
+ public synchronized void putBinary(BinaryBrokerKey key, byte[] bytes) {
+ byte[] old = (byte[]) fTable.get(key);
+ /* Sanity check that old is same as new */
+ if (old != null) {
+ Assert.isTrue(old.length == bytes.length);
+ for (int i = old.length; --i >= 0;) {
+ if (old[i] != bytes[i]) {
+ Assert.isTrue(false);
+ }
+ }
+ }
+ fTable.put(key, bytes);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NotPresentException.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NotPresentException.java
new file mode 100644
index 0000000000..4f2fbb568d
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NotPresentException.java
@@ -0,0 +1,21 @@
+package org.eclipse.jdt.internal.core.builder;
+
+public class NotPresentException extends RuntimeException {
+
+ /**
+ * Constructs a <code>NotPresentException</code> without a detail message.
+ */
+ public NotPresentException() {
+ super();
+ }
+
+ /**
+ * Constructs a <code>NotPresentException</code> with a detail message.
+ *
+ * @param s the detail message.
+ */
+ public NotPresentException(String s) {
+ super(s);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/SearchProgressEvent.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/SearchProgressEvent.java
new file mode 100644
index 0000000000..5a3796db2d
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/SearchProgressEvent.java
@@ -0,0 +1,22 @@
+package org.eclipse.jdt.internal.core.builder;
+
+public class SearchProgressEvent extends java.util.EventObject {
+ String name;
+ /**
+ * Creates a new <code>SearchProgressEvent</code> with the fully-qualified
+ * name of the package or type that is now being searched.
+ */
+ public SearchProgressEvent(String name) {
+ super(name);
+ this.name = name;
+ }
+
+ /**
+ * Returns the name of the package or type that this
+ * progress event represents.
+ */
+ public String getName() {
+ return name;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/SearchResultEvent.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/SearchResultEvent.java
new file mode 100644
index 0000000000..d8beeecd3c
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/SearchResultEvent.java
@@ -0,0 +1,43 @@
+package org.eclipse.jdt.internal.core.builder;
+
+public class SearchResultEvent extends java.util.EventObject {
+ IHandle result;
+ int[] fMatchingPositions;
+ /**
+ * Creates a new <code>SearchResultEvent</code> with the handle
+ * of the result that has been found.
+ */
+ public SearchResultEvent(IHandle result) {
+ this(result, null);
+ }
+
+ /**
+ * Creates a new <code>SearchResultEvent</code> with the handle
+ * of the result that has been found.
+ */
+ public SearchResultEvent(IHandle result, int[] positions) {
+ super(result);
+ this.result = result;
+ this.fMatchingPositions = positions;
+ }
+
+ /**
+ * Returns the matching char offset positions within the workspace element.
+ * Returns null if matching positions are not known.
+ */
+ public int[] getMatchingPositions() {
+ return fMatchingPositions;
+ }
+
+ /**
+ * Returns the result that this progress event represents.
+ */
+ public IHandle getResult() {
+ return result;
+ }
+
+ public String toString() {
+ return result.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/StateSpecificException.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/StateSpecificException.java
new file mode 100644
index 0000000000..ceef0fcc87
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/StateSpecificException.java
@@ -0,0 +1,21 @@
+package org.eclipse.jdt.internal.core.builder;
+
+public class StateSpecificException extends RuntimeException {
+
+ /**
+ * Constructs a <code>StateSpecificException</code> without a detail message.
+ */
+ public StateSpecificException() {
+ super();
+ }
+
+ /**
+ * Constructs a <code>StateSpecificException</code> with a detail message.
+ *
+ * @param s the detail message.
+ */
+ public StateSpecificException(String s) {
+ super(s);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/AbstractImageBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/AbstractImageBuilder.java
new file mode 100644
index 0000000000..6bcb0ca2ff
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/AbstractImageBuilder.java
@@ -0,0 +1,202 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.core.builder.*;
+
+import java.util.*;
+
+/**
+ * The abstract superclass of image builders.
+ * Provides the building and compilation mechanism
+ * in common with the batch and incremental builders.
+ */
+public abstract class AbstractImageBuilder
+ implements IImageBuilder, ICompilerRequestor {
+ protected JavaDevelopmentContextImpl fDC;
+ protected StateImpl fOldState;
+ protected StateImpl fNewState;
+ protected WorkQueue fWorkQueue;
+ protected BuilderEnvironment fBuilderEnvironment;
+ protected BuildNotifier fNotifier;
+ protected org.eclipse.jdt.internal.compiler.Compiler fCompiler;
+ protected ConfigurableOption[] fCompilerOptions;
+ protected Vector fCompilationResults;
+ public int MAX_AT_ONCE = 1000;
+ /**
+ * Creates a new builder.
+ */
+ protected AbstractImageBuilder() {
+ }
+
+ public void acceptResult(CompilationResult result) {
+ ConvertedCompilationResult convertedResult =
+ fNewState.convertCompilationResult(
+ result,
+ getBuilderEnvironment().getDefaultPackage());
+ PackageElement element = convertedResult.getPackageElement();
+ if (!fWorkQueue.hasBeenCompiled(element)) {
+ fCompilationResults.addElement(convertedResult);
+ fNotifier.compiled((CompilerCompilationUnit) result.getCompilationUnit());
+ fWorkQueue.compiled(element);
+ }
+ }
+
+ /**
+ * Check whether the build has been canceled.
+ */
+ protected void checkCancel() {
+ fNotifier.checkCancel();
+ }
+
+ /**
+ * Since the image builder is given as a result, let go of
+ * any unneeded structures.
+ */
+ protected void cleanUp() {
+ fCompiler = null;
+ fCompilationResults = null;
+ fWorkQueue = null;
+ fBuilderEnvironment = null;
+ fNotifier = null;
+ fNewState.cleanUp();
+ }
+
+ /**
+ * Compile the given elements, adding more elements to the work queue
+ * if they are affected by the changes.
+ */
+ protected void compile(Vector vToCompile) {
+ int i = 0;
+ Vector vToCompileAtOnce = new Vector(Math.min(vToCompile.size(), MAX_AT_ONCE));
+ while (i < vToCompile.size()) {
+ vToCompileAtOnce.removeAllElements();
+ while (i < vToCompile.size() && vToCompileAtOnce.size() < MAX_AT_ONCE) {
+ PackageElement unit = (PackageElement) vToCompile.elementAt(i);
+ // Although it needed compiling when this method was called,
+ // it may have already been compiled due to being brought in
+ // by another unit.
+ if (fWorkQueue.needsCompile(unit)) {
+ SourceEntry sEntry = fNewState.getSourceEntry(unit);
+ CompilerCompilationUnit compUnit =
+ new CompilerCompilationUnit(fNewState, sEntry, fNotifier);
+ compiling(compUnit);
+ vToCompileAtOnce.addElement(compUnit);
+ checkCancel();
+ }
+ ++i;
+ }
+ if (vToCompileAtOnce.size() > 0) {
+ CompilerCompilationUnit[] toCompile =
+ new CompilerCompilationUnit[vToCompileAtOnce.size()];
+ vToCompileAtOnce.copyInto(toCompile);
+ try {
+ fDC.inCompiler = true;
+ getCompiler().compile(toCompile);
+ } finally {
+ fDC.inCompiler = false;
+ }
+
+ /* Check for cancel immediately after a compile, because the compile may have been
+ * canceled but without propagating the build canceled exception. */
+ checkCancel();
+
+ /* store results in new state and get new units to compile */
+ ConvertedCompilationResult[] results = getCompilationResults();
+ updateState(results);
+ checkCancel();
+ }
+ }
+ }
+
+ /**
+ * A unit is being (re)compiled. Save any previous type structure.
+ */
+ protected void compiling(CompilerCompilationUnit unit) {
+ }
+
+ /**
+ * Returns the builder environment to use for this builder.
+ */
+ public BuilderEnvironment getBuilderEnvironment() {
+ if (fBuilderEnvironment == null) {
+ fBuilderEnvironment = new BuilderEnvironment(this);
+ fBuilderEnvironment.setDefaultPackage(fNewState.defaultPackageForProject());
+ }
+ return fBuilderEnvironment;
+ }
+
+ /**
+ * Returns the results of the last compile.
+ */
+ protected ConvertedCompilationResult[] getCompilationResults() {
+ ConvertedCompilationResult[] results =
+ new ConvertedCompilationResult[fCompilationResults.size()];
+ fCompilationResults.copyInto(results);
+ fCompilationResults = null;
+ return results;
+ }
+
+ /**
+ * Returns the compiler to use.
+ */
+ protected Compiler getCompiler() {
+ // Make sure to clear the results before starting a new compile.
+ fCompilationResults = new Vector();
+ if (fCompiler == null) {
+ IErrorHandlingPolicy errorPolicy =
+ DefaultErrorHandlingPolicies.proceedWithAllProblems();
+ IProblemFactory problemFactory =
+ ProblemFactory.getProblemFactory(Locale.getDefault());
+ fCompiler =
+ new Compiler(
+ getBuilderEnvironment(),
+ errorPolicy,
+ fCompilerOptions,
+ this,
+ problemFactory);
+ }
+ return fCompiler;
+ }
+
+ /**
+ * Returns the state that is being built.
+ */
+ public IState getNewState() {
+ return fNewState;
+ }
+
+ /**
+ * Returns the old state if the image is being built incrementally
+ */
+ public IState getOldState() {
+ return fOldState;
+ }
+
+ /**
+ * Returns true if the given source entry must be recompiled, false otherwise.
+ */
+ protected boolean isInvalid(SourceEntry sEntry) {
+ return fWorkQueue.needsCompile(fNewState.packageElementFromSourceEntry(sEntry));
+ }
+
+ /**
+ * Stores the results of a compilation in the appropriate state tables.
+ * Keeps track of what compilation units need to be compiled as a result
+ * of the changes.
+ */
+ protected void updateState(ConvertedCompilationResult[] results) {
+ // Must store all compilation results, so state has sufficient information
+ // to calculate changes.
+ fNewState.putCompilationResults(results);
+
+ // Notify listeners
+ fNotifier.notifyElementsChanged(results, fOldState, fNewState);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/AbstractMemberHandle.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/AbstractMemberHandle.java
new file mode 100644
index 0000000000..7bb21b5ca7
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/AbstractMemberHandle.java
@@ -0,0 +1,139 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.builder.*;
+
+public abstract class AbstractMemberHandle
+ extends NonStateSpecificHandleImpl
+ implements IMember {
+ /**
+ * The owner of the member
+ */
+ ClassOrInterfaceHandleImpl fOwner;
+
+ /**
+ * Member signature
+ */
+ String fSignature;
+ /**
+ * Synopsis: Answer a method or constructor signature given
+ * the name (which may be empty) and the parameter types.
+ */
+ String computeSignature(String name, IType[] parameterTypes) {
+
+ if (parameterTypes.length == 0) {
+ return name + "()";
+ }
+
+ StringBuffer sb = new StringBuffer(name);
+ sb.append('(');
+ for (int i = 0; i < parameterTypes.length; i++) {
+ try {
+ ((TypeImpl) parameterTypes[i]).appendSignature(sb, true);
+ } catch (ClassCastException e) {
+ throw new StateSpecificException("incompatible parameter types");
+ }
+ }
+ sb.append(')');
+ return sb.toString();
+ }
+
+ /**
+ * Compares two members
+ */
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof AbstractMemberHandle))
+ return false;
+
+ AbstractMemberHandle member = (AbstractMemberHandle) o;
+ return member.fSignature.equals(this.fSignature)
+ && member.fOwner.equals(this.fOwner);
+ }
+
+ /**
+ * Returns the owning class of this member.
+ */
+ public IType getDeclaringClass() {
+ return fOwner;
+ }
+
+ /**
+ * getInternalDC method comment.
+ */
+ JavaDevelopmentContextImpl getInternalDC() {
+ return fOwner.getInternalDC();
+ }
+
+ /**
+ * Returns the Java language modifiers for the member
+ * represented by this object, as an integer.
+ */
+ public int getModifiers() {
+ return ((AbstractMemberHandleSWH) inCurrentState()).getModifiers();
+ }
+
+ /**
+ * Returns the simple name of the member represented by this object.
+ * If this Member represents a constructor, this returns
+ * the simple name of its declaring class.
+ * This is a handle-only method.
+ */
+ public abstract String getName();
+ /**
+ * Returns the signature of the member. For fields, this is the field name.
+ * For methods, this is the method name, followed by $(, followed by the
+ * source signatures of the parameter types, followed by $).
+ * For constructors, this is $(, followed by the source signatures of the
+ * parameter types, followed by $).
+ */
+ String getSignature() {
+ return fSignature;
+ }
+
+ /**
+ * Returns a consistent hash code for this object
+ */
+ public int hashCode() {
+ return fSignature.hashCode();
+ }
+
+ /**
+ * Returns true if this represents a binary member, false otherwise.
+ * A binary member is one for which the declaring class is in .class
+ * file format in the source tree.
+ */
+ public boolean isBinary() {
+ return ((IMember) inCurrentState()).isBinary();
+ }
+
+ /**
+ * @see IMember
+ */
+ public boolean isDeprecated() {
+ return ((AbstractMemberHandleSWH) inCurrentState()).isDeprecated();
+ }
+
+ /**
+ * Returns true if the member represented by this object is
+ * synthetic, false otherwise. A synthetic object is one that
+ * was invented by the compiler, but was not declared in the source.
+ * See <em>The Inner Classes Specification</em>.
+ * A synthetic object is not the same as a fictitious object.
+ */
+ public boolean isSynthetic() {
+ return ((AbstractMemberHandleSWH) inCurrentState()).isSynthetic();
+ }
+
+ /**
+ * kind method comment.
+ */
+ public int kind() {
+ return 0;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/AbstractMemberHandleSWH.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/AbstractMemberHandleSWH.java
new file mode 100644
index 0000000000..5f1c2db1fb
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/AbstractMemberHandleSWH.java
@@ -0,0 +1,80 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.builder.*;
+
+public abstract class AbstractMemberHandleSWH
+ extends StateSpecificHandleImpl
+ implements IMember {
+ /**
+ * Returns the Type object representing the class or interface
+ * that declares the member represented by this object.
+ * Derived from java.lang.reflect.Member.getDeclaringClass();
+ * This is a handle-only method.
+ */
+ public IType getDeclaringClass() {
+ return (IType) getHandle().getDeclaringClass().inState(fState);
+ }
+
+ /**
+ * Returns the handle for this member
+ */
+ abstract IMember getHandle();
+ /**
+ * Returns the Java language modifiers for the member
+ * represented by this object, as an integer.
+ */
+ public abstract int getModifiers();
+ /**
+ * Returns the simple name of the member represented by this object.
+ * If this Member represents a constructor, this returns
+ * the simple name of its declaring class.
+ * This is a handle-only method.
+ */
+ public String getName() {
+ return ((IMember) nonStateSpecific()).getName();
+ }
+
+ /**
+ * Returns the type structure entry for the class or interface.
+ */
+ TypeStructureEntry getTypeStructureEntry() throws NotPresentException {
+ TypeStructureEntry tsEntry =
+ fState.getTypeStructureEntry(getHandle().getDeclaringClass(), true);
+ if (tsEntry == null) {
+ throw new NotPresentException();
+ }
+ return tsEntry;
+ }
+
+ /**
+ * Returns true if this represents a binary member, false otherwise.
+ * A binary member is one for which the declaring class is in .class
+ * file format in the source tree.
+ */
+ public boolean isBinary() {
+ if (!isPresent())
+ throw new NotPresentException();
+ return getDeclaringClass().isBinary();
+ }
+
+ /**
+ * @see IMember
+ */
+ public abstract boolean isDeprecated();
+ /**
+ * Returns true if the member represented by this object is
+ * synthetic, false otherwise. A synthetic object is one that
+ * was invented by the compiler, but was not declared in the source.
+ * See <em>The Inner Classes Specification</em>.
+ * A synthetic object is not the same as a fictitious object.
+ */
+ public boolean isSynthetic() {
+ //Do we have synthetic fields right now?
+ return false;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/AbstractMethodCollaboratorIndictment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/AbstractMethodCollaboratorIndictment.java
new file mode 100644
index 0000000000..baa07ef229
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/AbstractMethodCollaboratorIndictment.java
@@ -0,0 +1,53 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.builder.IType;
+
+/**
+ * An AbstractMethodCollaboratorIndictment is issued whenever an interface or abstract
+ * class adds an abstract method. All direct subtypes of the originating
+ * interface or abstract class must be found guilty and recompiled,
+ * regardless of evidence.
+ */
+class AbstractMethodCollaboratorIndictment extends Indictment {
+
+ protected IType fType;
+
+ /**
+ * Creates a new AbstractMethodCollaboratorIndictment for the given type.
+ */
+ protected AbstractMethodCollaboratorIndictment(IType type) {
+ super(type.getName().toCharArray());
+ fType = type;
+ }
+
+ /**
+ * Returns what kind of indictment this is
+ */
+ public int getKind() {
+ return K_ABSTRACT_METHOD;
+ }
+
+ /**
+ * Returns the type handle.
+ */
+ public IType getType() {
+ return fType;
+ }
+
+ /**
+ * Returns a string representation of this class. For debugging purposes
+ * only (NON-NLS).
+ */
+ public String toString() {
+ // don't use + with char[]
+ return new StringBuffer("AbstractMethodCollaboratorIndictment(")
+ .append(fName)
+ .append(")")
+ .toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/AbstractNode.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/AbstractNode.java
new file mode 100644
index 0000000000..3aedc021dd
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/AbstractNode.java
@@ -0,0 +1,374 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.Assert;
+import org.eclipse.jdt.internal.core.builder.IType;
+import org.eclipse.jdt.internal.core.util.Dumper;
+import org.eclipse.jdt.internal.core.util.IDumpable;
+
+import java.util.*;
+
+/**
+ * A node in the image builder dependency graph.
+ * @see IDependencyGraph
+ */
+public abstract class AbstractNode implements INode, IDumpable, Cloneable {
+
+ /**
+ * The "order number" of the node.
+ * Nodes with lower order numbers are earlier
+ * in the topological order.
+ * An order of -1 indicates that the order has not yet been calculated.
+ */
+ protected int fOrder = -1;
+
+ /**
+ * Nodes that this node depends on
+ */
+ protected INode[] fDependencies = fgEmptyNodeList;
+
+ /**
+ * Nodes that depend on this node
+ */
+ protected INode[] fDependents = fgEmptyNodeList;
+ protected int fNumDependents = 0;
+
+ /**
+ * Default list of dependencies or dependents
+ */
+ protected static final INode[] fgEmptyNodeList = new INode[0];
+ /**
+ * Hide the default constructor to force specialized instantiation of subclasses
+ */
+ protected AbstractNode() {
+ }
+
+ /**
+ * Adds a node that depends on this node.
+ * IMPORTANT: This should only be called by addDependency.
+ */
+ public void addDependent(INode nodeThatDependsOnMe) {
+ /* check if I already have this dependent */
+ /*
+ for (int i = fNumDependents; --i >= 0;) {
+ if (fDependents[i] == nodeThatDependsOnMe) {
+ System.out.println("Attempt to add duplicate dependent " + nodeThatDependsOnMe.getElement() + " to " + getElement());
+ return;
+ }
+ }
+ */
+ if (fNumDependents >= fDependents.length) {
+ /* grow array */
+ INode[] newDependents =
+ new INode[fNumDependents == 0 ? 5 : fNumDependents * 2 + 1];
+ System.arraycopy(fDependents, 0, newDependents, 0, fNumDependents);
+ fDependents = newDependents;
+ }
+ fDependents[fNumDependents++] = nodeThatDependsOnMe;
+ }
+
+ /**
+ * Clears all outgoing dependency links for this node
+ */
+ public void clearDependencies() {
+
+ /* do for all my dependencies (Nodes that I depend on) */
+ INode[] dependencies = getDependencies();
+ for (int i = 0; i < dependencies.length; i++) {
+ dependencies[i].removeDependent(this);
+ }
+ fDependencies = fgEmptyNodeList;
+ invalidateOrder();
+ }
+
+ /**
+ * Returns a copy of this node, without copying dependencies. Used
+ * by DependencyGraph.copy().
+ */
+ public abstract AbstractNode copy();
+ /**
+ * Adds a node that depends on this node.
+ * IMPORTANT: This should only be called by dependency graph copy methods.
+ * The dependents array at this point contains either new dependents or null
+ * values. This method must find the first null entry in the dependents array
+ * and add the given value.
+ */
+ public void copyAddDependent(INode nodeThatDependsOnMe) {
+ /* find first null entry */
+ int min = 0;
+ int max = fNumDependents - 1;
+ int mid = (max + min) / 2;
+ boolean found = false;
+
+ /* binary search until on or next to first non-null entry */
+ try {
+ while (max > min) {
+ if (fDependents[mid] == null) {
+ /* look in lower half */
+ max = mid - 1;
+ } else {
+ /* look in higher half */
+ min = mid + 1;
+ }
+ mid = (max + min) / 2;
+ }
+
+ /* linear search for first non-null entry */
+ while (fDependents[min] != null) {
+ min++;
+ }
+
+ /* add the dependent */
+ fDependents[min] = nodeThatDependsOnMe;
+ } catch (ArrayIndexOutOfBoundsException e) {
+ System.out.println(
+ "ArrayIndexOutOfBoundsException in AbstractNode.copyAddDependent()");
+ }
+ }
+
+ /**
+ * Returns a copy of this node, but with the dependents and dependencies
+ * left unchanged. They are later replaced using replaceDeps().
+ * Be careful that this implementation applies to any information in subclasses.
+ * Right now, all information except the dependents are non-state-specific
+ * and can be shared.
+ */
+ INode copyWithoutReplacingDeps() {
+ AbstractNode newNode = this.copy();
+
+ /* copy dependencies into new array */
+ int depCount = fDependencies.length;
+ newNode.fDependencies = new INode[depCount];
+ for (int i = depCount; --i >= 0;) {
+ newNode.fDependencies[i] = fDependencies[i];
+ }
+
+ newNode.fNumDependents = fNumDependents;
+ newNode.fDependents = new INode[fNumDependents];
+ newNode.fOrder = fOrder;
+ return newNode;
+ }
+
+ /**
+ * For debugging only.
+ */
+ public void dump(Dumper dumper) {
+ dumper.dump("element", getElement());
+ if (getKind() == JCU_NODE)
+ dumper.dump("types", getTypes());
+
+ Object[] dependencies = new Object[fDependencies.length];
+ for (int i = 0; i < fDependencies.length; ++i) {
+ dependencies[i] = fDependencies[i].getElement();
+ }
+ dumper.dump("dependencies", dependencies);
+
+ Object[] dependents = new Object[fNumDependents];
+ for (int i = 0; i < fDependents.length; ++i) {
+ dependents[i] = fDependents[i].getElement();
+ }
+ dumper.dump("dependents", dependents);
+
+ }
+
+ /**
+ * Make sure equality tests are never carried out on nodes
+ */
+ public boolean equals(Object o) {
+ Assert.isTrue(false, "Equality not defined for dependency graph nodes");
+ return false;
+ }
+
+ /**
+ * Returns the nodes that this node depends on. A change to the principal structure
+ * of any of these nodes may affect the principal structure of this node.
+ */
+ public INode[] getDependencies() {
+ return fDependencies;
+ }
+
+ /**
+ * Returns the nodes that depend on this node. A change to the principal structure
+ * of this node may affect the principal structure of the returned dependents.
+ */
+ public INode[] getDependents() {
+ if (fNumDependents < fDependents.length) {
+ System.arraycopy(
+ fDependents,
+ 0,
+ fDependents = new INode[fNumDependents],
+ 0,
+ fNumDependents);
+ }
+ return fDependents;
+ }
+
+ /**
+ * Returns the number of bytes that this node uses.
+ * For debugging and profiling purposes only.
+ */
+ int getFootprint() {
+ /* 5 slots plus 8 bytes for object header */
+ int size = 28;
+
+ /* size of dep arrays */
+ if (fDependencies != null) {
+ size += fDependencies.length * 4;
+ }
+ if (fDependents != null) {
+ size += fDependents.length * 4;
+ }
+ return size;
+ }
+
+ /**
+ * @see INode
+ */
+ public int getOrder() {
+ return getOrder(0);
+ }
+
+ /**
+ * Returns the order number, calculating it if not already done.
+ * seen is a set of previously visited nodes.
+ */
+ private int getOrder(int recursionLevel) {
+ if (fOrder != -1) {
+ return fOrder;
+ }
+
+ // trace(recursionLevel, -1);
+
+ fOrder = 0; // Mark as non-invalid to break cycles
+ int max = -1;
+ for (int i = 0, len = fDependencies.length; i < len; ++i) {
+ int order = ((AbstractNode) fDependencies[i]).getOrder(recursionLevel + 1);
+ if (order > max) {
+ max = order;
+ }
+ }
+ fOrder = max + 1;
+
+ // trace(recursionLevel, fOrder);
+ return fOrder;
+ }
+
+ /**
+ * Returns the types that belong to this node
+ */
+ public IType[] getTypes() {
+ Assert.isTrue(false, "My subclass should have implemented this");
+ return null;
+ }
+
+ /**
+ * Invalidates the order number, for this node and all dependents.
+ */
+ public void invalidateOrder() {
+ if (fOrder != -1) {
+ fOrder = -1;
+ /* do for each node that depends on me */
+ for (int i = 0, len = fNumDependents; i < len; ++i) {
+ ((AbstractNode) fDependents[i]).invalidateOrder();
+ }
+ }
+ }
+
+ /**
+ * Removes a node on which this node depends.
+ * This -does- remove the backwards link from the other node.
+ */
+ public void removeDependency(INode nodeThatIDependOn) {
+ nodeThatIDependOn.removeDependent(this);
+ int size = fDependencies.length;
+ for (int i = size; --i >= 0;) {
+ if (fDependencies[i] == nodeThatIDependOn) {
+ /* shrink array */
+ if (--size == 0) {
+ fDependencies = fgEmptyNodeList;
+ } else {
+ INode[] newDependencies = new INode[size];
+ System.arraycopy(fDependencies, 0, newDependencies, 0, i);
+ System.arraycopy(fDependencies, i + 1, newDependencies, i, size - i);
+ fDependencies = newDependencies;
+ }
+ invalidateOrder();
+ return;
+ }
+ }
+ }
+
+ /**
+ * Removes a node that depends on this node.
+ * This does not remove the backwards link.
+ */
+ public void removeDependent(INode nodeThatDependsOnMe) {
+ int size = fNumDependents;
+ for (int i = size; --i >= 0;) {
+ if (fDependents[i] == nodeThatDependsOnMe) {
+ /* shrink array */
+ if (--size == 0) {
+ fDependents = fgEmptyNodeList;
+ } else {
+ INode[] newDependents = new INode[size];
+ System.arraycopy(fDependents, 0, newDependents, 0, i);
+ System.arraycopy(fDependents, i + 1, newDependents, i, size - i);
+ fDependents = newDependents;
+ }
+ fNumDependents = size;
+ return;
+ }
+ }
+ }
+
+ /**
+ * This node has previously been copied without updating its
+ * dependency references. Now replace the dependency references
+ * with the corresponding nodes in the given graph.
+ * Note that we only need to replace the dependencies, because the dependents
+ * are added as backward links from other nodes.
+ */
+ void replaceDeps(DependencyGraph graph) {
+ int depCount = fDependencies.length;
+ INode newNode;
+
+ for (int i = 0; i < depCount; i++) {
+ /* get new node for old node */
+ newNode = graph.getNodeFor(fDependencies[i]);
+ newNode.copyAddDependent(this);
+ fDependencies[i] = newNode;
+ }
+ }
+
+ /**
+ * Sets the nodes that this node depends on.
+ * Backwards links are added automatically.
+ */
+ public void setDependencies(INode[] nodesThatIDependOn) {
+
+ /* clear old dependencies before nuking array */
+ clearDependencies();
+ fDependencies = nodesThatIDependOn;
+
+ /* add backwards links */
+ for (int i = nodesThatIDependOn.length; --i >= 0;) {
+ nodesThatIDependOn[i].addDependent(this);
+ }
+
+ invalidateOrder();
+ }
+
+ public void trace(int recursionLevel, int refCount) {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < recursionLevel; ++i)
+ sb.append(' ');
+ sb.append(this);
+ sb.append(": ");
+ sb.append(refCount);
+ System.out.println(sb.toString());
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ArrayTypeHandleImpl.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ArrayTypeHandleImpl.java
new file mode 100644
index 0000000000..31508a90d6
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ArrayTypeHandleImpl.java
@@ -0,0 +1,180 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.builder.*;
+
+public class ArrayTypeHandleImpl extends TypeImpl {
+ TypeImpl fElementType;
+ int fNestingDepth;
+ /**
+ * Creates a new ArrayTypeHandleImpl
+ * @param name name of the type
+ * @param depth depth of array nesting
+ */
+ ArrayTypeHandleImpl(TypeImpl type, int depth) {
+ fNestingDepth = depth;
+ fElementType = type;
+ }
+
+ /**
+ * Appends the signature for this type to the StringBuffer.
+ * If includeUnnamed is true, then the identifiers for unnamed packages
+ * are included, preceded by '$'. Otherwise, they are excluded.
+ */
+ void appendSignature(StringBuffer sb, boolean includeUnnamed) {
+
+ for (int i = fNestingDepth; --i >= 0;) {
+ sb.append('[');
+ }
+ fElementType.appendSignature(sb, includeUnnamed);
+ }
+
+ /**
+ * Appends the VM signature of the type to the StringBuffer.
+ */
+ void appendVMSignature(StringBuffer sb) {
+ for (int i = getNestingDepth(); --i >= 0;) {
+ sb.append('[');
+ }
+ getElementType().appendVMSignature(sb);
+ }
+
+ /**
+ * Compares this object against the specified object.
+ * Returns true if the objects are the same.
+ */
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof ArrayTypeHandleImpl))
+ return false;
+
+ ArrayTypeHandleImpl array = (ArrayTypeHandleImpl) o;
+ return fElementType.equals(array.fElementType)
+ && fNestingDepth == array.fNestingDepth;
+ }
+
+ /**
+ * Returns a Type object representing an array type with
+ * the type represented by this object as its component type.
+ * This is a handle-only method.
+ */
+ public org.eclipse.jdt.internal.core.builder.IType getArrayHandle() {
+ return new ArrayTypeHandleImpl(fElementType, fNestingDepth + 1);
+ }
+
+ /**
+ * If this class represents an array type, returns the Type
+ * object representing the component type of the array; otherwise
+ * returns null. The component type of an array may itself be
+ * an array type.
+ * This is a handle-only method.
+ */
+ public org.eclipse.jdt.internal.core.builder.IType getComponentType() {
+ if (fNestingDepth == 1)
+ return fElementType;
+ return new ArrayTypeHandleImpl(fElementType, fNestingDepth - 1);
+ }
+
+ /**
+ * If this is an array type, answer its element type (the leaf non-array type),
+ * otherwise answer this type.
+ */
+
+ TypeImpl getElementType() {
+ return fElementType;
+ }
+
+ public JavaDevelopmentContextImpl getInternalDC() {
+ return fElementType.getInternalDC();
+ }
+
+ /**
+ * Returns the fully-qualified name of the type (class, interface,
+ * array, or primitive) represented by this object, as a String.
+ * For classes and interfaces, the name is the VM class name,
+ * including the package name.
+ * For inner classes, the name is as described in the
+ * <em>Inner Classes Specification</em>.
+ * For array types, the name is the name of the component type, followed by '[]'.
+ * For primitive types, the name is the keyword for the primitive type.
+ * This is a handle-only method.
+ */
+ public String getName() {
+ String name = fElementType.getName();
+ for (int i = 0; i < fNestingDepth; i++)
+ name += "[]";
+ return name;
+ }
+
+ /**
+ * Return the array nesting depth
+ */
+ int getNestingDepth() {
+ return fNestingDepth;
+ }
+
+ /**
+ * getSimpleName method comment.
+ */
+ public String getSimpleName() {
+ String simpleName = fElementType.getSimpleName();
+ for (int i = 0; i < fNestingDepth; i++)
+ simpleName += "[]";
+ return simpleName;
+ }
+
+ /**
+ * If this object represents any class other than the class
+ * <code>java.lang.Object</code>, then the object that represents
+ * the direct superclass of that class is returned.
+ * <p>
+ * If this object represents the class <code>java.lang.Object</code>
+ * or this object represents an interface or a primitive type,
+ * <code>null</code> is returned.
+ * If this object represents an array type, then the Type that represents
+ * class <code>java.lang.Object</code> is returned.
+ * <p>
+ * See <em>The Java Language Specification</em> sections 8.1.3 and 20.3.4
+ * for more details.
+ */
+ public IType getSuperclass() throws NotPresentException {
+ return getInternalDC().getRootClassHandle();
+ }
+
+ /**
+ * Returns a consistent hash code for this object
+ */
+ public int hashCode() {
+ return fElementType.hashCode() + (fNestingDepth * 131);
+ }
+
+ /**
+ * Returns a state specific version of this handle in the given state.
+ */
+ public IHandle inState(IState s)
+ throws org.eclipse.jdt.internal.core.builder.StateSpecificException {
+
+ return new ArrayTypeHandleImplSWH((StateImpl) s, this);
+ }
+
+ /**
+ * If this Type object represents an array type, returns true,
+ * otherwise returns false.
+ * This is a handle-only method.
+ */
+ public boolean isArray() {
+ return true;
+ }
+
+ /**
+ * Set the array nesting depth
+ */
+ void setNestingDepth(int depth) {
+ fNestingDepth = depth;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ArrayTypeHandleImplSWH.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ArrayTypeHandleImplSWH.java
new file mode 100644
index 0000000000..8d3383df43
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ArrayTypeHandleImplSWH.java
@@ -0,0 +1,91 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.builder.*;
+
+public class ArrayTypeHandleImplSWH extends TypeImplSWH {
+ ArrayTypeHandleImpl fHandle;
+ /**
+ * Creates a new method handle in the given state
+ */
+ public ArrayTypeHandleImplSWH(StateImpl state, ArrayTypeHandleImpl handle) {
+ fState = state;
+ fHandle = handle;
+ }
+
+ /**
+ * If this class represents an array type, returns the Type
+ * object representing the component type of the array; otherwise
+ * returns null. The component type of an array may itself be
+ * an array type.
+ * This is a handle-only method.
+ */
+ public IType getComponentType() {
+ return (IType) fHandle.getComponentType().inState(fState);
+ }
+
+ /**
+ * If this is an array type, answer its element type (the leaf non-array type),
+ * otherwise answer this type.
+ */
+
+ TypeImplSWH getElementType() {
+ return (TypeImplSWH) fHandle.getElementType().inState(fState);
+ }
+
+ /**
+ * Returns the non state specific handle
+ */
+ protected TypeImpl getHandle() {
+ return fHandle;
+ }
+
+ /**
+ * Return the array nesting depth
+ */
+ int getNestingDepth() {
+ return fHandle.fNestingDepth;
+ }
+
+ /**
+ * If this object represents any class other than the class
+ * <code>java.lang.Object</code>, then the object that represents
+ * the direct superclass of that class is returned.
+ * <p>
+ * If this object represents the class <code>java.lang.Object</code>
+ * or this object represents an interface or a primitive type,
+ * <code>null</code> is returned.
+ * If this object represents an array type, then the Type that represents
+ * class <code>java.lang.Object</code> is returned.
+ * <p>
+ * See <em>The Java Language Specification</em> sections 8.1.3 and 20.3.4
+ * for more details.
+ */
+ public IType getSuperclass() throws NotPresentException {
+ return (IType) ((JavaDevelopmentContextImpl) getDevelopmentContext())
+ .getRootClassHandle()
+ .inState(fState);
+ }
+
+ /**
+ * If this Type object represents an array type, returns true,
+ * otherwise returns false.
+ * This is a handle-only method.
+ */
+ public boolean isArray() {
+ return true;
+ }
+
+ /**
+ * If this Type object represents an array type, returns true,
+ * otherwise returns false.
+ * This is a handle-only method.
+ */
+ public boolean isPresent() {
+ return getElementType().isPresent();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BatchImageBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BatchImageBuilder.java
new file mode 100644
index 0000000000..5049eb6e15
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BatchImageBuilder.java
@@ -0,0 +1,121 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.Assert;
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.core.builder.*;
+
+import java.util.*;
+
+/**
+ * The batch image builder - builds a state from scratch.
+ */
+public class BatchImageBuilder
+ extends AbstractImageBuilder
+ implements IImageBuilder, ICompilerRequestor {
+ /**
+ * A flag indicating we are doing a batch build rather than
+ * background lazy builds.
+ */
+ protected boolean fDoingBatchBuild = false;
+ /**
+ * Creates a new batch image builder on the given new state.
+ * The builder will compile everything in the state's project.
+ */
+ public BatchImageBuilder(StateImpl state) {
+ this(state, JavaDevelopmentContextImpl.getDefaultCompilerOptions());
+ }
+
+ /**
+ * Creates a new batch image builder on the given new state.
+ * The batch builder will build all classes within the state's project.
+ * This constructor has been created for testing purposes. This allows
+ * tests to control the compiler options used by the batch build.
+ */
+ protected BatchImageBuilder(StateImpl state, ConfigurableOption[] options) {
+ fDC = (JavaDevelopmentContextImpl) state.getDevelopmentContext();
+ state.setCompilerOptions(options);
+ fCompilerOptions = options;
+ fNewState = state;
+ fWorkQueue = new WorkQueue();
+ }
+
+ /**
+ * Builds the entire image from scratch, based on the provided workspace.
+ */
+ public void build() {
+ fDoingBatchBuild = true;
+ fNotifier = new BuildNotifier(fDC, true);
+ getBuilderEnvironment().setNotifier(fNotifier);
+ fNotifier.begin();
+ try {
+ fNewState.readClassPath();
+ fNotifier.subTask("Scrubbing output folder");
+ fNewState.getBinaryOutput().scrubOutput();
+ fNotifier.updateProgressDelta(0.05f);
+ fNotifier.subTask("Analyzing packages");
+ fNewState.buildInitialPackageMap();
+ fNotifier.updateProgressDelta(0.05f);
+
+ /* Force build all in build context */
+ fNotifier.subTask("Analyzing sources");
+ IPackage[] pkgs = fNewState.getPackageMap().getAllPackagesAsArray();
+ for (int i = 0; i < pkgs.length; ++i) {
+ fNotifier.checkCancel();
+ SourceEntry[] entries = fNewState.getSourceEntries(pkgs[i]);
+ if (entries != null) {
+ for (int j = 0; j < entries.length; ++j) {
+ SourceEntry sEntry = entries[j];
+ if (sEntry.isSource()) {
+ PackageElement element = fNewState.packageElementFromSourceEntry(sEntry);
+ fWorkQueue.add(element);
+ }
+ }
+ }
+ }
+ fNotifier.updateProgressDelta(0.05f);
+ Vector vToCompile = fWorkQueue.getElementsToCompile();
+ if (vToCompile.size() > 0) {
+ fNotifier.setProgressPerCompilationUnit(0.75f / vToCompile.size());
+ compile(vToCompile);
+ }
+ /* Copy resources to binary output */
+ new ProjectResourceCopier(fNewState.getJavaProject(), fDC, fNotifier, 0.10f)
+ .copyAllResourcesOnClasspath();
+
+ fNotifier.done();
+ } finally {
+ cleanUp();
+ }
+ }
+
+ /**
+ * Returns an image delta between old and new states in the image context.
+ * This does not apply to the batch builder.
+ * @see IImageBuilder
+ */
+ public IDelta getImageDelta(IImageContext imageContext) {
+ return null;
+ }
+
+ /**
+ * Builds a given compilation unit.
+ */
+ public void lazyBuild(PackageElement unit) {
+ // String msg = "Attempt to lazy build " + unit.getPackage().getName() + "." + unit.getFileName();
+ // System.err.println(msg + ". " + "Lazy building has been disabled.");
+ Assert.isTrue(false, "Lazy building has been disabled.");
+ }
+
+ /**
+ * Returns a string describe the builder
+ * @see IImageBuilder
+ */
+ public String toString() {
+ return "batch image builder for:\n\tnew state: " + getNewState();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BinaryBrokerOutput.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BinaryBrokerOutput.java
new file mode 100644
index 0000000000..fa0a182acf
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BinaryBrokerOutput.java
@@ -0,0 +1,98 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.builder.BinaryBrokerKey;
+import org.eclipse.jdt.internal.core.builder.IBinaryBroker;
+import org.eclipse.jdt.internal.core.builder.IState;
+import org.eclipse.jdt.internal.core.builder.IType;
+
+import java.util.Hashtable;
+
+/**
+ * A <BinaryBrokerOutput> is a <BinaryOutput> that stores the
+ * binaries using a binary broker.
+ */
+public class BinaryBrokerOutput extends BinaryOutput {
+ IBinaryBroker fBinaryBroker;
+ /**
+ * Creates a new BinaryBrokerOutput for the given binary broker.
+ */
+ public BinaryBrokerOutput(IBinaryBroker broker) {
+ fBinaryBroker = broker;
+ }
+
+ /**
+ * Stores the binary in a manner specific to this BinaryOutput.
+ */
+ protected void basicPutBinary(
+ TypeStructureEntry tsEntry,
+ byte[] binary,
+ int crc) {
+ BinaryBrokerKey key = new BinaryBrokerKey(tsEntry.getType(), crc);
+ fBinaryBroker.putBinary(key, binary);
+ }
+
+ /**
+ * @see BinaryOutput
+ */
+ public void deleteBinary(IType type) {
+ // Cannot delete a binary from a binary broker
+ }
+
+ /**
+ * @see BinaryOutput
+ *
+ * This releases any binaries in the binary broker
+ * which aren't needed for the given states.
+ */
+ public void garbageCollect(IState[] statesInUse) {
+ // estimate size of keysInUse set
+ int size = 0;
+ for (int i = 0; i < statesInUse.length; ++i) {
+ StateImpl state = (StateImpl) statesInUse[i];
+ size += state.getPrincipalStructureTable().size();
+ }
+
+ // collect keysInUse
+ Hashtable keysInUse = new Hashtable(size * 2 + 1);
+ for (int i = 0; i < statesInUse.length; ++i) {
+ StateImpl state = (StateImpl) statesInUse[i];
+ state.collectBinaryBrokerKeys(keysInUse);
+ }
+
+ // tell the broker to GC
+ fBinaryBroker.garbageCollect(keysInUse);
+ }
+
+ /**
+ * @see BinaryOutput
+ */
+ public byte[] getBinary(TypeStructureEntry tsEntry, IType type) {
+ /* get cached CRC value */
+ int crc = tsEntry.getCRC32();
+ if (crc == 0) {
+ // Never had the binary.
+ return null;
+ }
+ BinaryBrokerKey key = new BinaryBrokerKey(type, crc);
+ return fBinaryBroker.getBinary(key);
+ }
+
+ /**
+ * Returns the binary broker for this binary broker output.
+ */
+ public IBinaryBroker getBinaryBroker() {
+ return fBinaryBroker;
+ }
+
+ /**
+ * @see BinaryOutput
+ */
+ public void scrubOutput() {
+ // Cannot delete anything from a binary broker
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BinaryOutput.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BinaryOutput.java
new file mode 100644
index 0000000000..4f5e39e3eb
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BinaryOutput.java
@@ -0,0 +1,70 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.builder.IState;
+import org.eclipse.jdt.internal.core.builder.IType;
+
+/**
+ * A <BinaryOutput> is the place where binaries coming from the image
+ * builder are stored.
+ */
+public abstract class BinaryOutput {
+
+ private static final boolean COMPUTE_CRC = false; // disabled since unused
+ /**
+ * Stores the binary in a manner specific to this BinaryOutput.
+ */
+ abstract protected void basicPutBinary(
+ TypeStructureEntry tsEntry,
+ byte[] binary,
+ int crc);
+ /**
+ * Computes a 32-bit CRC on the given binary.
+ */
+ int crc32(byte[] binary) {
+ java.util.zip.CRC32 crc = new java.util.zip.CRC32();
+ crc.update(binary);
+ return (int) crc.getValue();
+ }
+
+ /**
+ * Deletes the binary previously produced for a type.
+ */
+ public abstract void deleteBinary(IType type);
+ /**
+ * Garbage collect any resources maintained by this binary
+ * output which are no longer needed, given the states which
+ * are still in use.
+ */
+ public abstract void garbageCollect(IState[] statesInUse);
+ /**
+ * Returns the binary previously produced for a type.
+ * Returns null if the binary could not be found.
+ */
+ public abstract byte[] getBinary(TypeStructureEntry tsEntry, IType type);
+ /**
+ * Stores the binary produced by compiling a type.
+ */
+ public void putBinary(TypeStructureEntry tsEntry, byte[] binary) {
+ /* store crc in type structure entry */
+ int crc;
+
+ if (COMPUTE_CRC) {
+ crc = crc32(binary);
+ tsEntry.setCRC32(crc);
+ } else {
+ crc = 0;
+ }
+
+ /* store binary */
+ basicPutBinary(tsEntry, binary, crc);
+ }
+
+ /**
+ * Deletes everything in this binary output.
+ */
+ public abstract void scrubOutput();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BinaryStructure.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BinaryStructure.java
new file mode 100644
index 0000000000..c3533da017
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BinaryStructure.java
@@ -0,0 +1,411 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.core.builder.*;
+
+import org.eclipse.jdt.internal.compiler.util.*;
+import org.eclipse.jdt.internal.core.Util;
+
+/**
+ * Utility class for interpreting the contents of IBinaryType objects.
+ */
+public abstract class BinaryStructure {
+ /**
+ * Should not instantiate.
+ */
+ private BinaryStructure() {
+ }
+
+ protected static boolean compare(IBinaryField[] listA, IBinaryField[] listB) {
+ if (listA == listB)
+ return true;
+ if (listA == null || listB == null)
+ return false;
+ if (listA.length != listB.length)
+ return false;
+ Util.Comparer comparer = new Util.Comparer() {
+ public int compare(Object a, Object b) {
+ IBinaryField fa = (IBinaryField) a;
+ IBinaryField fb = (IBinaryField) b;
+ int code = Util.compare(fa.getName(), fb.getName());
+ if (code != 0)
+ return code;
+ return Util.compare(fa.getTypeName(), fb.getTypeName());
+ }
+ };
+ Object[] sortedA = Util.sortCopy(listA, comparer);
+ Object[] sortedB = Util.sortCopy(listB, comparer);
+ for (int i = 0; i < listA.length; ++i) {
+ if (!compare((IBinaryField) sortedA[i], (IBinaryField) sortedB[i]))
+ return false;
+ }
+ return true;
+ }
+
+ protected static boolean compare(
+ IBinaryMethod[] listA,
+ IBinaryMethod[] listB) {
+ if (listA == listB)
+ return true;
+ if (listA == null || listB == null)
+ return false;
+ if (listA.length != listB.length)
+ return false;
+ Util.Comparer comparer = new Util.Comparer() {
+ public int compare(Object a, Object b) {
+ IBinaryMethod ma = (IBinaryMethod) a;
+ IBinaryMethod mb = (IBinaryMethod) b;
+ int code = Util.compare(ma.getSelector(), mb.getSelector());
+ if (code != 0)
+ return code;
+ return Util.compare(ma.getMethodDescriptor(), mb.getMethodDescriptor());
+ }
+ };
+ Object[] sortedA = Util.sortCopy(listA, comparer);
+ Object[] sortedB = Util.sortCopy(listB, comparer);
+ for (int i = 0; i < listA.length; ++i) {
+ if (!compare((IBinaryMethod) sortedA[i], (IBinaryMethod) sortedB[i]))
+ return false;
+ }
+ return true;
+ }
+
+ protected static boolean compare(
+ IBinaryNestedType[] listA,
+ IBinaryNestedType[] listB) {
+ if (listA == listB)
+ return true;
+ if (listA == null || listB == null)
+ return false;
+ if (listA.length != listB.length)
+ return false;
+ for (int i = 0; i < listA.length; ++i) {
+ if (!compare((IBinaryNestedType) listA[i], (IBinaryNestedType) listB[i]))
+ return false;
+ }
+ return true;
+ }
+
+ public static boolean compare(IBinaryField a, IBinaryField b) {
+ if (a == b)
+ return true;
+ if (!CharOperation.equals(a.getName(), b.getName()))
+ return false;
+ if (!CharOperation.equals(a.getTypeName(), b.getTypeName()))
+ return false;
+ if (a.getModifiers() != b.getModifiers())
+ return false;
+ if (!Util.equalOrNull(a.getConstant(), b.getConstant()))
+ return false;
+ return true;
+ }
+
+ public static boolean compare(IBinaryMethod a, IBinaryMethod b) {
+ if (a == b)
+ return true;
+ if (!CharOperation.equals(a.getSelector(), b.getSelector()))
+ return false;
+ if (!CharOperation.equals(a.getMethodDescriptor(), b.getMethodDescriptor()))
+ return false;
+ if (a.getModifiers() != b.getModifiers())
+ return false;
+ if (!CharOperation
+ .equals(a.getExceptionTypeNames(), b.getExceptionTypeNames()))
+ return false;
+ return true;
+ }
+
+ protected static boolean compare(IBinaryNestedType a, IBinaryNestedType b) {
+ if (a == b)
+ return true;
+ if (!CharOperation.equals(a.getName(), b.getName()))
+ return false;
+ if (a.getModifiers() != b.getModifiers())
+ return false;
+ if (!CharOperation.equals(a.getEnclosingTypeName(), b.getEnclosingTypeName()))
+ return false;
+ return true;
+ }
+
+ public static boolean compare(IBinaryType a, IBinaryType b) {
+ if (a == b)
+ return true;
+ if (!CharOperation.equals(a.getName(), b.getName()))
+ return false;
+ if (a.getModifiers() != b.getModifiers())
+ return false;
+ if (!CharOperation.equals(a.getSuperclassName(), b.getSuperclassName()))
+ return false;
+ if (!CharOperation.equals(a.getInterfaceNames(), b.getInterfaceNames()))
+ return false;
+ if (!compare(a.getFields(), b.getFields()))
+ return false;
+ if (!compare(a.getMethods(), b.getMethods()))
+ return false;
+ if (!compare(a.getMemberTypes(), b.getMemberTypes()))
+ return false;
+ return true;
+ }
+
+ /**
+ * Converts from the compiler's name representation to ours.
+ * i.e., converts from char[] some/pkg/Type$Subtype to
+ * String some.pkg.Type$Subtype
+ */
+ public static String convertTypeName(char[] vmName) {
+ char[] builderName = new char[vmName.length];
+ for (int i = vmName.length; --i >= 0;) {
+ if (vmName[i] == '/') {
+ builderName[i] = '.';
+ } else {
+ builderName[i] = vmName[i];
+ }
+ }
+ return new String(builderName);
+ }
+
+ /**
+ * Returns the constructor of the type, corresponding to the given constructor handle signature,
+ * or null if there is none which matches.
+ */
+ public static IBinaryMethod getConstructor(
+ IBinaryType type,
+ String handleSig) {
+ IBinaryMethod[] methods = type.getMethods();
+ if (methods != null) {
+ char[] sig = handleSig.replace('.', '/').toCharArray();
+ for (int i = 0; i < methods.length; i++) {
+ IBinaryMethod m = (IBinaryMethod) methods[i];
+ if (m.isConstructor()
+ && CharOperation.startsWith(m.getMethodDescriptor(), sig))
+ return m;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the non-state-specific constructor handle for an IBinaryMethod, given the containing
+ * non-state-specific type handle.
+ */
+ public static IConstructor getConstructorHandle(
+ IBinaryMethod method,
+ ClassOrInterfaceHandleImpl type) {
+ char[] sig = method.getMethodDescriptor();
+ sig = CharOperation.subarray(sig, 0, sig.length - 1); // Trim off V trailer
+ String convertedSig = new String(sig).replace('/', '.');
+ return new ConstructorImpl(type, convertedSig);
+ }
+
+ /**
+ * Returns the declared name (name as it appears in the source) for the given type.
+ */
+ public static char[] getDeclaredName(IBinaryNestedType type) {
+ char[] name = type.getName();
+ int lastDot = CharOperation.lastIndexOf('/', name);
+ if (lastDot != -1) {
+ name = CharOperation.subarray(name, lastDot + 1, name.length);
+ }
+ int lastDollar = CharOperation.lastIndexOf('$', name);
+ if (lastDollar != -1) {
+ name = CharOperation.subarray(name, lastDollar + 1, name.length);
+ }
+ return name;
+ }
+
+ /**
+ * Returns the declared name (name as it appears in the source) for the given type.
+ */
+ public static char[] getDeclaredName(IBinaryType type) {
+ char[] name = type.getName();
+ int lastDot = CharOperation.lastIndexOf('/', name);
+ if (lastDot != -1) {
+ name = CharOperation.subarray(name, lastDot + 1, name.length);
+ }
+ int lastDollar = CharOperation.lastIndexOf('$', name);
+ if (lastDollar != -1) {
+ name = CharOperation.subarray(name, lastDollar + 1, name.length);
+ }
+ return name;
+ }
+
+ /**
+ * Returns the name of the enclosing type, or null.
+ */
+ public static char[] getEnclosingTypeName(IBinaryType type) {
+ IBinaryNestedType t = getInnerClassEntry(type);
+ return t == null ? null : t.getEnclosingTypeName();
+ }
+
+ /**
+ * Returns the field of the type, with the given name,
+ * or null if there is none which matches.
+ */
+ public static IBinaryField getField(IBinaryType type, String name) {
+ IBinaryField[] fields = type.getFields();
+ if (fields != null) {
+ char[] nameChars = name.toCharArray();
+ for (int i = 0; i < fields.length; i++) {
+ IBinaryField f = (IBinaryField) fields[i];
+ if (CharOperation.equals(f.getName(), nameChars))
+ return f;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the non-state-specific field handle for an IBinaryField, given the containing
+ * non-state-specific type handle.
+ */
+ public static IField getFieldHandle(
+ IBinaryField field,
+ ClassOrInterfaceHandleImpl type) {
+ return type.getFieldHandle(new String(field.getName()));
+ }
+
+ /**
+ * Returns the fully qualified name of the given binary type
+ */
+ public static String getFullyQualifiedName(IBinaryType type) {
+ return convertTypeName(type.getName());
+ }
+
+ /**
+ * Returns the inner class entry representing this type, or null if not applicable.
+ */
+ protected static IBinaryNestedType getInnerClassEntry(IBinaryType type) {
+ IBinaryNestedType[] inners = type.getMemberTypes();
+ if (inners != null) {
+ char[] name = type.getName();
+ for (int i = 0, max = inners.length; i < max; ++i) {
+ IBinaryNestedType t = (IBinaryNestedType) inners[i];
+ if (CharOperation.equals(t.getName(), name)) {
+ return t;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the names of inner types in the inner class entries which have this type
+ * as their outer type. May include both local (pre JDK1.2) and member types.
+ */
+ public static char[][] getInnerTypes(IBinaryType type) {
+ IBinaryNestedType[] nested = type.getMemberTypes();
+ if (nested == null) {
+ return new char[0][];
+ } else {
+ char[][] result = new char[nested.length][];
+ int count = 0;
+ for (int i = 0; i < nested.length; ++i) {
+ IBinaryNestedType t = nested[i];
+ if (CharOperation.equals(t.getEnclosingTypeName(), type.getName())) {
+ result[count++] = t.getName();
+ }
+ }
+ if (count < result.length) {
+ System.arraycopy(result, 0, result = new char[count][], 0, count);
+ }
+ return result;
+ }
+ }
+
+ /**
+ * Returns the method of the type, corresponding to the given method handle signature,
+ * or null if there is none which matches.
+ */
+ public static IBinaryMethod getMethod(IBinaryType type, String handleSig) {
+ IBinaryMethod[] methods = type.getMethods();
+ if (methods != null) {
+ char[] sig = handleSig.replace('.', '/').toCharArray();
+ int paren = CharOperation.indexOf('(', sig);
+ if (paren == -1)
+ return null;
+ char[] sel = CharOperation.subarray(sig, 0, paren);
+ char[] desc = CharOperation.subarray(sig, paren, sig.length);
+ for (int i = 0; i < methods.length; i++) {
+ IBinaryMethod m = (IBinaryMethod) methods[i];
+ if (!m.isConstructor()
+ && CharOperation.equals(m.getSelector(), sel)
+ && CharOperation.startsWith(m.getMethodDescriptor(), desc))
+ return m;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the non-state-specific method handle for an IBinaryMethod, given the containing
+ * non-state-specific type handle.
+ */
+ public static IMethod getMethodHandle(
+ IBinaryMethod method,
+ ClassOrInterfaceHandleImpl type) {
+
+ /**
+ * Note that DC method signatures have the following grammar rule:
+ * - MethodSignature: selector ( ParameterDescriptor* )
+ * Whereas the VM signature format in IBinaryMethod is:
+ * - MethodDescriptor: ( ParameterDescriptor* ) ReturnDescriptor
+ */
+
+ char[] sig = method.getMethodDescriptor();
+ int i = CharOperation.lastIndexOf(')', sig);
+ if (i != -1)
+ sig = CharOperation.subarray(sig, 0, i + 1); // Trim return type
+
+ sig = CharOperation.concat(method.getSelector(), sig);
+ String convertedSig = new String(sig).replace('/', '.');
+ return new MethodImpl(type, convertedSig);
+ }
+
+ /**
+ * Returns a type handle for the given type name. The name
+ * must be in IBinaryType format.
+ * The TypeStructureEntry is passed in case the default package needs to be determined
+ * relative to the referring type.
+ */
+ public static IType getType(
+ StateImpl state,
+ TypeStructureEntry referringType,
+ char[] name) {
+ /* null is a valid type name */
+ if (name == null) {
+ return null;
+ }
+ return state.typeNameToHandle(
+ referringType,
+ new String(name).replace('/', '.'));
+ }
+
+ /**
+ * Returns whether the type is an anonymous type (local, without a name).
+ */
+ public static boolean isAnonymous(IBinaryType type) {
+ /* TBD: Don't have access to declared name, but assume it's anonymous if it's local. */
+ return isLocal(type);
+ }
+
+ /**
+ * Returns whether the type is a local type (not a top-level or member type).
+ */
+ public static boolean isLocal(IBinaryType type) {
+ /* As of JDK 1.2, the inner class entry for local types have null for the enclosing type. */
+ IBinaryNestedType t = getInnerClassEntry(type);
+ return t != null && t.getEnclosingTypeName() == null;
+ }
+
+ /**
+ * Returns whether the type is a package member (not a nested type).
+ */
+ public static boolean isPackageMember(IBinaryType type) {
+ return getInnerClassEntry(type) == null;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BuildMonitorImpl.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BuildMonitorImpl.java
new file mode 100644
index 0000000000..54c10fef28
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BuildMonitorImpl.java
@@ -0,0 +1,57 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.builder.IBuildMonitor;
+
+import java.util.Vector;
+
+/**
+ * The build monitor tracks what compilation units have been compiled during a
+ * given build. This allows test suites to evaluate the efficiency of incremental
+ * compilation.
+ */
+public class BuildMonitorImpl implements IBuildMonitor {
+ protected Vector fClasses = new Vector();
+
+ /**
+ * Creates a new BuildMonitorImpl.
+ */
+ public BuildMonitorImpl() {
+ }
+
+ /**
+ * Signals that a new build has begun.
+ */
+ public void beginBuild(String message) {
+ // System.out.println(message);
+ fClasses.removeAllElements();
+ }
+
+ /**
+ * Signals that a compilation unit with the given name has been compiled
+ */
+ public void compiled(String jcu) {
+ // System.out.println("<BM>Compiled: " + jcu);
+ fClasses.addElement(jcu);
+ }
+
+ /**
+ * Signals that a new build has begun.
+ */
+ public void endBuild(String message) {
+ // System.out.println(message);
+ }
+
+ /**
+ * Returns the compiled classes
+ */
+ public String[] getCompiledClasses() {
+ String[] results = new String[fClasses.size()];
+ fClasses.copyInto(results);
+ return results;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BuildNotifier.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BuildNotifier.java
new file mode 100644
index 0000000000..4e020def42
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BuildNotifier.java
@@ -0,0 +1,302 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.internal.core.builder.*;
+import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
+
+import java.text.NumberFormat;
+import java.util.*;
+
+/**
+ * A utility for notifying clients of changes during a build.
+ * This includes, progress, build events, etc.
+ */
+public class BuildNotifier {
+ protected JavaDevelopmentContextImpl fDC;
+ protected boolean fIsBatch;
+ protected IBuildMonitor fBuildMonitor;
+ protected IProgressMonitor fProgress;
+ protected boolean fCancelling = false;
+ protected float fPercentComplete;
+ protected float fProgressPerCompilationUnit;
+ protected Vector fBuildListeners;
+ protected int fNewErrorCount = 0;
+ protected int fFixedErrorCount = 0;
+ protected int fNewWarningCount = 0;
+ protected int fFixedWarningCount = 0;
+ protected int fWorkDone = 0;
+ protected int fTotalWork;
+
+ public static boolean DEBUG = false;
+
+ protected String previousSubtask;
+ public BuildNotifier(JavaDevelopmentContextImpl dc, boolean isBatch) {
+ fDC = dc;
+ fIsBatch = isBatch;
+ fProgress = dc.getProgressMonitor();
+ fBuildMonitor = dc.getBuildMonitor();
+ fBuildListeners = dc.getBuildListeners();
+ fTotalWork = 1000000;
+ }
+
+ public void begin() {
+ if (fBuildMonitor != null) {
+ fBuildMonitor.beginBuild(
+ fIsBatch ? "Begin batch build" : "Begin incremental build");
+ }
+ if (fProgress != null) {
+ fProgress.beginTask("", fTotalWork);
+ }
+ this.previousSubtask = null;
+ }
+
+ /**
+ * Check whether the build has been canceled.
+ */
+ public void checkCancel() {
+ if (fProgress != null && fProgress.isCanceled()) {
+ throw new OperationCanceledException();
+ }
+ }
+
+ /**
+ * Check whether the build has been canceled.
+ * Must use this call instead of checkCancel() when within the compiler.
+ */
+ public void checkCancelWithinCompiler() {
+ if (fProgress != null && fProgress.isCanceled() && !fCancelling) {
+ // Once the compiler has been canceled, don't check again.
+ setCancelling(true);
+ // Only AbortCompilation can stop the compiler cleanly.
+ // We check cancelation again following the call to compile.
+ throw new AbortCompilation(true, null);
+ }
+ }
+
+ /**
+ * Notification while within a compile that a unit has finished being compiled.
+ */
+ public void compiled(CompilerCompilationUnit unit) {
+ compiling(unit);
+ }
+
+ /**
+ * Notification while within a compile that a unit is starting to be compiled.
+ */
+ public void compiling(CompilerCompilationUnit unit) {
+ String message = new String(unit.getFileName());
+ message = message.replace('\\', '/');
+ // Trim off project names
+ int start = message.indexOf('/', 1);
+ int end = message.lastIndexOf('/');
+ if (end <= start) {
+ message = "Compiling " + message.substring(start + 1);
+ } else {
+ message = "Compiling content of " + message.substring(start + 1, end);
+ }
+ subTask(message);
+ updateProgressDelta(fProgressPerCompilationUnit / 2);
+ checkCancelWithinCompiler();
+ }
+
+ public void done() {
+ updateProgress(1.0f);
+ subTask("Build done");
+ if (fProgress != null) {
+ fProgress.done();
+ }
+ if (fBuildMonitor != null) {
+ fBuildMonitor.endBuild(
+ fIsBatch ? "->End batch build" : "->End incremental build");
+ }
+ this.previousSubtask = null;
+ }
+
+ /**
+ * Notify listeners that elements have changed.
+ */
+ public void notifyElementsChanged(
+ ConvertedCompilationResult[] results,
+ StateImpl oldState,
+ StateImpl newState) {
+ // if (fBuildListeners.size() == 0) {
+ // return;
+ // }
+ for (int i = 0; i < results.length; ++i) {
+ ConvertedCompilationResult result = results[i];
+ PackageElement element = result.getPackageElement();
+
+ /* notify the build monitor */
+ if (fBuildMonitor != null) {
+ String typeName = element.getFileName();
+ int lastDot = typeName.lastIndexOf('.');
+ typeName = typeName.substring(0, lastDot);
+ fBuildMonitor.compiled(element.getPackage().getName() + '.' + typeName);
+ }
+ Vector oldProblems = null;
+ Vector newProblems = null;
+ if (oldState != null) {
+ SourceEntry oldEntry = oldState.getSourceEntry(element);
+ if (oldEntry != null) {
+ oldProblems = oldState.getProblemReporter().getProblemVector(oldEntry);
+ }
+ }
+ SourceEntry newEntry = newState.getSourceEntry(element);
+ if (newEntry != null) {
+ newProblems = newState.getProblemReporter().getProblemVector(newEntry);
+ }
+ updateProblemCounts(oldProblems, newProblems);
+ ISourceFragment fragment =
+ (newEntry == null ? null : new SourceFragmentImpl(newEntry));
+ BuildEvent event =
+ new BuildEvent(
+ fragment,
+ fNewErrorCount,
+ fFixedErrorCount,
+ fNewWarningCount,
+ fFixedWarningCount);
+ for (int j = 0, size = fBuildListeners.size(); j < size; ++j) {
+ ((IBuildListener) fBuildListeners.elementAt(j)).buildUpdate(event);
+ }
+ }
+ }
+
+ /**
+ * Returns a string describing the problems.
+ */
+ protected String problemsMessage() {
+ int numNew = fNewErrorCount + fNewWarningCount;
+ int numFixed = fFixedErrorCount + fFixedWarningCount;
+ if (numNew == 0 && numFixed == 0) {
+ return "";
+ }
+ if (numFixed == 0) {
+ return "(" + numNew + " " + (numNew == 1 ? "problem" : "problems") + " found)";
+ } else
+ if (numNew == 0) {
+ return "("
+ + numFixed
+ + " "
+ + (numFixed == 1 ? "problem" : "problems")
+ + " fixed)";
+ } else {
+ return "("
+ + numFixed
+ + " "
+ + (numFixed == 1 ? "problem" : "problems")
+ + " fixed, "
+ + numNew
+ + " "
+ + (numNew == 1 ? "problem" : "problems")
+ + " found)";
+ }
+ }
+
+ /**
+ * Sets the cancelling flag, which indicates we are in the middle
+ * of being cancelled. Certain places (those callable indirectly from the compiler)
+ * should not check cancel again while this is true, to avoid OperationCanceledException
+ * being thrown at an inopportune time.
+ */
+ public void setCancelling(boolean cancelling) {
+ fCancelling = cancelling;
+ }
+
+ /**
+ * Sets the amount of progress to report for compiling each compilation unit.
+ */
+ public void setProgressPerCompilationUnit(float progress) {
+ fProgressPerCompilationUnit = progress;
+ }
+
+ public void subTask(String message) {
+ String pm = problemsMessage();
+ String msg = pm.length() == 0 ? message : pm + " " + message;
+
+ if (msg.equals(this.previousSubtask))
+ return; // avoid refreshing with same one
+ if (DEBUG)
+ System.out.println(msg);
+ if (fProgress != null)
+ fProgress.subTask(msg);
+
+ this.previousSubtask = msg;
+ }
+
+ /**
+ * Update the problem counts given the old and new problems,
+ * either of which may be null.
+ */
+ protected void updateProblemCounts(Vector oldProblems, Vector newProblems) {
+ if (oldProblems != null) {
+ for (int i = 0, oldSize = oldProblems.size(); i < oldSize; ++i) {
+ ProblemDetailImpl oldProblem = (ProblemDetailImpl) oldProblems.elementAt(i);
+ ProblemDetailImpl newProblem = null;
+ if (newProblems != null) {
+ for (int j = 0, newSize = newProblems.size(); j < newSize; ++j) {
+ ProblemDetailImpl pb = (ProblemDetailImpl) newProblems.elementAt(j);
+ if (oldProblem.equals(pb, true)) {
+ newProblem = pb;
+ break;
+ }
+ }
+ }
+ if (newProblem == null) {
+ if ((oldProblem.getSeverity() & IProblemDetail.S_ERROR) != 0) {
+ fFixedErrorCount++;
+ } else {
+ fFixedWarningCount++;
+ }
+ }
+ }
+ }
+ if (newProblems != null) {
+ for (int i = 0, newSize = newProblems.size(); i < newSize; ++i) {
+ ProblemDetailImpl newProblem = (ProblemDetailImpl) newProblems.elementAt(i);
+ ProblemDetailImpl oldProblem = null;
+ if (oldProblems != null) {
+ for (int j = 0, oldSize = oldProblems.size(); j < oldSize; ++j) {
+ ProblemDetailImpl pb = (ProblemDetailImpl) oldProblems.elementAt(j);
+ if (newProblem.equals(pb, true)) {
+ oldProblem = pb;
+ break;
+ }
+ }
+ }
+ if (oldProblem == null) {
+ if ((newProblem.getSeverity() & IProblemDetail.S_ERROR) != 0) {
+ fNewErrorCount++;
+ } else {
+ fNewWarningCount++;
+ }
+ }
+ }
+ }
+ }
+
+ public void updateProgress(float percentComplete) {
+ if (percentComplete > fPercentComplete) {
+ fPercentComplete = Math.min(percentComplete, 1.0f);
+ int work = Math.round(fPercentComplete * fTotalWork);
+ if (work > fWorkDone) {
+ if (fProgress != null) {
+ fProgress.worked(work - fWorkDone);
+ }
+ if (DEBUG) {
+ System.out.println(NumberFormat.getPercentInstance().format(fPercentComplete));
+ }
+ fWorkDone = work;
+ }
+ }
+ }
+
+ public void updateProgressDelta(float percentWorked) {
+ updateProgress(fPercentComplete + percentWorked);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BuilderEnvironment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BuilderEnvironment.java
new file mode 100644
index 0000000000..26ecd71609
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BuilderEnvironment.java
@@ -0,0 +1,199 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.jdt.internal.core.builder.*;
+import java.io.IOException;
+import java.util.*;
+
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.internal.core.Util;
+
+/**
+ * This is the main interface between the image builder and the compiler.
+ */
+public class BuilderEnvironment implements INameEnvironment {
+ protected AbstractImageBuilder fBuilder;
+ protected IDevelopmentContext fDevelopmentContext;
+ protected StateImpl fState;
+ protected Hashtable fPackages;
+ protected IPackage fDefaultPackage = null;
+ protected BuildNotifier fNotifier = null;
+ public BuilderEnvironment(AbstractImageBuilder builder) {
+ fBuilder = builder;
+ fState = (StateImpl) fBuilder.getNewState();
+ fDevelopmentContext = fState.getDevelopmentContext();
+ }
+
+ protected void checkCancel() {
+ if (fNotifier != null) {
+ fNotifier.checkCancelWithinCompiler();
+ }
+ }
+
+ /**
+ * Notifies interested listeners that a compilation unit is
+ * going to be compiled.
+ */
+ protected void compiling(CompilerCompilationUnit unit) {
+ fBuilder.compiling(unit);
+ }
+
+ /**
+ * Create a table keyed by package name, including all package prefixes.
+ * If it's a real package, it maps to the handle, otherwise to null.
+ */
+ void createPackageTable() {
+ Hashtable table = new Hashtable();
+ if (fDefaultPackage != null) {
+ table.put(IPackageFragment.DEFAULT_PACKAGE_NAME, fDefaultPackage);
+ }
+ PackageMap packageMap = fState.getPackageMap();
+ for (Enumeration e = packageMap.getAllPackages(); e.hasMoreElements();) {
+ IPackage pkg = (IPackage) e.nextElement();
+ if (!pkg.isUnnamed()) {
+ String name = pkg.getName();
+ table.put(name, pkg);
+ int i = -1;
+ while ((i = name.indexOf('.', i + 1)) != -1) {
+ String prefix = name.substring(0, i);
+ if (!table.containsKey(prefix)) {
+ // don't overwrite if there's a real package with the same prefix
+ table.put(prefix, prefix);
+ }
+ }
+ }
+ }
+ fPackages = table;
+ }
+
+ /**
+ * @see IBuilderEnvironment
+ */
+ protected NameEnvironmentAnswer find(
+ String packageName,
+ String simpleTypeName) {
+ checkCancel();
+ IPackage pkg = getPackageHandle(packageName);
+ if (pkg == null) {
+ return null;
+ }
+ IType type = pkg.getClassHandle(simpleTypeName);
+ SourceEntry sEntry = null;
+ TypeStructureEntry tsEntry = fState.getTypeStructureEntry(type, false);
+ boolean isInvalid;
+ if (tsEntry != null) {
+ sEntry = tsEntry.getSourceEntry();
+ isInvalid = fBuilder.isInvalid(sEntry);
+ if (!isInvalid) {
+ /* don't want to invoke a lazy build here */
+ IBinaryType binaryType = fState.getBinaryTypeOrNull(tsEntry);
+ if (binaryType != null) {
+ return new NameEnvironmentAnswer(binaryType);
+ }
+ }
+ } else {
+ sEntry = fState.getSourceEntry(type);
+ if (sEntry == null) {
+ return null;
+ }
+ isInvalid = fBuilder.isInvalid(sEntry);
+ }
+ if (sEntry != null && sEntry.isSource()) {
+ // only accept if really a compilation unit, not from binary
+ // If the type was unknown (as opposed to invalid), check to see if there are problems.
+ // If there was no principal structure and there are problems,
+ // then the compilation unit has tried to be compiled and it has failed,
+ // so don't try again.
+ // If the type was known, but needs to be recompiled because its principal structure was missing,
+ // then recompile it regardless of whether it has problems.
+ if (!isInvalid
+ && (tsEntry == null && fState.getProblemReporter().hasProblems(sEntry))) {
+ return null;
+ }
+ CompilerCompilationUnit unit =
+ new CompilerCompilationUnit(fState, sEntry, fNotifier);
+ compiling(unit);
+ return new NameEnvironmentAnswer(unit);
+ }
+ return null;
+ }
+
+ /**
+ * @see INameEnvironment
+ */
+ public NameEnvironmentAnswer findType(char[][] compoundTypeName) {
+ int last = compoundTypeName.length - 1;
+ char[][] pkgName = new char[last][];
+ System.arraycopy(compoundTypeName, 0, pkgName, 0, last);
+ return findType(compoundTypeName[last], pkgName);
+ }
+
+ /**
+ * @see INameEnvironment
+ */
+ public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) {
+ return find(Util.toString(packageName), Util.toString(typeName));
+ }
+
+ /**
+ * Return the default package or null.
+ */
+ public IPackage getDefaultPackage() {
+ return fDefaultPackage;
+ }
+
+ /**
+ * Internal - Returns the package handle corresponding to the given package name.
+ */
+ IPackage getPackageHandle(String packageName) {
+
+ if (fPackages == null) {
+ createPackageTable();
+ }
+ Object o = fPackages.get(packageName);
+ if (o == null
+ || !(o instanceof IPackage)) { // value is a string if it's only a package prefix
+ return null;
+ }
+ return (IPackage) o;
+ }
+
+ /**
+ * @see INameEnvironment
+ */
+ public boolean isPackage(char[][] parentPackageName, char[] packageName) {
+ checkCancel();
+ if (fPackages == null) {
+ createPackageTable();
+ }
+ String fullName = Util.toString(parentPackageName, packageName);
+ return fPackages.containsKey(fullName);
+ }
+
+ /**
+ * Set the default package or null. The compiler knows about at most one default package.
+ */
+ public void setDefaultPackage(IPackage pkg) {
+ if (!Util.equalOrNull(fDefaultPackage, pkg)) {
+ fPackages = null; // clear the table; it's reinitialized lazily
+ }
+ if (pkg.isStateSpecific()) {
+ fDefaultPackage = (IPackage) pkg.nonStateSpecific();
+ } else {
+ fDefaultPackage = pkg;
+ }
+ }
+
+ /**
+ * Set the notifier.
+ */
+ public void setNotifier(BuildNotifier notifier) {
+ fNotifier = notifier;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BuilderType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BuilderType.java
new file mode 100644
index 0000000000..881c46f4c4
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/BuilderType.java
@@ -0,0 +1,221 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.IBinaryType;
+import org.eclipse.jdt.internal.core.builder.IImage;
+import org.eclipse.jdt.internal.core.builder.IPackage;
+import org.eclipse.jdt.internal.core.builder.IType;
+
+import org.eclipse.jdt.internal.compiler.util.*;
+
+/**
+ * This class represents a type that is being examined by
+ * the incremental image builder. There is a one-one correspondence
+ * between builder types and class files. Each builder type
+ * has a structure in both the old and new states.
+ */
+public abstract class BuilderType {
+ /**
+ * The builder associated with this builder type
+ */
+ protected IncrementalImageBuilder fBuilder;
+
+ /**
+ * For computing hierarchy changes
+ */
+ protected boolean fComputedHierarchy;
+ protected boolean fHasHierarchyChange;
+ /**
+ * Creates a new BuilderType.
+ */
+ public BuilderType(
+ IncrementalImageBuilder builder,
+ boolean hasComputedHierarchy,
+ boolean hasHierarchyChange) {
+ fBuilder = builder;
+ fComputedHierarchy = hasComputedHierarchy;
+ fHasHierarchyChange = hasHierarchyChange;
+ }
+
+ /**
+ * Computes the indictments for this type and adds them to the
+ * given indictment set.
+ */
+ public abstract void computeIndictments(IndictmentSet indictments);
+ /**
+ * Returns true if there is a change to the supertype hierarchy of this type.
+ * Needs to check the whole hierarchy because changes from higher up are -not-
+ * automatically propagated through the dependency graph.
+ */
+ protected boolean detectHierarchyChange() {
+ /* If we've already done the work, return the result */
+ if (fComputedHierarchy) {
+ return fHasHierarchyChange;
+ }
+ fComputedHierarchy = true;
+ if (getNewTypeStructureEntry() == null) {
+ return fHasHierarchyChange = true;
+ }
+ IBinaryType oldType = getOldBinaryType();
+ if (oldType == null) {
+ return fHasHierarchyChange = true;
+ }
+ IBinaryType newType = getNewBinaryType();
+
+ /* check superclasses */
+ char[] oldSuper = oldType.getSuperclassName();
+ char[] newSuper = newType.getSuperclassName();
+ if (oldSuper == null ^ newSuper == null) {
+ return fHasHierarchyChange = true;
+ }
+ if (oldSuper != null && newSuper != null) {
+ if (!CharOperation.equals(oldSuper, newSuper)) {
+ return fHasHierarchyChange = true;
+ }
+
+ /* recurse on superclass */
+ BuilderType superBuilderType =
+ fBuilder.getBuilderType(
+ BinaryStructure.getType(getNewState(), getNewTypeStructureEntry(), oldSuper));
+ if (superBuilderType.detectHierarchyChange()) {
+ return fHasHierarchyChange = true;
+ }
+ }
+
+ /* check interfaces */
+ char[][] oldInterfaces = oldType.getInterfaceNames();
+ char[][] newInterfaces = newType.getInterfaceNames();
+ if (!CharOperation.equals(oldInterfaces, newInterfaces)) {
+ return fHasHierarchyChange = true;
+ }
+
+ /* recurse on interfaces */
+ if (oldInterfaces != null) {
+ for (int i = 0; i < oldInterfaces.length; i++) {
+ BuilderType superBuilderType =
+ fBuilder.getBuilderType(
+ BinaryStructure.getType(
+ getNewState(),
+ getNewTypeStructureEntry(),
+ oldInterfaces[i]));
+ if (superBuilderType.detectHierarchyChange()) {
+ return fHasHierarchyChange = true;
+ }
+ }
+ }
+ return fHasHierarchyChange = false;
+ }
+
+ /**
+ * Returns the binary type in the new state
+ */
+ public IBinaryType getNewBinaryType() {
+ return getNewState().getBinaryType(getNewTypeStructureEntry());
+ }
+
+ /**
+ * Returns the new state
+ */
+ protected StateImpl getNewState() {
+ return (StateImpl) fBuilder.getNewState();
+ }
+
+ /**
+ * Returns the tsEntry in the new state
+ */
+ public abstract TypeStructureEntry getNewTypeStructureEntry();
+ /**
+ * Returns the binary type in the old state
+ */
+ public IBinaryType getOldBinaryType() {
+ return getOldState().getBinaryType(getOldTypeStructureEntry());
+ }
+
+ /**
+ * Returns the old state
+ */
+ protected StateImpl getOldState() {
+ return (StateImpl) fBuilder.getOldState();
+ }
+
+ /**
+ * Returns the tsEntry in the old state
+ */
+ public abstract TypeStructureEntry getOldTypeStructureEntry();
+ /**
+ * Returns the non state-specific type handle for the superclass
+ * of this type, or null if the superclass is null.
+ */
+ public IType getSuperclass() {
+ char[] newSuper = getNewBinaryType().getSuperclassName();
+ return BinaryStructure.getType(
+ getNewState(),
+ getNewTypeStructureEntry(),
+ newSuper);
+ }
+
+ /**
+ * Returns true if the given type is either a direct or indirect superclass
+ * of this type, otherwise returns false. This method must never be
+ * called on a type that has had a hierarchy change.
+ */
+ public boolean hasSuperclass(IType type) {
+ IType supr = getSuperclass();
+ if (supr == null) {
+ return false;
+ }
+ if (supr.equals(type)) {
+ return true;
+ }
+ return fBuilder.getBuilderType(supr).hasSuperclass(type);
+ }
+
+ /**
+ * Returns true if the given type is either a direct or indirect superclass
+ * of this type, otherwise returns false. This method must never be
+ * called on a type that has had a hierarchy change.
+ */
+ public boolean hasSuperInterface(IType type) {
+ char[][] interfaces = getNewBinaryType().getInterfaceNames();
+ if (interfaces == null) {
+ return false;
+ }
+ for (int i = 0; i < interfaces.length; i++) {
+ IType supr =
+ BinaryStructure.getType(
+ getNewState(),
+ getNewTypeStructureEntry(),
+ interfaces[i]);
+ if (supr.equals(type)
+ || fBuilder.getBuilderType(supr).hasSuperInterface(type)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the given type is either a direct or indirect supertype
+ * of this type, otherwise returns false. This method must never be
+ * called on a type that has had a hierarchy change.
+ */
+ public boolean hasSuperType(IType type) {
+ return hasSuperclass(type) || hasSuperInterface(type);
+ }
+
+ /**
+ * Returns true if the given type was affected by the build
+ * (either added, removed, or changed)
+ */
+ public boolean isAffected() {
+ return true;
+ }
+
+ /**
+ * Sets the tsEntry in the new state
+ */
+ public abstract void setNewTypeStructureEntry(TypeStructureEntry newEntry);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ClassOrInterfaceHandleImpl.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ClassOrInterfaceHandleImpl.java
new file mode 100644
index 0000000000..b224e1108d
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ClassOrInterfaceHandleImpl.java
@@ -0,0 +1,554 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.builder.*;
+import org.eclipse.jdt.internal.core.Util;
+
+public class ClassOrInterfaceHandleImpl extends TypeImpl {
+ PackageImpl fOwner;
+ String fIdentifier;
+ /**
+ * Creates a new ClassOrInterfaceHandleImpl
+ */
+ ClassOrInterfaceHandleImpl(String name, PackageImpl owner) {
+ fIdentifier = name;
+ fOwner = owner;
+ }
+
+ /**
+ * Appends the signature for this type to the StringBuffer.
+ * If includeUnnamed is true, then the identifiers for unnamed packages
+ * are included, preceded by '$'. Otherwise, they are excluded.
+ */
+ void appendSignature(StringBuffer sb, boolean includeUnnamed) {
+
+ sb.append('L');
+ if (((PackageImpl) fOwner).appendSignature(sb, includeUnnamed)) {
+ sb.append('.');
+ }
+ sb.append(getSimpleName());
+ sb.append(';');
+ }
+
+ /**
+ * Appends the VM signature of the type to the StringBuffer.
+ */
+ void appendVMSignature(StringBuffer sb) {
+ sb.append('L');
+ if (!fOwner.isUnnamed()) {
+ sb.append(fOwner.getName());
+ sb.append('.');
+ }
+ sb.append(fIdentifier);
+ sb.append(';');
+ }
+
+ /**
+ * Return the current state implementation.
+ * Must be functionally equivalent to (StateImpl) getDevelopmentContext().getCurrentState().
+ */
+ private StateImpl currentState() {
+ StateImpl state = fOwner.fDevelopmentContext.fCurrentState;
+ if (state != null) {
+ return state;
+ }
+ throw new NotPresentException();
+ }
+
+ /**
+ * Compares this object against the specified object.
+ * Returns true if the objects are the same.
+ */
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof ClassOrInterfaceHandleImpl))
+ return false;
+
+ ClassOrInterfaceHandleImpl clazz = (ClassOrInterfaceHandleImpl) o;
+ return this.fIdentifier.equals(clazz.fIdentifier)
+ && this.fOwner.equals(clazz.fOwner);
+ }
+
+ /**
+ * Returns a Constructor object that represents the specified
+ * constructor of the class represented by this object.
+ * The parameterTypes parameter is an array of Type objects that
+ * identify the constructor's formal parameter types, in declared
+ * order.
+ * Returns null if this type does not represent a class or interface.
+ * This is a handle-only method; the specified constructor may
+ * or may not actually be present in the class or interface.
+ */
+ public IConstructor getConstructorHandle(IType[] parameterTypes) {
+ return new ConstructorImpl(this, parameterTypes);
+ }
+
+ /**
+ * @see IType#getCRC
+ */
+ public int getCRC() throws NotPresentException {
+ return inCurrentState0().getCRC();
+ }
+
+ /**
+ * Returns an array of Type objects representing all the classes
+ * and interfaces declared as members of the class represented by
+ * this object. This includes public, protected, default
+ * (package) access, and private classes and interfaces declared
+ * by the class, but excludes inherited classes and interfaces.
+ * Returns an array of length 0 if the class declares no classes
+ * or interfaces as members, or if this object represents an
+ * array type or primitive type.
+ * The resulting Types are in no particular order.
+ */
+ public IType[] getDeclaredClasses() throws NotPresentException {
+ return nonStateSpecific(inCurrentState0().getDeclaredClasses());
+ }
+
+ /**
+ * Returns an array of Constructor objects representing all the
+ * constructors declared by the class represented by this
+ * object. These are public, protected, default (package) access,
+ * and private constructors. Returns an array of length 0 if this
+ * object represents an interface, an array type or a primitive type.
+ * The resulting Constructors are in no particular order.
+ */
+ public IConstructor[] getDeclaredConstructors() throws NotPresentException {
+ return nonStateSpecific(inCurrentState0().getDeclaredConstructors());
+ }
+
+ /**
+ * Returns an array of Field objects representing all the fields
+ * declared by the class or interface represented by this
+ * object. This includes public, protected, default (package)
+ * access, and private fields, but excludes inherited
+ * fields. Returns an array of length 0 if the class or interface
+ * declares no fields, or if this object represents a
+ * primitive type or an array type (the implicit <code>length</code>
+ * field of array types is not considered to be a declared field).
+ * The resulting Fields are in no particular order.
+ */
+ public IField[] getDeclaredFields() throws NotPresentException {
+ return nonStateSpecific(inCurrentState0().getDeclaredFields());
+ }
+
+ /**
+ * Returns an array of Method objects representing all the methods
+ * declared by the class or interface represented by this
+ * object. This includes public, protected, default (package)
+ * access, and private methods, but excludes inherited
+ * methods. Returns an array of length 0 if the class or interface
+ * declares no methods, or if this object represents an
+ * array type or primitive type.
+ * The resulting Methods are in no particular order.
+ */
+ public IMethod[] getDeclaredMethods() throws NotPresentException {
+ return nonStateSpecific(inCurrentState0().getDeclaredMethods());
+ }
+
+ /**
+ * Returns the declared Java language modifiers, as specified in the declaration
+ * of this class or interface, encoded in an integer.
+ * The modifiers consist of the Java Virtual Machine's constants
+ * for public, protected, private, and final; they should be decoded
+ * using the methods of class Modifier.
+ * The result may not correspond to the modifiers in the compiled
+ * binary, since the compiler may change them (in particular,
+ * for inner classes). The <code>getModifiers()</code>
+ * method should be used if the compiled modifiers are needed.
+ * Returns 0 if this type does not represent a class or interface.
+ *
+ * <p>The modifier encodings are defined in <em>The Java Virtual
+ * Machine Specification</em>, table 4.1.
+ */
+ public int getDeclaredModifiers() throws NotPresentException {
+ return inCurrentState0().getDeclaredModifiers();
+ }
+
+ /**
+ * Returns the declared name of the class or interface represented
+ * by this object, as a String.
+ * The name is the simple, unqualified name used in the source code.
+ * If this represents an inner class, it does not include the names
+ * of any containing classes.
+ * If this represents an anonymous class, it returns a String of length 0.
+ * If this does not represent a class or interface, it returns
+ * a String of length 0.
+ */
+ public String getDeclaredName() throws NotPresentException {
+ return inCurrentState0().getDeclaredName();
+ }
+
+ /**
+ * If the class or interface represented by this Type object is
+ * a member of another class or interface (i.e. it is a nested class),
+ * this returns the Type object representing the class or interface
+ * of which it is a member (its <em>declaring class</em>).
+ * If this class or interface is a local class, returns the Type
+ * object representing the class containing the member in which
+ * this class is declared.
+ * Returns null if this class or interface is not a nested class,
+ * or if this type does not represent a class or interface.
+ */
+ public IType getDeclaringClass() {
+ IType result = inCurrentState0().getDeclaringClass();
+ if (result == null)
+ return null;
+ return (IType) result.nonStateSpecific();
+ }
+
+ /**
+ * Returns a Field object that represents the specified
+ * member field of the class or interface represented
+ * by this object. The name parameter is a String specifying
+ * the simple name of the desired field.
+ * Returns null if this type does not represent a class or interface.
+ * This is a handle-only method; the specified field may
+ * or may not actually be present in the class or interface.
+ */
+ public IField getFieldHandle(String name) {
+ return new FieldImpl(this, name);
+ }
+
+ /**
+ * Returns an array of Type objects representing the
+ * classes in the given ImageContext which directly implement this interface.
+ * A class is said to directly implement this interface if the interface
+ * appears in the <code>implements</code> clause of the class's declaration.
+ * Although all array types are considered to implement the <code>Cloneable</code>
+ * interface, this method never returns array types, only class types.
+ * Returns an array of length 0 if this object does not represent
+ * an interface.
+ * The resulting Types are in no particular order.
+ * See <em>The Java Language Specification</em> section 8.1.4
+ * for more details.
+ */
+ public IType[] getImplementingClasses(IImageContext imageContext)
+ throws NotPresentException {
+ return nonStateSpecific(inCurrentState0().getImplementingClasses(imageContext));
+ }
+
+ /**
+ * Returns an array of Type objects representing the direct
+ * superinterfaces of the class or interface represented by this object.
+ * <p>
+ * If this object represents a class, the return value is an array
+ * containing objects representing all interfaces directly implemented by the
+ * class. The order of the interface objects in the array corresponds
+ * to the order of the interface names in the <code>implements</code>
+ * clause of the declaration of the class represented by this object.
+ * <p>
+ * If this object represents an interface, the array contains
+ * objects representing all interfaces directly extended by the interface.
+ * The order of the interface objects in the array corresponds to the
+ * order of the interface names in the <code>extends</code> clause of
+ * the declaration of the interface represented by this object.
+ * <p>
+ * If the class or interface implements no interfaces, or if this
+ * object represents neither a class nor an interface, this method
+ * returns an array of length 0.
+ *
+ * See <em>The Java Language Specification</em> sections 8.1.4 and 9.1.3
+ * for more details.
+ */
+ public IType[] getInterfaces() throws NotPresentException {
+ IType[] interfaces = inCurrentState0().getInterfaces();
+ int len = interfaces.length;
+ if (len == 0) {
+ return interfaces;
+ }
+
+ IType[] results = new IType[len];
+ for (int i = 0; i < len; i++) {
+ results[i] = (IType) interfaces[i].nonStateSpecific();
+ }
+ return results;
+ }
+
+ public JavaDevelopmentContextImpl getInternalDC() {
+ return fOwner.getInternalDC();
+ }
+
+ /**
+ * Returns a Method object that represents the specified
+ * member method of the class or interface represented
+ * by this object. The name parameter is a String specifying the
+ * simple name the desired method, and the parameterTypes
+ * parameter is an array of Type objects that identify the
+ * method's formal parameter types, in declared order.
+ * Returns null if this type does not represent a class or interface.
+ * This is a handle-only method; the specified method may
+ * or may not actually be present in the class or interface.
+ */
+ public IMethod getMethodHandle(String name, IType[] parameterTypes) {
+ return new MethodImpl(this, name, parameterTypes);
+ }
+
+ /**
+ * Returns the compiled Java language modifiers for this class or
+ * interface, encoded in an integer. The modifiers consist of the
+ * Java Virtual Machine's constants for public, protected,
+ * private, and final; they should be decoded using the
+ * methods of class Modifier.
+ * The result may not correspond to the modifiers as declared in
+ * the source, since the compiler may change them (in particular,
+ * for inner classes). The <code>getDeclaredModifiers()</code>
+ * method should be used if the original modifiers are needed.
+ * Returns 0 if this type does not represent a class or interface.
+ */
+ public int getModifiers() throws NotPresentException {
+ return inCurrentState0().getModifiers();
+ }
+
+ /**
+ * getName method comment.
+ */
+ public String getName() {
+ if (fOwner.isUnnamed())
+ return fIdentifier;
+ return Util.concat(fOwner.getName(), '.', fIdentifier);
+ }
+
+ /**
+ * Returns the Package in which this class or interface is declared.
+ * Returns null if this object represents a primitive type or array type.
+ * This is a handle-only method.
+ */
+ public IPackage getPackage() {
+ return fOwner;
+ }
+
+ /**
+ * getSimpleName method comment.
+ */
+ public String getSimpleName() {
+ return fIdentifier;
+ }
+
+ /**
+ * Returns a SourceFragment describing the fragment of source
+ * from which this member is derived.
+ * Returns null if this type represent a primitive type or an
+ * array type, or if this type is not derived directly from source
+ * (e.g. a fictional type, which is created by the image builder).
+ */
+ public ISourceFragment getSourceFragment() throws NotPresentException {
+ return inCurrentState0().getSourceFragment();
+ }
+
+ /**
+ * Returns an array of Type objects representing the
+ * classes in the given ImageContext which are direct subclasses of
+ * this class.
+ * Returns an array of length 0 if this object does not represent
+ * a class.
+ * The resulting Types are in no particular order.
+ * See <em>The Java Language Specification</em> sections 8.1.3 and 20.3.4
+ * for more details.
+ */
+ public IType[] getSubclasses(IImageContext imageContext)
+ throws NotPresentException {
+ return nonStateSpecific(inCurrentState0().getSubclasses(imageContext));
+ }
+
+ /**
+ * Returns an array of Type objects representing the
+ * interfaces in the given ImageContext which are direct subinterfaces of
+ * this interface.
+ * Returns an array of length 0 if this object does not represent
+ * an interface.
+ * The resulting Types are in no particular order.
+ * See <em>The Java Language Specification</em> section 9.1.3
+ * for more details.
+ */
+ public IType[] getSubinterfaces(IImageContext imageContext)
+ throws NotPresentException {
+ return nonStateSpecific(inCurrentState0().getSubinterfaces(imageContext));
+ }
+
+ /**
+ * If this object represents any class other than the class
+ * <code>java.lang.Object</code>, then the object that represents
+ * the direct superclass of that class is returned.
+ * <p>
+ * If this object represents the class <code>java.lang.Object</code>
+ * or this object represents an interface or a primitive type,
+ * <code>null</code> is returned.
+ * If this object represents an array type, then the Type that represents
+ * class <code>java.lang.Object</code> is returned.
+ * <p>
+ * See <em>The Java Language Specification</em> sections 8.1.3 and 20.3.4
+ * for more details.
+ */
+ public IType getSuperclass() throws NotPresentException {
+ IType supr = inCurrentState0().getSuperclass();
+ if (supr != null) {
+ return (IType) supr.nonStateSpecific();
+ }
+ return supr;
+ }
+
+ /**
+ * Returns a consistent hash code for this object
+ */
+ public int hashCode() {
+ return fIdentifier.hashCode();
+ }
+
+ private ClassOrInterfaceHandleImplSWH inCurrentState0() {
+ return new ClassOrInterfaceHandleImplSWH(
+ fOwner.fDevelopmentContext.fCurrentState,
+ this);
+ }
+
+ /**
+ * Returns a state specific version of this handle in the given state.
+ */
+ public IHandle inState(IState s)
+ throws org.eclipse.jdt.internal.core.builder.StateSpecificException {
+
+ return new ClassOrInterfaceHandleImplSWH((StateImpl) s, this);
+ }
+
+ /**
+ * Returns true if this object represents an anonymous class,
+ * false otherwise.
+ * An anonymous class is a local inner class with no declared name.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ */
+ public boolean isAnonymous() throws NotPresentException {
+ return inCurrentState0().isAnonymous();
+ }
+
+ /**
+ * Return true if this represents a binary class or interface, false otherwise.
+ * A binary type is one which is in .class file format in the source tree.
+ * Returns false if this represents a primitive type or an array type.
+ */
+ public boolean isBinary() throws NotPresentException {
+ return inCurrentState0().isBinary();
+ }
+
+ /**
+ * Determines if this object represents a class type.
+ * This returns false if this object represents an interface,
+ * an array type, or a primitive type.
+ */
+ public boolean isClass() throws NotPresentException {
+ return inCurrentState0().isClass();
+ }
+
+ /**
+ * Returns true if the type represented by this object is
+ * deprecated, false otherwise. A deprecated object is one that
+ * has a deprecated tag in its doc comment.
+ * Returns false if this represents a primitive type or an array type.
+ */
+ public boolean isDeprecated() throws NotPresentException {
+ return inCurrentState0().isDeprecated();
+ }
+
+ /**
+ * Returns true if this object represents an inner class or interface,
+ * false otherwise.
+ * An inner class is one which can only be created in the context of
+ * an instance of its outer class. This does not include package member
+ * classes or other top-level classes. Such a class cannot be static.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ */
+ public boolean isInnerClass() throws NotPresentException {
+ return inCurrentState0().isInnerClass();
+ }
+
+ /**
+ * Determines if this object represents an interface type.
+ * This returns false if this object represents a class,
+ * an array type, or a primitive type.
+ */
+ public boolean isInterface() throws NotPresentException {
+ return inCurrentState0().isInterface();
+ }
+
+ /**
+ * Returns true if this object represents a local inner class,
+ * false otherwise.
+ * A local inner class is an inner class which is defined in the body of
+ * a method or other block, not as a class field.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ */
+ public boolean isLocal() throws NotPresentException {
+ return inCurrentState0().isLocal();
+ }
+
+ /**
+ * Returns true if this object represents a class or interface
+ * which is declared as a package member (i.e. a 'normal' class
+ * as in JDK 1.02). Returns false otherwise.
+ * In particular, this method returns false if this object represents a
+ * top-level class which is declared as a member of a class.
+ * For the sake of consistent terminology, a class which is
+ * not a package member is considered 'nested', whether or not
+ * it is top-level.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ */
+ public boolean isPackageMember() throws NotPresentException {
+ return inCurrentState0().isPackageMember();
+ }
+
+ /**
+ * Returns true if the type represented by this object is
+ * synthetic, false otherwise. A synthetic object is one that
+ * was invented by the compiler, but was not declared in the source.
+ * See <em>The Inner Classes Specification</em>.
+ * A synthetic object is not the same as a fictitious object.
+ */
+ public boolean isSynthetic() throws NotPresentException {
+ return inCurrentState0().isSynthetic();
+ }
+
+ /**
+ * Returns true if this object represents a top-level class or interface,
+ * false otherwise.
+ * A top-level class is declared either as a package member or as a
+ * static member of another top-level class. Unlike inner classes,
+ * instances of top-level classes are not created in the context of
+ * another object.
+ * Given the appropriate access modifiers, a top-level class can be
+ * referred to directly by a qualified name.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ */
+ public boolean isTopLevel()
+ throws org.eclipse.jdt.internal.core.builder.NotPresentException {
+ return inCurrentState0().isTopLevel();
+ }
+
+ /**
+ * Returns the source name, estimated from looking at the class name.
+ * The source name does not include any enclosing types.
+ */
+ String sourceNameFromHandle() {
+
+ String simpleName = getSimpleName();
+ int i = simpleName.lastIndexOf('$');
+
+ /* if its not an inner class */
+ if (i == 0) {
+ return simpleName;
+ }
+ if (i < simpleName.length() && !Character.isDigit(simpleName.charAt(i + 1))) {
+ return simpleName.substring(i + 1);
+ } else {
+ return simpleName;
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ClassOrInterfaceHandleImplSWH.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ClassOrInterfaceHandleImplSWH.java
new file mode 100644
index 0000000000..f1d9ffcde0
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ClassOrInterfaceHandleImplSWH.java
@@ -0,0 +1,651 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.core.builder.*;
+
+import java.util.Hashtable;
+
+public class ClassOrInterfaceHandleImplSWH extends TypeImplSWH {
+ ClassOrInterfaceHandleImpl fHandle;
+ /**
+ * Creates a new method handle in the given state
+ */
+ ClassOrInterfaceHandleImplSWH(
+ StateImpl state,
+ ClassOrInterfaceHandleImpl handle)
+ throws NotPresentException {
+ if (state == null)
+ throw new NotPresentException();
+ fState = state;
+ fHandle = handle;
+ }
+
+ /**
+ * Returns the IBinaryType for this class or interface.
+ * Throws a not present exception if the type is not present.
+ */
+ protected IBinaryType getBinaryType() throws NotPresentException {
+ return fState.getBinaryType(getTypeStructureEntry());
+ }
+
+ /**
+ * Returns the IBinaryType for this class or interface.
+ */
+ protected IBinaryType getBinaryType(TypeStructureEntry tsEntry) {
+ return fState.getBinaryType(tsEntry);
+ }
+
+ /**
+ * Returns a Constructor object that represents the specified
+ * constructor of the class represented by this object.
+ * The parameterTypes parameter is an array of Type objects that
+ * identify the constructor's formal parameter types, in declared
+ * order.
+ * Returns null if this type does not represent a class or interface.
+ * This is a handle-only method; the specified constructor may
+ * or may not actually be present in the class or interface.
+ */
+ public IConstructor getConstructorHandle(IType[] parameterTypes) {
+ IType[] params = new IType[parameterTypes.length];
+ for (int i = 0; i < params.length; i++)
+ params[i] = (IType) parameterTypes[i].nonStateSpecific();
+ return (IConstructor) fHandle.getConstructorHandle(params).inState(fState);
+ }
+
+ /**
+ * @see IType#getCRC
+ */
+ public int getCRC() throws NotPresentException {
+ TypeStructureEntry tsEntry = getTypeStructureEntry();
+ int crc = tsEntry.getCRC32();
+ if (crc == 0) {
+ /* If it's a class file, then read the binary from the workspace and compute the CRC */
+ if (tsEntry.isBinary()) {
+ byte[] binary = fState.getElementContentBytes(tsEntry.getSourceEntry());
+ crc = fState.getBinaryOutput().crc32(binary);
+ tsEntry.setCRC32(crc);
+ }
+ }
+ return crc;
+ }
+
+ /**
+ * Returns an array of Type objects representing all the classes
+ * and interfaces declared as members of the class represented by
+ * this object. This includes public, protected, default
+ * (package) access, and private classes and interfaces declared
+ * by the class, but excludes inherited classes and interfaces.
+ * Returns an array of length 0 if the class declares no classes
+ * or interfaces as members, or if this object represents an
+ * array type or primitive type.
+ * The resulting Types are in no particular order.
+ */
+ public IType[] getDeclaredClasses() throws NotPresentException {
+ TypeStructureEntry tsEntry = getTypeStructureEntry();
+ IBinaryType binaryType = getBinaryType(tsEntry);
+ char[][] names = BinaryStructure.getInnerTypes(binaryType);
+ int len = names.length;
+ IType[] types = new IType[len];
+ int count = 0;
+ for (int i = 0; i < len; i++) {
+ IType type =
+ (IType) fState
+ .typeNameToHandle(tsEntry, BinaryStructure.convertTypeName(names[i]))
+ .inState(fState);
+ if (!type.isLocal()) {
+ types[count++] = type;
+ }
+ }
+ if (count < len) {
+ System.arraycopy(types, 0, types = new IType[count], 0, count);
+ }
+ return types;
+ }
+
+ /**
+ * Returns an array of Constructor objects representing all the
+ * constructors declared by the class represented by this
+ * object. These are public, protected, default (package) access,
+ * and private constructors. Returns an array of length 0 if this
+ * object represents an interface, an array type or a primitive type.
+ * The resulting Constructors are in no particular order.
+ */
+ public IConstructor[] getDeclaredConstructors() throws NotPresentException {
+ IBinaryMethod[] methods = getBinaryType().getMethods();
+ if (methods == null)
+ return new IConstructor[0];
+
+ // count constructors
+ int n = 0;
+ for (int i = 0; i < methods.length; i++) {
+ if (methods[i].isConstructor()) {
+ ++n;
+ }
+ }
+ IConstructor[] result = new IConstructor[n];
+ int k = 0;
+ for (int i = 0; i < methods.length; i++) {
+ if (methods[i].isConstructor()) {
+ result[k++] =
+ (IConstructor) BinaryStructure
+ .getConstructorHandle(methods[i], fHandle)
+ .inState(fState);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns an array of Field objects representing all the fields
+ * declared by the class or interface represented by this
+ * object. This includes public, protected, default (package)
+ * access, and private fields, but excludes inherited
+ * fields. Returns an array of length 0 if the class or interface
+ * declares no fields, or if this object represents a
+ * primitive type or an array type (the implicit <code>length</code>
+ * field of array types is not considered to be a declared field).
+ * The resulting Fields are in no particular order.
+ */
+ public IField[] getDeclaredFields() throws NotPresentException {
+ IBinaryField[] fields = getBinaryType().getFields();
+ if (fields == null)
+ return new IField[0];
+ IField[] handles = new IField[fields.length];
+ for (int i = 0; i < fields.length; i++) {
+ handles[i] =
+ (IField) BinaryStructure.getFieldHandle(fields[i], fHandle).inState(fState);
+ }
+ return handles;
+ }
+
+ /**
+ * Returns an array of Method objects representing all the methods
+ * declared by the class or interface represented by this
+ * object. This includes public, protected, default (package)
+ * access, and private methods, but excludes inherited
+ * methods. Returns an array of length 0 if the class or interface
+ * declares no methods, or if this object represents an
+ * array type or primitive type.
+ * The resulting Methods are in no particular order.
+ */
+ public IMethod[] getDeclaredMethods() throws NotPresentException {
+ IBinaryMethod[] methods = getBinaryType().getMethods();
+ if (methods == null)
+ return new IMethod[0];
+
+ // count methods
+ int n = 0;
+ for (int i = 0; i < methods.length; i++) {
+ if (!methods[i].isConstructor()
+ && methods[i].getSelector()[0] != '<') { // TBD: need IBinaryMethod.isClinit()
+ ++n;
+ }
+ }
+ IMethod[] result = new IMethod[n];
+ int k = 0;
+ for (int i = 0; i < methods.length; i++) {
+ if (!methods[i].isConstructor()
+ && methods[i].getSelector()[0] != '<') { // TBD: need IBinaryMethod.isClinit()
+ result[k++] =
+ (IMethod) BinaryStructure.getMethodHandle(methods[i], fHandle).inState(fState);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the declared Java language modifiers, as specified in the declaration
+ * of this class or interface, encoded in an integer.
+ * The modifiers consist of the Java Virtual Machine's constants
+ * for public, protected, private, and final; they should be decoded
+ * using the methods of class Modifier.
+ * The result may not correspond to the modifiers in the compiled
+ * binary, since the compiler may change them (in particular,
+ * for inner classes). The <code>getModifiers()</code>
+ * method should be used if the compiled modifiers are needed.
+ * Returns 0 if this type does not represent a class or interface.
+ *
+ * <p>The modifier encodings are defined in <em>The Java Virtual
+ * Machine Specification</em>, table 4.1.
+ */
+ public int getDeclaredModifiers() throws NotPresentException {
+
+ return getModifiers();
+ }
+
+ /**
+ * Returns the declared name of the class or interface represented
+ * by this object, as a String.
+ * The name is the simple, unqualified name used in the source code.
+ * If this represents an inner class, it does not include the names
+ * of any containing classes.
+ * If this represents an anonymous class, it returns a String of length 0.
+ * If this does not represent a class or interface, it returns
+ * a String of length 0.
+ */
+ public String getDeclaredName() throws NotPresentException {
+
+ if (isAnonymous()) {
+ return "";
+ }
+
+ String name = fHandle.getSimpleName();
+ return name.substring(name.lastIndexOf('$') + 1);
+ }
+
+ /**
+ * If the class or interface represented by this Type object is
+ * a member of another class or interface (i.e. it is a nested class),
+ * this returns the Type object representing the class or interface
+ * of which it is a member (its <em>declaring class</em>).
+ * If this class or interface is a local class, returns the Type
+ * object representing the class containing the member in which
+ * this class is declared.
+ * Returns null if this class or interface is not a nested class,
+ * or if this type does not represent a class or interface.
+ */
+ public IType getDeclaringClass() {
+ TypeStructureEntry tsEntry = getTypeStructureEntry();
+ IBinaryType binaryType = getBinaryType(tsEntry);
+ char[] enclosing = BinaryStructure.getEnclosingTypeName(binaryType);
+ if (enclosing == null) {
+ return null;
+ }
+ return (IType) fState
+ .typeNameToHandle(tsEntry, BinaryStructure.convertTypeName(enclosing))
+ .inState(fState);
+ }
+
+ /**
+ * Returns a Field object that represents the specified
+ * member field of the class or interface represented
+ * by this object. The name parameter is a String specifying
+ * the simple name of the desired field.
+ * Returns null if this type does not represent a class or interface.
+ * This is a handle-only method; the specified field may
+ * or may not actually be present in the class or interface.
+ */
+ public IField getFieldHandle(String name) {
+ return (IField) ((IType) fHandle).getFieldHandle(name).inState(fState);
+ }
+
+ /**
+ * Returns the non state specific handle
+ */
+ protected TypeImpl getHandle() {
+ return fHandle;
+ }
+
+ /**
+ * Returns an array of Type objects representing the
+ * classes in the given ImageContext which directly implement this interface.
+ * A class is said to directly implement this interface if the interface
+ * appears in the <code>implements</code> clause of the class's declaration.
+ * Although all array types are considered to implement the <code>Cloneable</code>
+ * interface, this method never returns array types, only class types.
+ * Returns an array of length 0 if this object does not represent
+ * an interface.
+ * The resulting Types are in no particular order.
+ * See <em>The Java Language Specification</em> section 8.1.4
+ * for more details.
+ */
+ public IType[] getImplementingClasses(IImageContext imageContext)
+ throws NotPresentException {
+
+ return getSubtypes(imageContext, true, false);
+ }
+
+ /**
+ * Returns an array of Type objects representing the direct
+ * superinterfaces of the class or interface represented by this object.
+ * <p>
+ * If this object represents a class, the return value is an array
+ * containing objects representing all interfaces directly implemented by the
+ * class. The order of the interface objects in the array corresponds
+ * to the order of the interface names in the <code>implements</code>
+ * clause of the declaration of the class represented by this object.
+ * <p>
+ * If this object represents an interface, the array contains
+ * objects representing all interfaces directly extended by the interface.
+ * The order of the interface objects in the array corresponds to the
+ * order of the interface names in the <code>extends</code> clause of
+ * the declaration of the interface represented by this object.
+ * <p>
+ * If the class or interface implements no interfaces, or if this
+ * object represents neither a class nor an interface, this method
+ * returns an array of length 0.
+ *
+ * See <em>The Java Language Specification</em> sections 8.1.4 and 9.1.3
+ * for more details.
+ */
+ public IType[] getInterfaces() throws NotPresentException {
+ char[][] interfaces = getBinaryType().getInterfaceNames();
+ if (interfaces == null) {
+ return new IType[0];
+ }
+ int len = interfaces.length;
+ IType[] results = new IType[len];
+ if (len > 0) {
+ TypeStructureEntry tsEntry = getTypeStructureEntry();
+ for (int i = 0; i < len; i++) {
+ results[i] = (IType) BinaryStructure.getType(fState, tsEntry, interfaces[i]);
+ }
+ }
+ return results;
+ }
+
+ /**
+ * Returns a Method object that represents the specified
+ * member method of the class or interface represented
+ * by this object. The name parameter is a String specifying the
+ * simple name the desired method, and the parameterTypes
+ * parameter is an array of Type objects that identify the
+ * method's formal parameter types, in declared order.
+ * Returns null if this type does not represent a class or interface.
+ * This is a handle-only method; the specified method may
+ * or may not actually be present in the class or interface.
+ */
+ public IMethod getMethodHandle(String name, IType[] parameterTypes) {
+ IType[] paramNSS = new IType[parameterTypes.length];
+ // non-state-specific handles
+ for (int i = 0; i < parameterTypes.length; i++)
+ paramNSS[i] = (IType) parameterTypes[i].nonStateSpecific();
+
+ return (IMethod) ((IType) fHandle).getMethodHandle(name, paramNSS).inState(
+ fState);
+ }
+
+ /**
+ * Returns the compiled Java language modifiers for this class or
+ * interface, encoded in an integer. The modifiers consist of the
+ * Java Virtual Machine's constants for public, protected,
+ * private, and final; they should be decoded using the
+ * methods of class Modifier.
+ * The result may not correspond to the modifiers as declared in
+ * the source, since the compiler may change them (in particular,
+ * for inner classes). The <code>getDeclaredModifiers()</code>
+ * method should be used if the original modifiers are needed.
+ * Returns 0 if this type does not represent a class or interface.
+ */
+ public int getModifiers() throws NotPresentException {
+ int flags = getBinaryType().getModifiers();
+ return flags & (0xFFFF & ~IConstants.AccInterface & ~IConstants.AccSuper);
+ // clear out special flags and interface flag
+ }
+
+ /**
+ * Returns the Package in which this class or interface is declared.
+ * Returns null if this object represents a primitive type or array type.
+ * This is a handle-only method.
+ */
+ public IPackage getPackage() {
+ return (IPackage) fHandle.getPackage().inState(fState);
+ }
+
+ /**
+ * Returns a SourceFragment describing the fragment of source
+ * from which this member is derived.
+ * Returns null if this type represent a primitive type or an
+ * array type, or if this type is not derived directly from source
+ * (e.g. a fictional type, which is created by the image builder).
+ */
+ public ISourceFragment getSourceFragment() throws NotPresentException {
+ return getTypeStructureEntry().getSourceFragment();
+ }
+
+ /**
+ * Returns an array of Type objects representing the
+ * classes in the given ImageContext which are direct subclasses of
+ * this class.
+ * Returns an array of length 0 if this object does not represent
+ * a class.
+ * The resulting Types are in no particular order.
+ * See <em>The Java Language Specification</em> sections 8.1.3 and 20.3.4
+ * for more details.
+ */
+ public IType[] getSubclasses(IImageContext imageContext)
+ throws NotPresentException {
+
+ return getSubtypes(imageContext, true, false);
+ }
+
+ /**
+ * Returns an array of Type objects representing the
+ * interfaces in the given ImageContext which are direct subinterfaces of
+ * this interface.
+ * Returns an array of length 0 if this object does not represent
+ * an interface.
+ * The resulting Types are in no particular order.
+ * See <em>The Java Language Specification</em> section 9.1.3
+ * for more details.
+ */
+ public IType[] getSubinterfaces(IImageContext imageContext)
+ throws NotPresentException {
+
+ return getSubtypes(imageContext, false, true);
+ }
+
+ /**
+ * Returns an array of Type objects representing the
+ * types in the given ImageContext which are direct subtypes of this interface.
+ * @param includeClasses true iff classes are candidates
+ * @param includeInterfaces true iff interfaces are candidates
+ */
+ IType[] getSubtypes(
+ IImageContext imageContext,
+ boolean includeClasses,
+ boolean includeInterfaces)
+ throws NotPresentException {
+
+ Hashtable table = fState.getSubtypesTable(imageContext);
+ TypeStructureEntry[] subtypes = (TypeStructureEntry[]) table.get(this);
+ if (subtypes == null) {
+ if (!isPresent())
+ throw new NotPresentException();
+ else
+ return new IType[0];
+ }
+
+ int numSubtypes = subtypes.length;
+ int count = 0;
+ IType[] result = new IType[numSubtypes];
+ for (int i = 0, n = numSubtypes; i < n; i++) {
+ IType type = (IType) subtypes[i].getType().inState(fState);
+ if (type.isInterface()) {
+ if (!includeInterfaces)
+ continue;
+ } else {
+ if (!includeClasses)
+ continue;
+ }
+ result[count++] = type;
+ }
+
+ if (count < numSubtypes)
+ System.arraycopy(result, 0, result = new IType[count], 0, count);
+ return result;
+ }
+
+ /**
+ * If this object represents any class other than the class
+ * <code>java.lang.Object</code>, then the object that represents
+ * the direct superclass of that class is returned.
+ * <p>
+ * If this object represents the class <code>java.lang.Object</code>
+ * or this object represents an interface or a primitive type,
+ * <code>null</code> is returned.
+ * If this object represents an array type, then the Type that represents
+ * class <code>java.lang.Object</code> is returned.
+ * <p>
+ * See <em>The Java Language Specification</em> sections 8.1.3 and 20.3.4
+ * for more details.
+ */
+ public IType getSuperclass() throws NotPresentException {
+ return BinaryStructure.getType(
+ fState,
+ getTypeStructureEntry(),
+ getBinaryType().getSuperclassName());
+ }
+
+ /**
+ * Returns the type structure entry for this class or interface. Throws a
+ * not present exception if the type is not present.
+ */
+ public TypeStructureEntry getTypeStructureEntry() throws NotPresentException {
+ TypeStructureEntry tsEntry = fState.getTypeStructureEntry(fHandle, true);
+ if (tsEntry != null) {
+ return tsEntry;
+ }
+ throw new NotPresentException();
+ }
+
+ /**
+ * Returns true if this object represents an anonymous class,
+ * false otherwise.
+ * An anonymous class is a local inner class with no declared name.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ */
+ public boolean isAnonymous()
+ throws org.eclipse.jdt.internal.core.builder.NotPresentException {
+ return BinaryStructure.isAnonymous(getBinaryType());
+ }
+
+ /**
+ * Return true if this represents a binary class or interface, false otherwise.
+ * A binary type is one which is in .class file format in the source tree.
+ * Returns false if this represents a primitive type or an array type.
+ */
+ public boolean isBinary() throws NotPresentException {
+ return getTypeStructureEntry().isBinary();
+ }
+
+ /**
+ * Determines if this object represents a class type.
+ * This returns false if this object represents an interface,
+ * an array type, or a primitive type.
+ */
+ public boolean isClass() throws NotPresentException {
+ return !isInterface();
+ }
+
+ /**
+ * Returns true if the type represented by this object is
+ * deprecated, false otherwise. A deprecated object is one that
+ * has a deprecated tag in its doc comment.
+ * Returns false if this represents a primitive type or an array type.
+ */
+ public boolean isDeprecated() throws NotPresentException {
+ return (getBinaryType().getModifiers() & IConstants.AccDeprecated) != 0;
+ }
+
+ /**
+ * Returns true if this object represents an inner class or interface,
+ * false otherwise.
+ * An inner class is one which can only be created in the context of
+ * an instance of its outer class. This does not include package member
+ * classes or other top-level classes. Such a class cannot be static.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ */
+ public boolean isInnerClass() throws NotPresentException {
+ return !isTopLevel();
+ }
+
+ /**
+ * Determines if this object represents an interface type.
+ * This returns false if this object represents a class,
+ * an array type, or a primitive type.
+ */
+ public boolean isInterface() throws NotPresentException {
+ return getBinaryType().isInterface();
+ }
+
+ /**
+ * Returns true if this object represents a local inner class,
+ * false otherwise.
+ * A local inner class is an inner class which is defined in the body of
+ * a method or other block, not as a class field.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ */
+ public boolean isLocal() throws NotPresentException {
+ return BinaryStructure.isLocal(getBinaryType());
+ }
+
+ /**
+ * Returns true if this object represents a class or interface
+ * which is declared as a package member (i.e. a 'normal' class
+ * as in JDK 1.02). Returns false otherwise.
+ * In particular, this method returns false if this object represents a
+ * top-level class which is declared as a member of a class.
+ * For the sake of consistent terminology, a class which is
+ * not a package member is considered 'nested', whether or not
+ * it is top-level.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ */
+ public boolean isPackageMember() throws NotPresentException {
+ return BinaryStructure.isPackageMember(getBinaryType());
+ }
+
+ /**
+ * A class or interface type is present if:
+ * - its package is present, and
+ * - the package declares a type of the same name.
+ */
+ public boolean isPresent() {
+ return fState.getTypeStructureEntry(fHandle, true) != null;
+ }
+
+ /**
+ * Returns true if the type represented by this object is
+ * synthetic, false otherwise. A synthetic object is one that
+ * was invented by the compiler, but was not declared in the source.
+ * See <em>The Inner Classes Specification</em>.
+ * A synthetic object is not the same as a fictitious object.
+ */
+ public boolean isSynthetic() throws NotPresentException {
+ return (getBinaryType().getModifiers() & IConstants.AccSynthetic) != 0;
+ }
+
+ /**
+ * Returns true if this object represents a top-level class or interface,
+ * false otherwise.
+ * A top-level class is declared either as a package member or as a
+ * static member of another top-level class. Unlike inner classes,
+ * instances of top-level classes are not created in the context of
+ * another object.
+ * Given the appropriate access modifiers, a top-level class can be
+ * referred to directly by a qualified name.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ */
+ public boolean isTopLevel()
+ throws org.eclipse.jdt.internal.core.builder.NotPresentException {
+ IBinaryType binaryType = getBinaryType();
+ if (BinaryStructure.isPackageMember(binaryType)) {
+ return true;
+ }
+ if (BinaryStructure.isLocal(binaryType)) {
+ return false;
+ }
+ char[] enclosingType = BinaryStructure.getEnclosingTypeName(binaryType);
+ if (enclosingType == null) {
+ return true;
+ }
+ if ((binaryType.getModifiers() & IConstants.AccStatic) == 0) {
+ return false;
+ }
+ TypeStructureEntry tsEntry = getTypeStructureEntry();
+ IType enclosing =
+ (IType) fState.typeNameToHandle(tsEntry, new String(enclosingType)).inState(
+ fState);
+ return enclosing.isTopLevel();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/CompilerCompilationUnit.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/CompilerCompilationUnit.java
new file mode 100644
index 0000000000..1daaadc588
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/CompilerCompilationUnit.java
@@ -0,0 +1,81 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+import org.eclipse.jdt.internal.core.builder.*;
+
+import java.io.IOException;
+
+/**
+ * This is the representation of a compilation unit which
+ * is passed to the compiler. It remembers the contents of the unit
+ * once read, since the compiler may request it multiple times
+ * (it currently asks for it twice: once to get the structure, once
+ * when actually compiling methds). The compiler actually clears out the entries in
+ * the array of ICompilationUnit passed to the compiler, so the
+ * source is only hung onto while needed.
+ */
+public class CompilerCompilationUnit implements ICompilationUnit {
+ protected StateImpl fState;
+ protected SourceEntry fSourceEntry;
+ protected BuildNotifier fNotifier;
+ protected char[] fContents;
+ /**
+ * Creates a new compilation unit for the given source entry.
+ */
+ public CompilerCompilationUnit(
+ StateImpl state,
+ SourceEntry sourceEntry,
+ BuildNotifier notifier) {
+ fState = state;
+ fSourceEntry = sourceEntry;
+ fNotifier = notifier;
+ }
+
+ /**
+ * @see ICompilationUnit
+ * See the discussion of remembering contents in the class comment.
+ */
+ public char[] getContents() {
+ if (fContents == null) {
+ if (fNotifier != null) {
+ fNotifier.compiling(this);
+ }
+ fContents = fState.getElementContentCharArray(fSourceEntry);
+ }
+ return fContents;
+ }
+
+ /**
+ * @see ICompilationUnit
+ */
+ public char[] getFileName() {
+ return fSourceEntry.getPathWithZipEntryName().toCharArray();
+ }
+
+ /**
+ * @see ICompilationUnit
+ */
+ public char[] getMainTypeName() {
+ return fSourceEntry.getName().toCharArray();
+ }
+
+ /**
+ * Returns the source entry
+ */
+ public SourceEntry getSourceEntry() {
+ return fSourceEntry;
+ }
+
+ public String toString() {
+ // don't use append(char[]) due to JDK1.2 problems
+ return new StringBuffer("CompilationUnit(")
+ .append(getFileName())
+ .append(")")
+ .toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ConsoleProgressMonitor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ConsoleProgressMonitor.java
new file mode 100644
index 0000000000..660f47ac52
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ConsoleProgressMonitor.java
@@ -0,0 +1,87 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * This progress monitor is used as the default progress monitor in cases
+ * where none has been set. It is used mainly for test cases. The monitor
+ * simply echoes updates to the console (System.out).
+ */
+class ConsoleProgressMonitor implements IProgressMonitor {
+ protected int fTotalWork;
+ protected int fWorkDone;
+ /**
+ * beginTask method comment.
+ */
+ public void beginTask(String name, int totalWork) {
+ System.out.println(name + ", total work: " + totalWork);
+ fTotalWork = totalWork;
+ fWorkDone = 0;
+ }
+
+ /**
+ * done method comment.
+ */
+ public void done() {
+ System.out.println("Task Done");
+ fTotalWork = 0;
+ fWorkDone = 0;
+ }
+
+ public void internalWorked(double work) {
+ fWorkDone += work;
+ double percent = (double) fWorkDone / (double) fTotalWork;
+ percent *= 100;
+ System.out.println("\t" + percent + "% work done");
+ }
+
+ /**
+ * isCanceled method comment.
+ */
+ public boolean isCanceled() {
+ return false;
+ }
+
+ /**
+ * setCanceled method comment.
+ */
+ public void setCanceled(boolean b) {
+ }
+
+ /**
+ * setTaskName method comment.
+ */
+ public void setTaskName(String name) {
+ System.out.println("\t" + name);
+ }
+
+ /**
+ * subTask method comment.
+ */
+ public void subTask(String name) {
+ System.out.println("\t" + name);
+ }
+
+ /**
+ * Returns a String that represents the value of this object.
+ * @return a string representation of the receiver
+ */
+ public String toString() {
+ return "Default ImageBuilder Progress Monitor";
+ }
+
+ /**
+ * worked method comment.
+ */
+ public void worked(int work) {
+ fWorkDone += work;
+ double percent = (double) fWorkDone / (double) fTotalWork;
+ percent *= 100;
+ System.out.println("\t" + percent + "% work done");
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ConstructorImpl.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ConstructorImpl.java
new file mode 100644
index 0000000000..0644ee724e
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ConstructorImpl.java
@@ -0,0 +1,92 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.builder.*;
+
+public class ConstructorImpl
+ extends AbstractMemberHandle
+ implements IConstructor {
+ ConstructorImpl(ClassOrInterfaceHandleImpl owner, IType[] paramTypes) {
+ fOwner = owner;
+ fSignature = computeSignature("", paramTypes);
+ }
+
+ public ConstructorImpl(ClassOrInterfaceHandleImpl owner, String signature) {
+ fOwner = owner;
+ fSignature = signature;
+ }
+
+ /**
+ * Returns an array of Type objects that represent the types of
+ * the checked exceptions thrown by the underlying constructor
+ * represented by this Constructor object.
+ * Unchecked exceptions are not included in the result, even if
+ * they are declared in the source.
+ * Returns an array of length 0 if the constructor throws no checked
+ * exceptions.
+ * The resulting Types are in no particular order.
+ */
+ public IType[] getExceptionTypes() {
+ return nonStateSpecific(((IConstructor) inCurrentState()).getExceptionTypes());
+ }
+
+ /**
+ * Returns the simple name of the member represented by this object.
+ * If this Member represents a constructor, this returns
+ * the simple name of its declaring class.
+ * This is a handle-only method.
+ */
+ public String getName() {
+ return ((ClassOrInterfaceHandleImpl) getDeclaringClass())
+ .sourceNameFromHandle();
+ }
+
+ /**
+ * Returns an array of Type objects that represent the formal
+ * parameter types, in declaration order, of the constructor
+ * represented by this Constructor object.
+ * Returns an array of length 0 if the underlying constructor
+ * takes no parameters.
+ * This is a handle-only method.
+ */
+ public IType[] getParameterTypes() {
+ return getInternalDC().parameterTypesFromSignature(getSignature());
+ }
+
+ /**
+ * Returns a state specific version of this handle in the given state.
+ */
+ public IHandle inState(IState s)
+ throws org.eclipse.jdt.internal.core.builder.StateSpecificException {
+
+ return new ConstructorImplSWH((StateImpl) s, this);
+ }
+
+ /**
+ * Returns a constant indicating what kind of handle this is.
+ */
+ public int kind() {
+ return IHandle.K_JAVA_CONSTRUCTOR;
+ }
+
+ /**
+ * toString method comment.
+ */
+ public String toString() {
+ StringBuffer sb = new StringBuffer(getDeclaringClass().getName());
+ sb.append('(');
+ IType[] paramTypes = getParameterTypes();
+ for (int i = 0; i < paramTypes.length; ++i) {
+ if (i != 0) {
+ sb.append(',');
+ }
+ sb.append(paramTypes[i].getName());
+ }
+ sb.append(')');
+ return sb.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ConstructorImplSWH.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ConstructorImplSWH.java
new file mode 100644
index 0000000000..b324e870ee
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ConstructorImplSWH.java
@@ -0,0 +1,145 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.core.builder.*;
+import org.eclipse.jdt.internal.core.Util;
+
+public class ConstructorImplSWH
+ extends AbstractMemberHandleSWH
+ implements IConstructor {
+ ConstructorImpl fHandle;
+ /**
+ * Internal - Creates a new constructor handle in the given state
+ */
+ ConstructorImplSWH(StateImpl state, ConstructorImpl handle) {
+ fState = state;
+ fHandle = handle;
+ }
+
+ /**
+ * Internal - Returns the IBinaryMethod for this method.
+ */
+ protected IBinaryMethod getBinaryMethod() throws NotPresentException {
+ return getBinaryMethod(getTypeStructureEntry());
+ }
+
+ /**
+ * Internal - Returns the IBinaryMethod for this method.
+ */
+ protected IBinaryMethod getBinaryMethod(TypeStructureEntry tsEntry)
+ throws NotPresentException {
+ IBinaryType t = fState.getBinaryType(getTypeStructureEntry());
+ IBinaryMethod m = BinaryStructure.getConstructor(t, fHandle.fSignature);
+ if (m == null) {
+ throw new NotPresentException();
+ } else {
+ return m;
+ }
+ }
+
+ /**
+ * Returns an array of Type objects that represent the types of
+ * the checked exceptions thrown by the underlying constructor
+ * represented by this Constructor object.
+ * Unchecked exceptions are not included in the result, even if
+ * they are declared in the source.
+ * Returns an array of length 0 if the constructor throws no checked
+ * exceptions.
+ * The resulting Types are in no particular order.
+ */
+ public IType[] getExceptionTypes() {
+ TypeStructureEntry tsEntry = getTypeStructureEntry();
+ char[][] exceptions = getBinaryMethod(tsEntry).getExceptionTypeNames();
+ PackageImpl pkg = fHandle.fOwner.fOwner;
+ int len = exceptions.length;
+ IType[] results = new IType[len];
+ for (int i = 0; i < len; i++) {
+ results[i] =
+ (IType) fState
+ .typeNameToHandle(tsEntry, Util.convertTypeSignature(exceptions[i]))
+ .inState(fState);
+ }
+ return results;
+ }
+
+ /**
+ * Internal - Returns the non state specific handle
+ */
+ IMember getHandle() {
+ return fHandle;
+ }
+
+ /**
+ * Returns the Java language modifiers for the member
+ * represented by this object, as an integer.
+ */
+ public int getModifiers() {
+ return getBinaryMethod().getModifiers() & 0xFFFF;
+ }
+
+ /**
+ * Returns an array of Type objects that represent the formal
+ * parameter types, in declaration order, of the constructor
+ * represented by this Constructor object.
+ * Returns an array of length 0 if the underlying constructor
+ * takes no parameters. This is a handle-only method.
+ */
+ public IType[] getParameterTypes() {
+ IType[] unwrapped = (IType[]) fHandle.getParameterTypes();
+ IType[] results = new IType[unwrapped.length];
+ for (int i = 0; i < results.length; i++) {
+ results[i] = (IType) unwrapped[i].inState(fState);
+ }
+ return results;
+ }
+
+ /**
+ * Returns true if the member represented by this object is
+ * deprecated, false otherwise. A deprecated object is one that
+ * has a @ deprecated tag in its doc comment.
+ */
+ public boolean isDeprecated() {
+ return (getBinaryMethod().getModifiers() & IConstants.AccDeprecated) != 0;
+ }
+
+ /**
+ * Returns true if the object represented by the receiver is present
+ * in the development context, false otherwise. If the receiver is
+ * state-specific, checks whether it is present in this object's state,
+ * otherwise checks whether it is present in the current state of the
+ * development context.
+ */
+ public boolean isPresent() {
+ TypeStructureEntry entry =
+ fState.getTypeStructureEntry(fHandle.getDeclaringClass(), true);
+ if (entry == null) {
+ return false;
+ }
+ IBinaryType t = fState.getBinaryType(entry);
+ IBinaryMethod m = BinaryStructure.getConstructor(t, fHandle.fSignature);
+ return m != null;
+ }
+
+ /**
+ * Returns true if the member represented by this object is
+ * synthetic, false otherwise. A synthetic object is one that
+ * was invented by the compiler, but was not declared in the source.
+ * See <em>The Inner Classes Specification</em>.
+ * A synthetic object is not the same as a fictitious object.
+ */
+ public boolean isSynthetic() throws NotPresentException {
+ return (getBinaryMethod().getModifiers() & IConstants.AccSynthetic) != 0;
+ }
+
+ /**
+ * Returns the non state specific handle
+ */
+ public IHandle nonStateSpecific() {
+ return fHandle;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ConvertedCompilationResult.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ConvertedCompilationResult.java
new file mode 100644
index 0000000000..d7392fa927
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ConvertedCompilationResult.java
@@ -0,0 +1,52 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.builder.*;
+
+import java.util.Vector;
+
+public class ConvertedCompilationResult {
+ PackageElement fPackageElement;
+ Vector fDependencies;
+ IProblemDetail[] fProblems;
+ TypeStructureEntry[] fTypes;
+
+ ConvertedCompilationResult(
+ PackageElement packageElement,
+ Vector dependencies,
+ IProblemDetail[] problems,
+ TypeStructureEntry[] types) {
+
+ fPackageElement = packageElement;
+ fDependencies = dependencies;
+ fProblems = problems;
+ fTypes = types;
+ }
+
+ Vector getDependencies() {
+ return fDependencies;
+ }
+
+ PackageElement getPackageElement() {
+ return fPackageElement;
+ }
+
+ IProblemDetail[] getProblems() {
+ return fProblems;
+ }
+
+ TypeStructureEntry[] getTypes() {
+ return fTypes;
+ }
+
+ public String toString() {
+ return (fProblems.length == 0 ? "" : "*")
+ + "ConvertedCompilationResult("
+ + fPackageElement
+ + ")";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/DeltaImpl.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/DeltaImpl.java
new file mode 100644
index 0000000000..7fb0da2cb5
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/DeltaImpl.java
@@ -0,0 +1,1020 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.Assert;
+import org.eclipse.jdt.internal.compiler.env.IBinaryType;
+import org.eclipse.jdt.internal.core.builder.*;
+import org.eclipse.jdt.internal.core.Util;
+
+import java.util.*;
+
+class DeltaImpl implements IDelta {
+ protected IDelta fParent;
+ protected IDelta[] fChildren;
+
+ /* Non state specific object */
+ protected Object fObject;
+
+ protected String fName;
+ protected DeltaKey fKey;
+
+ protected StateImpl fNewState;
+ protected StateImpl fOldState;
+
+ protected int fStatus;
+ protected IImageContext fContext;
+
+ /* names for checklist items */
+ public static final String fgImage = "Image";
+
+ public static final String fgPackageCategory = "Packages";
+ public static final String fgTypeCategory = "Types";
+ public static final String fgBinaryCategory = "Binaries";
+ public static final String fgMethodCategory = "Methods";
+
+ public static final String fgPackage = "Package";
+ public static final String fgType = "Type";
+ public static final String fgBinary = "Binary";
+ public static final String fgMethod = "Method";
+
+ /* convenience structure for delta calculation process */
+ class DeltaInfo {
+ PackageInfo[] addedPkgs;
+ PackageInfo[] removedPkgs;
+ PackageInfo[] changedPkgs;
+ };
+
+ class PackageInfo {
+ IPackage pkg;
+ IType[] addedTypes;
+ IType[] removedTypes;
+ IType[] changedTypes;
+ IType[] changedBinaries;
+ };
+
+ /* shared empty array */
+ protected static final IDelta[] fgEmptyArray = new IDelta[0];
+
+ protected IncrementalImageBuilder fIncrementalBuilder;
+
+ static final int PS_CHANGED = 1; // has the principal structure changed?
+ static final int BIN_CHANGED = 2; // has the binary changed?
+
+ /**
+ * Creates a new root image delta
+ */
+ DeltaImpl(IncrementalImageBuilder builder, IImageContext context) {
+ this(builder.getOldState(), builder.getNewState(), context, builder);
+ }
+
+ /**
+ * Creates a new root image delta
+ */
+ protected DeltaImpl(
+ StateImpl oldState,
+ StateImpl newState,
+ String name,
+ Object o,
+ DeltaKey key,
+ IDelta parent,
+ int status) {
+
+ fNewState = (StateImpl) newState;
+ fOldState = (StateImpl) oldState;
+ fName = name;
+ fObject = o;
+ fParent = parent;
+ fKey = key;
+ fStatus = status;
+ fChildren = fgEmptyArray;
+ fContext = parent.getImageContext();
+ }
+
+ /**
+ * Creates a new root image delta
+ */
+ DeltaImpl(IState oldState, IState newState, IImageContext context) {
+ this(oldState, newState, context, null);
+ }
+
+ /**
+ * Creates a new root image delta
+ */
+ DeltaImpl(
+ IState oldState,
+ IState newState,
+ IImageContext context,
+ IncrementalImageBuilder builder) {
+ try {
+ fNewState = (StateImpl) newState;
+ fOldState = (StateImpl) oldState;
+ } catch (ClassCastException cce) {
+ Assert.isTrue(false, "Invalid states");
+ }
+ fStatus = CHANGED;
+ fName = fgImage;
+ fObject = newState.getDevelopmentContext().getImage();
+ fParent = null;
+ fKey = DeltaKey.getRoot();
+ fContext = context;
+ fChildren = fgEmptyArray;
+ fIncrementalBuilder = builder;
+ computeImageDelta();
+ }
+
+ /**
+ * Creates and returns a child with the given name and object
+ */
+ protected DeltaImpl add(String name, Object object, int status) {
+ return add(name, object, getKey().add(object), status);
+ }
+
+ /**
+ * Creates and returns a child with the given name and object
+ */
+ protected DeltaImpl add(String name, Object object, DeltaKey key, int status) {
+ return new DeltaImpl(fOldState, fNewState, //same states as me
+ name, object, key, //given name, object and key
+ this, //parent
+ status); //added, removed, or changed
+ }
+
+ /**
+ * Returns the child of this delta with the given object
+ */
+ protected IDelta at(Object o) {
+ Assert.isNotNull(fChildren, "navigating off a leaf delta!");
+ for (int i = 0; i < fChildren.length; i++) {
+ if (o instanceof String) {
+ if (o.equals(fChildren[i].getName())) {
+ return fChildren[i];
+ }
+ } else {
+ if (o.equals(fChildren[i].getObject())) {
+ return fChildren[i];
+ }
+ }
+ }
+ /* not found */
+ return null;
+ }
+
+ /**
+ * Compares the type in the old and new states.
+ * Returns a bit mask indicating whether the principal structure or binary have changed.
+ */
+ protected int compareBuilderType(BuilderType type) {
+
+ if (!type.isAffected()) {
+ return 0;
+ }
+
+ TypeStructureEntry oldEntry = type.getOldTypeStructureEntry();
+ TypeStructureEntry newEntry = type.getNewTypeStructureEntry();
+ if (oldEntry == null || newEntry == null) {
+ return PS_CHANGED | BIN_CHANGED;
+ }
+ if (oldEntry == newEntry) {
+ return 0;
+ }
+
+ int result = 0;
+
+ IBinaryType oldType = type.getOldBinaryType();
+ IBinaryType newType = type.getNewBinaryType();
+
+ if (!BinaryStructure.compare(oldType, newType)) {
+ result |= PS_CHANGED;
+ }
+ /*
+ * If the source entry has changed, consider the binary to have changed
+ * even if the binary is actually the same. Some clients, such as the
+ * target manager, need to know when the source changes.
+ */
+ if (!oldEntry.getSourceEntry().equals(newEntry.getSourceEntry())) {
+ result |= BIN_CHANGED;
+ } else
+ if (oldEntry.getCRC32() != newEntry.getCRC32()) {
+ result |= BIN_CHANGED;
+ } else {
+ boolean oldIsBinary = oldEntry.isBinary();
+ boolean newIsBinary = newEntry.isBinary();
+ if (oldIsBinary != newIsBinary) {
+ result |= BIN_CHANGED;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns an integer indicating whether anotherDelta is less than, equal to,
+ * or greater than this delta.
+ */
+ public int compareTo(IDelta anotherDelta) {
+ /* is this used? */
+ Assert.isTrue(false, "TBD");
+ return 0;
+ }
+
+ /**
+ * Compares the type in the old and new states.
+ * Returns a bit mask indicating whether the principal structure or binary have changed.
+ */
+ protected int compareTypes(IType handle) {
+ if (fIncrementalBuilder != null) {
+ return compareBuilderType(fIncrementalBuilder.getBuilderType(handle));
+ }
+
+ TypeStructureEntry oldEntry = fOldState.getTypeStructureEntry(handle, true);
+ TypeStructureEntry newEntry = fNewState.getTypeStructureEntry(handle, true);
+ if (oldEntry == null || newEntry == null) {
+ return PS_CHANGED | BIN_CHANGED;
+ }
+ if (oldEntry == newEntry) {
+ return 0;
+ }
+ int result = 0;
+
+ IBinaryType oldType = fOldState.getBinaryType(oldEntry);
+ IBinaryType newType = fNewState.getBinaryType(newEntry);
+
+ if (!BinaryStructure.compare(oldType, newType)) {
+ result |= PS_CHANGED;
+ }
+ /*
+ * If the source entry has changed, consider the binary to have changed
+ * even if the binary is actually the same. Some clients, such as the
+ * target manager, need to know when the source changes.
+ */
+ if (!oldEntry.getSourceEntry().equals(newEntry.getSourceEntry())) {
+ result |= BIN_CHANGED;
+ } else
+ if (oldEntry.getCRC32() != newEntry.getCRC32()) {
+ result |= BIN_CHANGED;
+ } else {
+ boolean oldIsBinary = oldEntry.isBinary();
+ boolean newIsBinary = newEntry.isBinary();
+ if (oldIsBinary != newIsBinary) {
+ result |= BIN_CHANGED;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Computes the added classes for each added package.
+ * Returns a DeltaInfo object for each package describing the affected
+ * classes.
+ */
+ protected PackageInfo[] computeAddedClasses(Vector pkgs) {
+
+ PackageInfo[] infos = new PackageInfo[pkgs.size()];
+ int i = 0;
+
+ for (Enumeration pkgEnum = pkgs.elements(); pkgEnum.hasMoreElements(); i++) {
+ IPackage pkg = (IPackage) pkgEnum.nextElement();
+ infos[i] = new PackageInfo();
+ infos[i].pkg = pkg;
+ IType[] types = ((IPackage) pkg.inState(fNewState)).getAllClasses();
+ for (int j = 0; j < types.length; ++j) {
+ types[j] = (IType) types[j].nonStateSpecific();
+ }
+ infos[i].addedTypes = types;
+ } //next package
+
+ return infos;
+ } //end function
+
+ /**
+ * Computes added, removed, and changed classes for a set of packages.
+ * Stores vectors of IType handles.
+ */
+ protected void computeAllClasses(
+ IPackage pkg,
+ Vector added,
+ Vector removed,
+ Vector changedTypes,
+ Vector changedBinaries) {
+
+ /* collect a set of all classes in old package */
+ /* we have to make a copy here to avoid destroying the state */
+ Hashtable oldTypeTable = new Hashtable();
+ IType[] oldTypes = ((IPackage) pkg.inState(fOldState)).getAllClasses();
+ for (int i = 0; i < oldTypes.length; i++) {
+ IType handle = (IType) oldTypes[i].nonStateSpecific();
+ oldTypeTable.put(handle, handle);
+ }
+
+ /* iterate through new classes */
+ IType[] newTypes = ((IPackage) pkg.inState(fNewState)).getAllClasses();
+ for (int i = 0; i < newTypes.length; i++) {
+ IType handle = (IType) newTypes[i].nonStateSpecific();
+ if (oldTypeTable.remove(handle) != null) {
+ /* class is in both packages */
+ int code = compareTypes(handle);
+ if ((code & PS_CHANGED) != 0) {
+ changedTypes.addElement(handle);
+ }
+ if ((code & BIN_CHANGED) != 0) {
+ changedBinaries.addElement(handle);
+ }
+ } else {
+ /* its only in the new package */
+ added.addElement(handle);
+ }
+ }
+
+ /* remaining classes are removed */
+ for (Enumeration e = oldTypeTable.keys(); e.hasMoreElements();) {
+ removed.addElement(e.nextElement());
+ }
+ }
+
+ /**
+ * Computes added, removed, and changed packages. At this
+ * stage, if a package hasn't been added or removed, it is
+ * considered to be changed. Later, when the classes are
+ * calculated, the packages that don't have changed classes
+ * will be removed from the list. Stores vectors of non-state
+ * specific package handles.
+ */
+ protected void computeAllPackages(
+ Vector added,
+ Vector removed,
+ Vector changed) {
+
+ /* do for each affected package */
+ for (Enumeration e = getAffectedPackages(); e.hasMoreElements();) {
+ IPackage pkg = (IPackage) e.nextElement();
+ boolean inOld = pkg.inState(fOldState).isPresent();
+ boolean inNew = pkg.inState(fNewState).isPresent();
+ if (inOld) {
+ if (inNew) {
+ changed.addElement(pkg);
+ } else {
+ // Package was removed.
+ removed.addElement(pkg);
+ }
+ } else {
+ if (inNew) {
+ // Package was added.
+ added.addElement(pkg);
+ } else {
+ // Package was in image context but was not in either state.
+ // Ignore it.
+ }
+ }
+ }
+ }
+
+ /**
+ * Computes added, removed, and changed classes for a set of packages.
+ * Returns a DeltaInfo object for each package describing the affected
+ * classes.
+ */
+ protected PackageInfo[] computeChangedClasses(Vector pkgs) {
+
+ Vector vInfo = new Vector();
+ Vector toRemove = new Vector();
+
+ for (Enumeration pkgEnum = pkgs.elements(); pkgEnum.hasMoreElements();) {
+ IPackage pkg = (IPackage) pkgEnum.nextElement();
+
+ Vector vAdded = new Vector();
+ Vector vRemoved = new Vector();
+ Vector vChanged = new Vector();
+ Vector vBinaries = new Vector();
+ computeAllClasses(pkg, vAdded, vRemoved, vChanged, vBinaries);
+
+ /* if there are any affected classes */
+ if (vAdded.size() + vRemoved.size() + vChanged.size() + vBinaries.size() > 0) {
+
+ /* fill out package information */
+ PackageInfo pkgInfo = new PackageInfo();
+ pkgInfo.pkg = pkg;
+
+ pkgInfo.addedTypes = new IType[vAdded.size()];
+ vAdded.copyInto(pkgInfo.addedTypes);
+
+ pkgInfo.removedTypes = new IType[vRemoved.size()];
+ vRemoved.copyInto(pkgInfo.removedTypes);
+
+ pkgInfo.changedTypes = new IType[vChanged.size()];
+ vChanged.copyInto(pkgInfo.changedTypes);
+
+ pkgInfo.changedBinaries = new IType[vBinaries.size()];
+ vBinaries.copyInto(pkgInfo.changedBinaries);
+
+ vInfo.addElement(pkgInfo);
+ } else {
+ /* remove the element -- can't delete while enumerating */
+ toRemove.addElement(pkg);
+ }
+ } //next package
+
+ /* remove packages with no changes */
+ for (Enumeration e = toRemove.elements(); e.hasMoreElements();) {
+ pkgs.removeElement(e.nextElement());
+ }
+
+ Assert.isTrue(vInfo.size() == pkgs.size(), "sanity check");
+
+ /* convert info vector to array */
+ PackageInfo[] infos = new PackageInfo[vInfo.size()];
+ vInfo.copyInto(infos);
+ return infos;
+ } //end function
+
+ /**
+ * Calculates the added, removed, and changed packages, types and methods
+ * that consitute an image delta. The results are stored in the supplied
+ * DeltaInfo object
+ */
+ protected DeltaInfo computeDeltaInfo() {
+ DeltaInfo info = new DeltaInfo();
+
+ /* compute packages */
+ Vector vAddedPkgs = new Vector();
+ Vector vRemovedPkgs = new Vector();
+ Vector vChangedPkgs = new Vector();
+ computeAllPackages(vAddedPkgs, vRemovedPkgs, vChangedPkgs);
+
+ /* compute classes */
+ info.addedPkgs = computeAddedClasses(vAddedPkgs);
+ info.removedPkgs = computeRemovedClasses(vRemovedPkgs);
+ info.changedPkgs = computeChangedClasses(vChangedPkgs);
+
+ return info;
+ }
+
+ /**
+ * Computes the image delta.
+ */
+ protected void computeImageDelta() {
+
+ /* compute the delta info */
+ DeltaInfo info = computeDeltaInfo();
+
+ /* create categories, any or all of them may be null */
+ IDelta pkgCategory = createPackageCategory(this, info);
+ IDelta typeCategory = createCategory(this, info, fgTypeCategory);
+ IDelta binaryCategory = createCategory(this, info, fgBinaryCategory);
+
+ /* Create top level children */
+ int childCount = 0;
+ if (pkgCategory != null)
+ childCount++;
+ if (typeCategory != null)
+ childCount++;
+ if (binaryCategory != null)
+ childCount++;
+
+ fChildren = new IDelta[childCount];
+ childCount = 0;
+ if (pkgCategory != null)
+ fChildren[childCount++] = pkgCategory;
+ if (typeCategory != null)
+ fChildren[childCount++] = typeCategory;
+ if (binaryCategory != null)
+ fChildren[childCount++] = binaryCategory;
+ }
+
+ /**
+ * Computes the removed classes for each removed package.
+ * Returns a DeltaInfo object for each package describing the affected
+ * classes.
+ */
+ protected PackageInfo[] computeRemovedClasses(Vector pkgs) {
+
+ PackageInfo[] infos = new PackageInfo[pkgs.size()];
+ int i = 0;
+
+ for (Enumeration pkgEnum = pkgs.elements(); pkgEnum.hasMoreElements(); i++) {
+ IPackage pkg = (IPackage) pkgEnum.nextElement();
+ infos[i] = new PackageInfo();
+ infos[i].pkg = pkg;
+ IType[] types = ((IPackage) pkg.inState(fOldState)).getAllClasses();
+ for (int j = 0; j < types.length; ++j) {
+ types[j] = (IType) types[j].nonStateSpecific();
+ }
+ infos[i].removedTypes = types;
+ } //next package
+
+ return infos;
+ } //end function
+
+ /**
+ * Converts a vector of handles to an array of delta info objects of the given
+ * type.
+ */
+ protected IDelta[] convertHandlesToDeltaArray(
+ Vector vHandles,
+ String type,
+ int status) {
+
+ int i = 0;
+ IDelta[] results = new IDelta[vHandles.size()];
+ for (Enumeration e = vHandles.elements(); e.hasMoreElements(); i++) {
+ results[i] = add(type, e.nextElement(), status);
+ }
+ return results;
+ }
+
+ /**
+ * Copies information from a PackageInfo to the children of a DeltaImpl.
+ * If types is true, copy the type information, otherwise copy the binary information
+ */
+ protected void copyInfoToChildren(
+ DeltaImpl delta,
+ PackageInfo info,
+ boolean types) {
+
+ /* are we looking at binaries or types ? */
+ IType[] changed = types ? info.changedTypes : info.changedBinaries;
+ String name = types ? fgType : fgBinary;
+
+ int count = info.addedTypes.length + info.removedTypes.length + changed.length;
+ if (count == 0) {
+ delta.fStatus = SAME;
+ delta.setChildren(new IDelta[0]);
+ return;
+ }
+ IDelta[] children = new IDelta[count];
+ int i = 0;
+ for (; i < info.addedTypes.length; i++) {
+ children[i] = delta.add(name, info.addedTypes[i], ADDED);
+ }
+ for (int j = 0; j < info.removedTypes.length; j++, i++) {
+ children[i] = delta.add(name, info.removedTypes[j], REMOVED);
+ }
+ for (int j = 0; j < changed.length; j++, i++) {
+ children[i] = delta.add(name, changed[j], CHANGED);
+ }
+ delta.setChildren(children);
+ }
+
+ /**
+ * Creates the types category of the image delta. Returns
+ * the Delta object for the category. If there are no added,
+ * removed, or changed types, returns null.
+ */
+ protected IDelta createCategory(
+ DeltaImpl parent,
+ DeltaInfo info,
+ String categoryName) {
+
+ int size =
+ info.changedPkgs.length + info.addedPkgs.length + info.removedPkgs.length;
+ if (size == 0)
+ return null;
+
+ /* collection of packages that are children of the type category */
+ IDelta[] children = new IDelta[size];
+
+ /* create Type category node */
+ DeltaImpl category =
+ parent.add(
+ categoryName,
+ parent.getObject(),
+ parent.getKey().add(categoryName),
+ CHANGED);
+
+ /* create new deltas for changed packages */
+ int count = 0;
+ for (int i = 0; i < info.changedPkgs.length; i++) {
+ PackageInfo pkgInfo = info.changedPkgs[i];
+ DeltaImpl child = (DeltaImpl) category.add(fgPackage, pkgInfo.pkg, CHANGED);
+ copyInfoToChildren(child, pkgInfo, categoryName == fgTypeCategory);
+ children[count++] = child;
+ }
+
+ /* create deltas for added and removed packages */
+ for (int i = 0; i < info.addedPkgs.length; i++) {
+ children[count++] = category.packageForTypeCategory(ADDED, info.addedPkgs[i]);
+ }
+ for (int i = 0; i < info.removedPkgs.length; i++) {
+ children[count++] =
+ category.packageForTypeCategory(REMOVED, info.removedPkgs[i]);
+ }
+
+ category.setChildren(children);
+ return category;
+ }
+
+ /**
+ * Creates the package category of the image delta. Returns
+ * the Delta object for the category. If there are no added,
+ * removed, or changed packages, returns null. A changed package
+ * is a package that has had a package fragment added or removed.
+ */
+ protected IDelta createPackageCategory(DeltaImpl parent, DeltaInfo info) {
+
+ /* number of children of this category */
+ int size =
+ info.addedPkgs.length + info.changedPkgs.length + info.removedPkgs.length;
+ if (size == 0)
+ return null;
+
+ /* create the category */
+ DeltaImpl category =
+ parent.add(
+ fgPackageCategory,
+ parent.getObject(),
+ parent.getKey().add(fgPackageCategory),
+ CHANGED);
+
+ IDelta[] children = new IDelta[size];
+ int count = 0;
+ for (int i = 0; i < info.addedPkgs.length; i++) {
+ children[count++] = category.add(fgPackage, info.addedPkgs[i].pkg, ADDED);
+ }
+ for (int i = 0; i < info.removedPkgs.length; i++) {
+ children[count++] = category.add(fgPackage, info.removedPkgs[i].pkg, REMOVED);
+ }
+ for (int i = 0; i < info.changedPkgs.length; i++) {
+ IPackage pkg = info.changedPkgs[i].pkg;
+ if (!Util
+ .equalArraysOrNull(
+ fOldState.getPackageMap().getFragments(pkg),
+ fNewState.getPackageMap().getFragments(pkg))) {
+ children[count++] = category.add(fgPackage, pkg, CHANGED);
+ }
+ }
+
+ /* there could be no changed packages */
+ if (count == 0) {
+ return null;
+ }
+
+ /* compact if some changed packages did not actually change */
+ if (count < children.length) {
+ System.arraycopy(children, 0, children = new IDelta[count], 0, count);
+ }
+ category.setChildren(children);
+ return category;
+ }
+
+ public void dump() {
+ dump(this, 0);
+ }
+
+ protected static void dump(IDelta delta, int depth) {
+ for (int i = 0; i < depth; ++i)
+ System.out.print(" ");
+ System.out.println(delta);
+ IDelta[] children = delta.getAffectedSubdeltas();
+ for (int i = 0; i < children.length; ++i) {
+ dump(children[i], depth + 1);
+ }
+ }
+
+ /**
+ * Returns the delta reached by navigating the given
+ * relative path from this object.
+ * It is an error if the delta could never have such a descendent.
+ * <pre>
+ * - navigation off a checklist with the wrong child name
+ * is always bad
+ * - navigation off a batch delta is common when you don't
+ * yet know whether the object is present; this is allowed
+ * - navigation off a leaf delta is always bad
+ * </pre>
+ *
+ * @param path the path to follow
+ * @exception InvalidKeyException if an invalid key is given.
+ */
+ public IDelta follow(IDeltaKey path) throws InvalidKeyException {
+ IDelta delta = this;
+ for (int i = 0, size = path.size(); i < size; ++i) {
+ delta = ((DeltaImpl) delta).at(path.at(i));
+ if (delta == null) {
+ throw new InvalidKeyException();
+ }
+ }
+ return delta;
+ }
+
+ /**
+ * Returns the immediate subdeltas of this delta that are additions
+ * (i.e. their status is Added).
+ */
+ public IDelta[] getAddedSubdeltas() {
+ if (fChildren == null)
+ return fgEmptyArray;
+ Vector vAdded = new Vector();
+ for (int i = 0; i < fChildren.length; i++) {
+ if (fChildren[i].getStatus() == IDelta.ADDED) {
+ vAdded.addElement(fChildren[i]);
+ }
+ }
+ IDelta[] added = new IDelta[vAdded.size()];
+ vAdded.copyInto(added);
+ return added;
+ }
+
+ /**
+ * Returns an enumeration of packages which are possibly affected.
+ */
+ public Enumeration getAffectedPackages() {
+ /* Non-naive case - the image builder knows. */
+ if (fIncrementalBuilder != null) {
+ return fIncrementalBuilder.getAffectedPackages();
+ }
+
+ /* Naive case - take union of packages in old and new state. */
+ Hashtable affected = new Hashtable(21);
+ for (Enumeration e = fOldState.getPackageMap().getAllPackages();
+ e.hasMoreElements();
+ ) {
+ IPackage pkg = (IPackage) e.nextElement();
+ affected.put(pkg, pkg);
+ }
+ for (Enumeration e = fNewState.getPackageMap().getAllPackages();
+ e.hasMoreElements();
+ ) {
+ IPackage pkg = (IPackage) e.nextElement();
+ affected.put(pkg, pkg);
+ }
+ return affected.keys();
+ }
+
+ /**
+ * Returns the immediate subdeltas of this delta that are
+ * not the same (i.e. their status is either Added, Removed, or Changed).
+ */
+ public IDelta[] getAffectedSubdeltas() {
+ if (fChildren == null)
+ return fgEmptyArray;
+ Vector vAffected = new Vector();
+ for (int i = 0; i < fChildren.length; i++) {
+ if (fChildren[i].getStatus() != IDelta.SAME) {
+ vAffected.addElement(fChildren[i]);
+ }
+ }
+ IDelta[] affected = new IDelta[vAffected.size()];
+ vAffected.copyInto(affected);
+ return affected;
+ }
+
+ /**
+ * Returns the immediate subdeltas of this delta that are true
+ * changes, not additions or removals (i.e. their status is Changed).
+ */
+ public IDelta[] getChangedSubdeltas() {
+ if (fChildren == null)
+ return fgEmptyArray;
+ Vector vChanged = new Vector();
+ for (int i = 0; i < fChildren.length; i++) {
+ if (fChildren[i].getStatus() == IDelta.CHANGED) {
+ vChanged.addElement(fChildren[i]);
+ }
+ }
+ IDelta[] changed = new IDelta[vChanged.size()];
+ vChanged.copyInto(changed);
+ return changed;
+ }
+
+ /**
+ * Returns the ImageContext that the delta is restricted to.
+ *
+ * @see IImageBuilder#getImageDelta
+ */
+ public IImageContext getImageContext() {
+ return fContext;
+ }
+
+ /**
+ * Returns the delta key for this delta.
+ * Delta keys often contain non-state-specific handles, but
+ * never state-specific ones.
+ *
+ * @see DeltaKey
+ */
+ public IDeltaKey getKey() {
+ return fKey;
+ }
+
+ /**
+ * Returns the name of the aspect being compared in this delta.
+ */
+ public String getName() {
+ return fName;
+ }
+
+ /**
+ * Returns the object in the new state that is the focus of this delta.
+ * It only make sense to talk about the 'new object' if the object
+ * that is the focus of this delta is a Handle. If it is not, this
+ * returns null.
+ *
+ * @return the state-specific handle of the object in the new state.
+ */
+ public IHandle getNewObject() {
+ IHandle handle;
+ try {
+ handle = (IHandle) fObject;
+ } catch (ClassCastException cce) {
+ //not a handle
+ return null;
+ }
+ return handle.inState(fNewState);
+ }
+
+ /**
+ * Returns the new state to which this delta pertains.
+ */
+ public IState getNewState() {
+ return fNewState;
+ }
+
+ /**
+ * Returns the object that is the focus of this delta.
+ * The result is often a Handle, but in
+ * some cases it is another type of object.
+ * When it is a Handle, it is non-state-specific.
+ */
+ public Object getObject() {
+ return fObject;
+ }
+
+ /**
+ * Returns the object in the old state that is the focus of this delta.
+ * It only make sense to talk about the 'old object' if the object
+ * that is the focus of this delta is a Handle. If it is not, this
+ * returns null.
+ *
+ * @return the state-specific handle of the object in the old state.
+ */
+ public IHandle getOldObject() {
+ IHandle handle;
+ try {
+ handle = (IHandle) fObject;
+ } catch (ClassCastException cce) {
+ //not a handle
+ return null;
+ }
+ return handle.inState(fOldState);
+ }
+
+ /**
+ * Returns the old state to which this delta pertains.
+ */
+ public org.eclipse.jdt.internal.core.builder.IState getOldState() {
+ return fOldState;
+ }
+
+ /**
+ * Returns the parent delta of this delta, or null if it has no parent.
+ */
+ public IDelta getParent() {
+ return fParent;
+ }
+
+ /**
+ * Returns the immediate subdeltas of this delta that are removals
+ * (i.e. their status is Removed).
+ */
+ public IDelta[] getRemovedSubdeltas() {
+ if (fChildren == null)
+ return fgEmptyArray;
+ Vector vRemoved = new Vector();
+ for (int i = 0; i < fChildren.length; i++) {
+ if (fChildren[i].getStatus() == IDelta.REMOVED) {
+ vRemoved.addElement(fChildren[i]);
+ }
+ }
+ IDelta[] removed = new IDelta[vRemoved.size()];
+ vRemoved.copyInto(removed);
+ return removed;
+ }
+
+ /**
+ * Returns the root delta of the tree containing this delta.
+ */
+ public IDelta getRoot() {
+ /* don't bother caching the root at each branch for now */
+ if (fKey == DeltaKey.getRoot()) {
+ return this;
+ } else {
+ return getParent().getRoot();
+ }
+ }
+
+ /**
+ * Returns the status of this delta. If this delta
+ * is not applicable, it always returns SAME.
+ * If the status is not currently known, it is computed
+ * (UNKNOWN is never returned).
+ */
+ public int getStatus() {
+ return fStatus;
+ }
+
+ /**
+ * Returns the status of this delta if it is known.
+ * Returns UNKNOWN if it is not known whether the object has changed.
+ *
+ */
+ public int getStatusIfKnown() {
+ return fStatus;
+ }
+
+ /**
+ * Returns an array of Delta objects that are children of this delta.
+ * Returns an array of length 0 if this delta has no children,
+ * or if it is not composite.
+ */
+ public IDelta[] getSubdeltas() {
+ return fChildren;
+ }
+
+ /**
+ * Returns whether this delta is a composite delta that is further
+ * broken down into subdeltas.
+ */
+ public boolean hasSubdeltas() {
+ return fChildren != null && fChildren.length > 0;
+ }
+
+ /**
+ * Creates a package delta for the types or binaries category.
+ * The package delta can be for either an added or removed package,
+ * according to the constant given. The package delta will have
+ * children for each type in the package.
+ */
+ protected IDelta packageForTypeCategory(int status, PackageInfo info) {
+
+ /* create the package delta */
+ DeltaImpl pkgDelta = (DeltaImpl) this.add(fgPackage, info.pkg, status);
+
+ IType[] types = (status == ADDED ? info.addedTypes : info.removedTypes);
+ IDelta[] children = new IDelta[types.length];
+ for (int i = 0; i < types.length; i++) {
+ children[i] = pkgDelta.add(fgType, types[i], status);
+ }
+ pkgDelta.setChildren(children);
+ return pkgDelta;
+ }
+
+ /**
+ * Sets the children of this delta
+ */
+ protected void setChildren(IDelta[] children) {
+ fChildren = children;
+ }
+
+ /**
+ * Return a string of the form:
+ * status key
+ *
+ * status will be one of the following:
+ * + if status is ADDED
+ * - if status is REMOVED
+ * * if status is CHANGED
+ * = if status is SAME
+ * ? if status is UNKNOWN
+ * The string returned is only for debugging purposes,
+ * and the contents of the string may change in the future.
+ * @return java.lang.String
+ */
+ public String toString() {
+ StringBuffer sb = new StringBuffer("DeltaImpl(");
+ switch (fStatus) {
+ case ADDED :
+ sb.append("+");
+ break;
+ case REMOVED :
+ sb.append("-");
+ break;
+ case CHANGED :
+ sb.append("*");
+ break;
+ case SAME :
+ sb.append("=");
+ break;
+ case UNKNOWN :
+ sb.append("?");
+ break;
+ default :
+ sb.append("(ERROR)");
+ }
+ if (fKey.isRoot()) {
+ sb.append(fOldState);
+ sb.append("-->");
+ sb.append(fNewState);
+ } else {
+ for (int i = 0; i < fKey.size(); ++i) {
+ if (i != 0) {
+ sb.append('/');
+ }
+ sb.append(fKey.at(i));
+ }
+ }
+ sb.append(')');
+ return sb.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/DependencyGraph.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/DependencyGraph.java
new file mode 100644
index 0000000000..7c8e04ca6b
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/DependencyGraph.java
@@ -0,0 +1,614 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IPath;
+
+import org.eclipse.jdt.internal.core.Assert;
+import org.eclipse.jdt.internal.core.builder.*;
+import org.eclipse.jdt.internal.core.util.*;
+
+import java.util.*;
+
+/**
+ * An explicit graph of dependencies between source elements and packages
+ * in the state.
+ */
+public class DependencyGraph implements IDumpable, Cloneable {
+ /**
+ * Maps ICompilationUnits to INodes in the dependency graph
+ */
+ private LookupTable fCompilationUnits;
+
+ /**
+ * Maps IPackages to INodes in the dependency graph
+ */
+ private LookupTable fNamespaces;
+
+ /**
+ * Maps ITypes to INodes in the graph
+ */
+ private LookupTable fTypes;
+
+ /**
+ * Maps Strings (filenames) to INodes in the graph
+ */
+ private LookupTable fZips;
+ /**
+ * DependencyGraph constructor comment.
+ */
+ public DependencyGraph() {
+ fNamespaces = new LookupTable(11);
+ fCompilationUnits = new LookupTable(11);
+ fTypes = new LookupTable(11);
+ fZips = new LookupTable(11);
+ }
+
+ /**
+ * Creates a node for the object. Returns the added node.
+ */
+ public INode add(Object element) {
+
+ INode node = getNodeFor(element);
+ // force creation of a node for the package
+ if (element instanceof PackageElement) {
+ getNodeFor(((PackageElement) element).getPackage());
+ }
+ return node;
+ }
+
+ /**
+ * Add the compilation unit, its dependencies, and any other relevant info
+ * from the compilation result to the graph.
+ * The compilation unit has just been compiled, so its status is COMPILED.
+ */
+ public void add(
+ PackageElement resultUnit,
+ IType[] types,
+ Vector vDependencies) {
+
+ // force the package node if not yet present
+ getNodeFor(resultUnit.getPackage());
+
+ JCUNode unitNode = (JCUNode) getNodeFor(resultUnit);
+ unitNode.setTypes(types);
+ INode node = unitNode;
+
+ // convert dependencies to INodes
+ INode[] deps = new INode[vDependencies.size()];
+ int count = 0;
+ for (Enumeration e = vDependencies.elements(); e.hasMoreElements();) {
+ Object o = e.nextElement();
+ INode depNode = getNodeFor(o);
+ deps[count++] = depNode;
+ }
+ node.setDependencies(deps);
+ }
+
+ /**
+ * Returns a copy of the dependency graph with all counters and flags reset
+ */
+ protected Object clone() {
+ try {
+ DependencyGraph newGraph = (DependencyGraph) super.clone();
+
+ /* First pass: copy tables and all nodes,
+ * leaving dependencies and dependents pointing to old nodes. */
+ newGraph.fNamespaces = copyTableAndNodesWithoutReplacingDeps(fNamespaces);
+ newGraph.fCompilationUnits =
+ copyTableAndNodesWithoutReplacingDeps(fCompilationUnits);
+ newGraph.fTypes = copyTableAndNodesWithoutReplacingDeps(fTypes);
+ newGraph.fZips = copyTableAndNodesWithoutReplacingDeps(fZips);
+
+ /* Second pass: replace dependencies and dependents to point to new nodes. */
+ replaceDeps(newGraph.fNamespaces, newGraph);
+ replaceDeps(newGraph.fCompilationUnits, newGraph);
+ replaceDeps(newGraph.fTypes, newGraph);
+ replaceDeps(newGraph.fZips, newGraph);
+
+ return newGraph;
+ } catch (CloneNotSupportedException e) {
+ // Should not happen since we implement Cloneable
+ Assert.isTrue(false, "Unexpected clone exception in DependencyGraph.clone()");
+ return null;
+ }
+ }
+
+ /**
+ * Returns a copy of the dependency graph with all counters and flags reset
+ */
+ public DependencyGraph copy() {
+ //this.integrityCheck();
+ DependencyGraph newGraph = (DependencyGraph) this.clone();
+ //newGraph.integrityCheck();
+ return newGraph;
+ }
+
+ /**
+ * Copies the edges from an old node to a new node. Any nodes that have
+ * to be created are added to the graph.
+ */
+ protected void copyEdges(INode oldNode, INode newNode) {
+
+ /* copy dependencies */
+ INode[] oldDeps = oldNode.getDependencies();
+ INode[] newDeps = new INode[oldDeps.length];
+
+ /* create nodes in the new graph for each dependency in the old graph */
+ for (int i = oldDeps.length; --i >= 0;) {
+ newDeps[i] = getNodeFor(oldDeps[i]);
+ }
+ newNode.setDependencies(newDeps);
+
+ /**
+ * Don't have to add dependents, because dependents
+ * will add newNode as a dependency, creating both directional links
+ */
+ }
+
+ /**
+ * Returns a copy of a table of nodes, with copies of the nodes,
+ * but with their dependencies and dependents not copied.
+ */
+ private static LookupTable copyTableAndNodesWithoutReplacingDeps(LookupTable oldTable) {
+ LookupTable newTable = (LookupTable) oldTable.clone();
+ for (Enumeration e = oldTable.elements(); e.hasMoreElements();) {
+ AbstractNode node = (AbstractNode) e.nextElement();
+ newTable.put(node.getElement(), node.copyWithoutReplacingDeps());
+ }
+ return newTable;
+ }
+
+ /**
+ * Deletes the node in this graph corresponding to the given object,
+ * and answers it if found, or null if it wasn't found.
+ * The node must not have any dependents.
+ */
+ public INode deleteNode(Object o) {
+ INode toRemove = getNodeFor(o, false);
+ if (toRemove != null) {
+ deleteNode(toRemove);
+ }
+ return toRemove;
+ }
+
+ /**
+ * Deletes the node in this graph corresponding to the given object,
+ * and answers it if found, or null if it wasn't found.
+ * The node must not have any dependents.
+ */
+ INode deleteNode(INode toRemove) {
+ Assert.isTrue(toRemove.getDependents().length == 0);
+ Object value = null;
+ switch (toRemove.getKind()) {
+ case INode.JCU_NODE :
+ value = fCompilationUnits.remove(((JCUNode) toRemove).getPackageElement());
+ break;
+ case INode.TYPE_NODE :
+ value = fTypes.remove(((TypeNode) toRemove).getPackageElement());
+ break;
+ case INode.NAMESPACE_NODE :
+ value = fNamespaces.remove(((NamespaceNode) toRemove).getPackage());
+ break;
+ case INode.ZIP_NODE :
+ value = fZips.remove(((ZipNode) toRemove).getZipFile());
+ break;
+ default :
+ Assert.isTrue(
+ false,
+ "Attempt to delete unknown node type from dependency graph");
+ }
+ return (INode) value;
+ }
+
+ /**
+ * For debugging only. Dump the graph in readable form.
+ */
+ public void dump(Dumper dumper) {
+ dumper.dumpMessage("Namespaces", "");
+ dumper.indent();
+ for (Enumeration e = fNamespaces.elements(); e.hasMoreElements();) {
+ AbstractNode node = (AbstractNode) e.nextElement();
+ dumper.dump(node);
+ }
+ dumper.outdent();
+
+ dumper.dumpMessage("JCUs", "");
+ dumper.indent();
+ for (Enumeration e = fCompilationUnits.elements(); e.hasMoreElements();) {
+ AbstractNode node = (AbstractNode) e.nextElement();
+ dumper.dump(node);
+ }
+ dumper.outdent();
+
+ dumper.dumpMessage("ZIPs", "");
+ dumper.indent();
+ for (Enumeration e = fZips.elements(); e.hasMoreElements();) {
+ AbstractNode node = (AbstractNode) e.nextElement();
+ dumper.dump(node);
+ }
+ dumper.outdent();
+ }
+
+ /**
+ * Debugging - Force the order counts.
+ */
+ public void forceOrders() {
+ for (Enumeration e = fCompilationUnits.elements(); e.hasMoreElements();) {
+ AbstractNode node = (AbstractNode) e.nextElement();
+ node.getOrder();
+ }
+ }
+
+ /**
+ * Returns the elements which directly depend on the given element.
+ */
+ public Object[] getDependents(Object element) {
+ INode node = getNodeFor(element, false);
+ if (node == null) {
+ return new Object[0];
+ }
+ INode[] dependentNodes = node.getDependents();
+ Object[] dependents = new Object[dependentNodes.length];
+ for (int i = 0; i < dependents.length; ++i) {
+ dependents[i] = dependentNodes[i].getElement();
+ }
+ return dependents;
+ }
+
+ /**
+ * Returns the number of bytes that the nodes of the dependency graph use.
+ * For debugging and profiling purposes only.
+ */
+ public int getFootprint() {
+ int size = 0;
+ size += getFootprint(fCompilationUnits);
+ size += getFootprint(fNamespaces);
+ size += getFootprint(fTypes);
+ size += getFootprint(fZips);
+ return size;
+ }
+
+ /**
+ * Returns the number of bytes that the nodes of the dependency graph use.
+ * For debugging and profiling purposes only.
+ */
+ public int getFootprint(Dictionary table) {
+ int size = 0;
+ for (Enumeration e = table.elements(); e.hasMoreElements();) {
+ AbstractNode node = (AbstractNode) e.nextElement();
+ size += node.getFootprint();
+ }
+ return size;
+ }
+
+ /**
+ * Returns the JCU nodes in the graph.
+ */
+ public Enumeration getJCUNodes() {
+ return fCompilationUnits.elements();
+ }
+
+ /**
+ * Returns the packages this source element is directly dependent on.
+ */
+ public IPackage[] getNamespaceDependencies(Object element) {
+ INode node = getNodeFor(element, false);
+ if (node == null) {
+ return new IPackage[0];
+ }
+ Vector vPackages = new Vector();
+ INode[] dependencies = node.getDependencies();
+ for (int i = 0; i < dependencies.length; i++) {
+ if (dependencies[i].getKind() == INode.NAMESPACE_NODE) {
+ vPackages.addElement(((NamespaceNode) dependencies[i]).getPackage());
+ }
+ }
+
+ IPackage[] results = new IPackage[vPackages.size()];
+ vPackages.copyInto(results);
+ return results;
+ }
+
+ /**
+ * Returns a node in this graph corresponding to the given object.
+ * A new node is created if necessary.
+ */
+ public INode getNodeFor(Object o) {
+ return getNodeFor(o, true);
+ }
+
+ /**
+ * Returns a node in this graph corresponding to the given object.
+ * If create is true, the node is added if necessary.
+ */
+ public INode getNodeFor(Object o, boolean create) {
+ if (o instanceof PackageElement) {
+ return getNodeFor((PackageElement) o, create);
+ } else
+ if (o instanceof IPackage) {
+ return getNodeFor((IPackage) o, create);
+ } else
+ if (o instanceof IPath) {
+ return getNodeFor((IPath) o, create);
+ } else {
+ Assert.isTrue(false, "Unknown kind of node.");
+ return null;
+ }
+ }
+
+ /**
+ * Returns the node for a zip file. If create is true, the node is
+ * created if necessary.
+ */
+ public INode getNodeFor(IPath zipFile, boolean create) {
+
+ /* what about the namespaces for this zip?? */
+
+ INode zipNode = (INode) fZips.get(zipFile);
+ if (zipNode == null && create) {
+ zipNode = new ZipNode(zipFile);
+ fZips.put(zipFile, zipNode);
+ }
+ return zipNode;
+ }
+
+ /**
+ * Returns a node in this graph corresponding to the given node, which
+ * may be from another graph. A new node is created if necessary.
+ */
+ INode getNodeFor(INode node) {
+ return getNodeFor(node.getElement(), true);
+ }
+
+ /**
+ * Returns the node for the given compilation unit. The node
+ * is added if necessary.
+ */
+ public INode getNodeFor(PackageElement e) {
+ return getNodeFor(e, true);
+ }
+
+ /**
+ * Returns the node for the given package element.
+ * If create is true, the node is added if necessary.
+ * A package element may be a JCU, a class file, or a zip file.
+ * Class files are keyed by type handle, and zip files are keyed
+ * by the filename.
+ */
+ public INode getNodeFor(PackageElement e, boolean create) {
+ INode node;
+ if (e.isSource()) {
+ /* create a node for this unit if necessary */
+ node = (INode) fCompilationUnits.get(e);
+ if (node == null && create) {
+ node = new JCUNode(e);
+ fCompilationUnits.put(e, node);
+ }
+ } else {
+ node = (INode) fTypes.get(e);
+ if (node == null && create) {
+ node = new TypeNode(e);
+ fTypes.put(e, node);
+ }
+ }
+ return node;
+ }
+
+ /**
+ * Returns the node for a builder package. The node is
+ * created if necessary.
+ */
+ public INode getNodeFor(IPackage pkg) {
+ return getNodeFor(pkg, true);
+ }
+
+ /**
+ * Returns the node for a builder package. If create is true, the node is
+ * created if necessary.
+ */
+ public INode getNodeFor(IPackage pkg, boolean create) {
+
+ /* create the namespace if necessary */
+ INode pkgNode = (INode) fNamespaces.get(pkg);
+ if (pkgNode == null && create) {
+ pkgNode = new NamespaceNode(pkg);
+ fNamespaces.put(pkg, pkgNode);
+ }
+ return pkgNode;
+ }
+
+ /**
+ * Returns an enumeration over all nodes in the graph. Uses a composite
+ * enumerator to avoid copying all the elements.
+ */
+ public Enumeration getNodes() {
+ Vector v =
+ new Vector(
+ fNamespaces.size() + fTypes.size() + fCompilationUnits.size() + fZips.size());
+ for (Enumeration e = fNamespaces.elements(); e.hasMoreElements();) {
+ v.addElement(e.nextElement());
+ }
+ for (Enumeration e = fTypes.elements(); e.hasMoreElements();) {
+ v.addElement(e.nextElement());
+ }
+ for (Enumeration e = fCompilationUnits.elements(); e.hasMoreElements();) {
+ v.addElement(e.nextElement());
+ }
+ for (Enumeration e = fZips.elements(); e.hasMoreElements();) {
+ v.addElement(e.nextElement());
+ }
+ return v.elements();
+ }
+
+ /**
+ * Returns the topological order number of the given element.
+ */
+ public int getOrder(Object element) {
+ AbstractNode node = (AbstractNode) getNodeFor(element, true);
+ return node.getOrder();
+ }
+
+ /**
+ * Returns the types this source element is directly dependent on.
+ */
+ public IType[] getTypeDependencies(Object element) {
+ INode node = getNodeFor(element);
+ Vector vTypes = new Vector();
+ INode[] dependencies = node.getDependencies();
+ for (int i = 0; i < dependencies.length; i++) {
+ switch (dependencies[i].getKind()) {
+ case INode.JCU_NODE :
+ case INode.TYPE_NODE :
+ IType[] types = dependencies[i].getTypes();
+ for (int j = 0; j < types.length; ++j) {
+ vTypes.addElement(types[j]);
+ }
+ break;
+ }
+ }
+
+ IType[] results = new IType[vTypes.size()];
+ vTypes.copyInto(results);
+ return results;
+ }
+
+ /**
+ * Returns the types that belong to the given source element, or null
+ * if the element is not present.
+ */
+ public IType[] getTypes(Object element) {
+ // Need to create node if not present to properly handle
+ // binary types.
+ INode node = getNodeFor(element, true);
+ return node == null ? null : node.getTypes();
+ }
+
+ /**
+ * Returns a Vector of unused namespace nodes.
+ * That is, namespace nodes which have no dependents.
+ */
+ public Vector getUnusedNamespaceNodes() {
+ Vector v = new Vector();
+ for (Enumeration e = fNamespaces.elements(); e.hasMoreElements();) {
+ INode node = (INode) e.nextElement();
+ if (node.getDependents().length == 0) {
+ v.addElement(node);
+ }
+ }
+ return v;
+ }
+
+ /**
+ * For debugging only -- asserts graph integrity
+ */
+ public void integrityCheck() {
+ integrityCheck(fCompilationUnits);
+ integrityCheck(fTypes);
+ integrityCheck(fNamespaces);
+ }
+
+ /**
+ * For debugging only -- asserts graph integrity
+ */
+ public void integrityCheck(Dictionary table) {
+ String msg =
+ "Internal Error: the dependency graph is corrupt, do a full build to workaround error.";
+ for (Enumeration e = table.elements(); e.hasMoreElements();) {
+ AbstractNode node = (AbstractNode) e.nextElement();
+
+ /* do for each dependent of node */
+ INode[] nodesThatDependOnMe = node.getDependents();
+ for (int i = 0; i < nodesThatDependOnMe.length; i++) {
+ /* make sure current node is a dependency of the dependent node */
+ INode[] depDeps = nodesThatDependOnMe[i].getDependencies();
+ boolean found = false;
+ for (int j = depDeps.length; --j >= 0;) {
+ if (depDeps[j] == node) {
+ found = true;
+ }
+ }
+ Assert.isTrue(found, msg);
+ }
+
+ /* do for each dependency of node */
+ INode[] nodesThatIDependOn = node.getDependencies();
+ for (int i = 0; i < nodesThatIDependOn.length; i++) {
+ /* make sure current node is a dependent of the dependency node */
+ INode[] depDeps = nodesThatIDependOn[i].getDependents();
+ boolean found = false;
+ for (int j = depDeps.length; --j >= 0;) {
+ if (depDeps[j] == node) {
+ found = true;
+ }
+ }
+ Assert.isTrue(found, msg);
+ }
+ }
+ }
+
+ /**
+ * Remove the node for the given element, and mark all dependents
+ * as having to be recompiled, if they haven't been already.
+ * Returns true if the node was successfully removed, and false
+ * if the node could not be found.
+ */
+ public boolean remove(Object element) {
+ INode node = getNodeFor(element, false);
+ if (node == null) {
+ return false;
+ }
+
+ /* remove dependencies -- this removes backwards links as well */
+ node.clearDependencies();
+
+ /* do for each dependent (nodes that depend on me)
+ note: these weren't cleared above */
+ INode[] dependents = node.getDependents();
+ for (int i = 0; i < dependents.length; i++) {
+ INode dep = dependents[i];
+
+ /* remove the dependency */
+ dep.removeDependency(node);
+ // this must not cause the dependents local to be modified
+ }
+
+ return deleteNode(node) != null;
+ }
+
+ /**
+ * A package is being removed from the state. Delete the corresponding namespace nodes,
+ * but only if they have no dependents.
+ */
+ public void removePackage(IPackage pkg) {
+ INode node = (INode) fNamespaces.get(pkg);
+ if (node != null && node.getDependents().length == 0) {
+ fNamespaces.remove(pkg);
+ }
+ }
+
+ /**
+ * Replaces the dependencies and dependents of nodes in the given
+ * table with the corresponding nodes in the new graph.
+ */
+ private static void replaceDeps(Dictionary table, DependencyGraph newGraph) {
+ for (Enumeration e = table.elements(); e.hasMoreElements();) {
+ AbstractNode node = (AbstractNode) e.nextElement();
+ node.replaceDeps(newGraph);
+ }
+ }
+
+ /**
+ * Returns the number of nodes in the graph.
+ */
+ public int size() {
+ return fNamespaces.size() + fTypes.size() + fCompilationUnits.size();
+ }
+
+ public String toString() {
+ return "a DependencyGraph";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/DependencyGraphImpl.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/DependencyGraphImpl.java
new file mode 100644
index 0000000000..1e1476f4b0
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/DependencyGraphImpl.java
@@ -0,0 +1,49 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.Assert;
+import org.eclipse.jdt.internal.core.builder.*;
+
+/**
+ * @see IDependencyGraph
+ */
+public class DependencyGraphImpl implements IDependencyGraph {
+ StateImpl fState;
+ /**
+ * DependencyGraphImpl constructor comment.
+ */
+ DependencyGraphImpl(StateImpl state) {
+ fState = state;
+ }
+
+ /**
+ * @see IDependencyGraph#getNamespaceDependencies
+ */
+ public IPackage[] getNamespaceDependencies(IType type) {
+ Assert.isTrue(!type.isStateSpecific());
+ TypeStructureEntry tsEntry = fState.buildTypeStructureEntry(type);
+ Object key = tsEntry.getDependencyGraphKey();
+ return fState.getInternalDependencyGraph().getNamespaceDependencies(key);
+ }
+
+ /**
+ * @see IDependencyGraph#getState
+ */
+ public IState getState() {
+ return fState;
+ }
+
+ /**
+ * @see IDependencyGraph#getTypeDependencies
+ */
+ public IType[] getTypeDependencies(IType type) {
+ Assert.isTrue(!type.isStateSpecific());
+ TypeStructureEntry tsEntry = fState.buildTypeStructureEntry(type);
+ Object key = tsEntry.getDependencyGraphKey();
+ return fState.getInternalDependencyGraph().getTypeDependencies(key);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/FieldCollaboratorIndictment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/FieldCollaboratorIndictment.java
new file mode 100644
index 0000000000..eaf1002aac
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/FieldCollaboratorIndictment.java
@@ -0,0 +1,30 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+class FieldCollaboratorIndictment extends Indictment {
+ /**
+ * Creates a new FieldCollaboratorIndictment.
+ */
+ protected FieldCollaboratorIndictment(char[] name) {
+ super(name);
+ }
+
+ /**
+ * Returns what kind of indictment this is
+ */
+ public int getKind() {
+ return K_FIELD;
+ }
+
+ /**
+ * Returns a string representation of this class. For debugging purposes
+ * only (NON-NLS).
+ */
+ public String toString() {
+ // don't use + with char[]
+ return new StringBuffer("FieldIndictment(")
+ .append(fName)
+ .append(")")
+ .toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/FieldImpl.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/FieldImpl.java
new file mode 100644
index 0000000000..c8ee52ba4e
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/FieldImpl.java
@@ -0,0 +1,56 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.builder.*;
+
+public class FieldImpl extends AbstractMemberHandle implements IField {
+ /**
+ * Creates a new non state specific field implementation
+ */
+ FieldImpl(ClassOrInterfaceHandleImpl owner, String name) {
+ fOwner = owner;
+ fSignature = name;
+ }
+
+ /**
+ * getName method comment.
+ */
+ public String getName() {
+ return fSignature;
+ }
+
+ /**
+ * Returns a Type object that identifies the declared type for
+ * the field represented by this Field object.
+ */
+ public IType getType() {
+ return (IType) ((IField) inCurrentState()).getType().nonStateSpecific();
+ }
+
+ /**
+ * Returns a state specific version of this handle in the given state.
+ */
+ public IHandle inState(IState s)
+ throws org.eclipse.jdt.internal.core.builder.StateSpecificException {
+
+ return new FieldImplSWH((StateImpl) s, this);
+ }
+
+ /**
+ * Returns a constant indicating what kind of handle this is.
+ */
+ public int kind() {
+ return IHandle.K_JAVA_FIELD;
+ }
+
+ /**
+ * toString method comment.
+ */
+ public String toString() {
+ return getDeclaringClass().getName() + "." + getName();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/FieldImplSWH.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/FieldImplSWH.java
new file mode 100644
index 0000000000..2cba9938c8
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/FieldImplSWH.java
@@ -0,0 +1,122 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.core.builder.*;
+import org.eclipse.jdt.internal.core.Util;
+
+public class FieldImplSWH extends AbstractMemberHandleSWH implements IField {
+ FieldImpl fHandle;
+ /**
+ * Internal - Creates a new field handle in the given state
+ */
+ FieldImplSWH(StateImpl state, FieldImpl handle) {
+ fState = state;
+ fHandle = handle;
+ }
+
+ /**
+ * Gets the IBinaryField for this field.
+ */
+ protected IBinaryField getBinaryField() throws NotPresentException {
+ return getBinaryField(getTypeStructureEntry());
+ }
+
+ /**
+ * Returns the IBinaryField for this field
+ */
+ protected IBinaryField getBinaryField(TypeStructureEntry tsEntry)
+ throws NotPresentException {
+ IBinaryType t = fState.getBinaryType(tsEntry);
+ IBinaryField f = BinaryStructure.getField(t, fHandle.getName());
+ if (f == null) {
+ throw new NotPresentException();
+ } else {
+ return f;
+ }
+ }
+
+ /**
+ * Returns the non state specific handle
+ */
+ IMember getHandle() {
+ return fHandle;
+ }
+
+ /**
+ * Returns the Java language modifiers for the member
+ * represented by this object, as an integer.
+ */
+ public int getModifiers() {
+ return getBinaryField().getModifiers() & 0xFFFF;
+ }
+
+ /**
+ * Returns the name of the field.
+ */
+ public String getName() {
+ return fHandle.getName();
+ }
+
+ /**
+ * Returns a Type object that identifies the declared type for
+ * the field represented by this Field object.
+ */
+ public IType getType() {
+ TypeStructureEntry tsEntry = getTypeStructureEntry();
+ IBinaryField f = getBinaryField(tsEntry);
+ char[] sig = f.getTypeName();
+ return (IType) fState
+ .typeSignatureToHandle(tsEntry, Util.convertTypeSignature(sig))
+ .inState(fState);
+ }
+
+ /**
+ * Returns true if the member represented by this object is
+ * deprecated, false otherwise. A deprecated object is one that
+ * has a @ deprecated tag in its doc comment.
+ */
+ public boolean isDeprecated() {
+ return (getBinaryField().getModifiers() & IConstants.AccDeprecated) != 0;
+ }
+
+ /**
+ * Returns true if the object represented by the receiver is present
+ * in the development context, false otherwise. If the receiver is
+ * state-specific, checks whether it is present in this object's state,
+ * otherwise checks whether it is present in the current state of the
+ * development context.
+ */
+ public boolean isPresent() {
+ TypeStructureEntry entry =
+ fState.getTypeStructureEntry(fHandle.getDeclaringClass(), true);
+ if (entry == null) {
+ return false;
+ }
+ IBinaryType t = fState.getBinaryType(entry);
+ IBinaryField f = BinaryStructure.getField(t, fHandle.fSignature);
+ return f != null;
+ }
+
+ /**
+ * Returns true if the member represented by this object is
+ * synthetic, false otherwise. A synthetic object is one that
+ * was invented by the compiler, but was not declared in the source.
+ * See <em>The Inner Classes Specification</em>.
+ * A synthetic object is not the same as a fictitious object.
+ */
+ public boolean isSynthetic() throws NotPresentException {
+ return (getBinaryField().getModifiers() & IConstants.AccSynthetic) != 0;
+ }
+
+ /**
+ * Returns the non state specific handle
+ */
+ public IHandle nonStateSpecific() {
+ return fHandle;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/INode.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/INode.java
new file mode 100644
index 0000000000..77b9d57465
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/INode.java
@@ -0,0 +1,80 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.builder.IType;
+
+import java.util.Vector;
+
+/**
+ * A node in the image builder dependency graph.
+ * @see IDependencyGraph
+ */
+public interface INode {
+ // kinds of nodes (mutually exclusive, so they don't need to be maskable)
+ public static final int JCU_NODE = 0;
+ public static final int TYPE_NODE = 1;
+ public static final int NAMESPACE_NODE = 2;
+ public static final int ZIP_NODE = 3;
+ /**
+ * Adds a node that depends on this node.
+ */
+ void addDependent(INode nodeThatDependsOnMe);
+ /**
+ * Clears all incoming and outgoing dependency links for this node
+ */
+ void clearDependencies();
+ /**
+ * Adds a node that depends on this node.
+ * IMPORTANT: This should only be called by dependency graph copy methods.
+ * The dependents array at this point contains either new dependents or null
+ * values. This method must find the first null entry in the dependents array
+ * and add the given value.
+ */
+ void copyAddDependent(INode nodeThatDependsOnMe);
+ /**
+ * Returns an enumeration over the nodes that this node depends on.
+ * A change to the prinicipal structure of any of these nodes may affect
+ * the principal structure of this node.
+ */
+ INode[] getDependencies();
+ /**
+ * Returns an enumeration over the nodes that depend on this node.
+ * A change to the prinicipal structure of this node may affect the principal
+ * structure of the returned dependents.
+ */
+ INode[] getDependents();
+ /**
+ * Returns the element which this node represents.
+ */
+ public Object getElement();
+ /**
+ * Returns what kind of node this is.
+ */
+ int getKind();
+ /**
+ * Returns the topological order number of this node.
+ * Note that this may change if direct or indirect predecessors
+ * are added or removed from the graph.
+ */
+ int getOrder();
+ /**
+ * Returns the types that belong to this node
+ */
+ IType[] getTypes();
+ /**
+ * Removes a node on which this node depends.
+ * This -does- remove the backwards link from the other node.
+ */
+ void removeDependency(INode nodeThatIDependOn);
+ /**
+ * Removes a node that depends on this node
+ */
+ void removeDependent(INode nodeThatDependsOnMe);
+ /**
+ * Sets the nodes that this node depends on.
+ */
+ void setDependencies(INode[] nodesThatIDependOn);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ImageBuilderInternalException.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ImageBuilderInternalException.java
new file mode 100644
index 0000000000..813fb8aab0
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ImageBuilderInternalException.java
@@ -0,0 +1,45 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+public class ImageBuilderInternalException extends RuntimeException {
+ protected Throwable fThrowable;
+ /**
+ * Creates the exception with no error message.
+ */
+ public ImageBuilderInternalException() {
+ }
+
+ /**
+ * Creates the exception with an error message.
+ */
+ public ImageBuilderInternalException(String s) {
+ super(s);
+ }
+
+ /**
+ * Creates the exception, wrappering another throwable.
+ */
+ public ImageBuilderInternalException(Throwable t) {
+ fThrowable = t;
+ }
+
+ /**
+ * Returns the throwable which this wraps, or null if not applicable.
+ */
+ public Throwable getThrowable() {
+ return fThrowable;
+ }
+
+ /**
+ * Prints the exception to System.err.
+ */
+ public void printStackTrace() {
+ if (fThrowable != null) {
+ System.err.println(this);
+ System.err.println("Stack trace of embedded throwable:");
+ fThrowable.printStackTrace();
+ } else {
+ super.printStackTrace();
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ImageContextImpl.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ImageContextImpl.java
new file mode 100644
index 0000000000..0feb744249
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ImageContextImpl.java
@@ -0,0 +1,110 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.builder.*;
+import org.eclipse.jdt.internal.core.Util;
+
+import java.util.Hashtable;
+
+public class ImageContextImpl implements IImageContext {
+ private IPackage[] fPackages;
+ private IDevelopmentContext fDevContext;
+ /**
+ * Creates a new ImageContext.
+ */
+ public ImageContextImpl(IDevelopmentContext context, IPackage[] packages) {
+ fDevContext = context;
+ fPackages = packages;
+ }
+
+ /**
+ * Returns true if the image context contains the given package, false otherwise.
+ */
+ public boolean containsPackage(IPackage pkg) {
+ for (int i = 0, len = fPackages.length; i < len; ++i) {
+ if (fPackages[i].equals(pkg)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the given image context is equal to this one. Returns
+ * false otherwise.
+ */
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof ImageContextImpl))
+ return false;
+
+ ImageContextImpl ctx = (ImageContextImpl) o;
+
+ if (!ctx.fDevContext.equals(fDevContext))
+ return false;
+ int pkgCount = fPackages.length;
+ if (ctx.fPackages.length != pkgCount)
+ return false;
+
+ /* place packages of this in hashtable to avoid n squared search */
+ Hashtable pkgTable = new Hashtable(pkgCount * 2 + 1);
+ for (int i = 0; i < pkgCount; i++) {
+ pkgTable.put(fPackages[i], fPackages[i]);
+ }
+
+ /* check packages of other context for inclusion in this context */
+ IPackage[] otherPkgs = ctx.getPackages();
+ for (int i = 0; i < pkgCount; i++) {
+ if (!pkgTable.contains(otherPkgs[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns the development context for this image context.
+ */
+ public IDevelopmentContext getDevelopmentContext() {
+ return fDevContext;
+ }
+
+ /**
+ * Returns the packages in this image context. The packages will always
+ * be non state-specific.
+ */
+ public IPackage[] getPackages() {
+ return fPackages;
+ }
+
+ /**
+ * Returns true if all packages in this image context appear in the given one.
+ */
+ public boolean isSubsetOf(ImageContextImpl other) {
+ if (this == other)
+ return true;
+ if (Util.equalArraysOrNull(fPackages, other.fPackages))
+ return true;
+ for (int i = 0; i < fPackages.length; ++i) {
+ if (!other.containsPackage(fPackages[i]))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Return a string describing the image context. This is for debugging
+ * purposes only.
+ */
+ public String toString() {
+ StringBuffer buf = new StringBuffer("ImageContext with packages: \n");
+ for (int i = 0; i < fPackages.length; i++)
+ buf.append(" " + fPackages[i].getName() + "\n");
+ return buf.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ImageImpl.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ImageImpl.java
new file mode 100644
index 0000000000..18deb547d0
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ImageImpl.java
@@ -0,0 +1,236 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IPath;
+
+import org.eclipse.jdt.internal.core.builder.*;
+
+public class ImageImpl extends NonStateSpecificHandleImpl implements IImage {
+ JavaDevelopmentContextImpl fDevelopmentContext;
+
+ /**
+ * Creates a new image
+ */
+ public ImageImpl(JavaDevelopmentContextImpl dc) {
+ fDevelopmentContext = dc;
+ }
+
+ /**
+ * Returns the Type representing the primitive type boolean.
+ */
+ public IType booleanType() {
+ return fDevelopmentContext.fBooleanType;
+ }
+
+ /**
+ * Returns the Type representing the primitive type byte
+ */
+ public org.eclipse.jdt.internal.core.builder.IType byteType() {
+ return fDevelopmentContext.fByteType;
+ }
+
+ /**
+ *Returns the Type representing the primitive type char
+ */
+ public org.eclipse.jdt.internal.core.builder.IType charType() {
+ return fDevelopmentContext.fCharType;
+ }
+
+ /**
+ * Returns an Image Context consisting of all the given packages.
+ * This object and the packages must all be non-state-specific.
+ * This is a handle-only operation. The packages need not
+ * be present in the image.
+ */
+ public IImageContext createImageContext(IPackage[] packages)
+ throws StateSpecificException {
+ // copy array and verify that the packages are non-state-specific
+ IPackage[] pkgs = new IPackage[packages.length];
+ for (int i = 0; i < packages.length; i++) {
+ if ((packages[i].kind() != K_JAVA_PACKAGE)
+ || (packages[i].isStateSpecific())) {
+ throw new StateSpecificException();
+ }
+ pkgs[i] = packages[i];
+ }
+ // create the image context
+ return new ImageContextImpl(fDevelopmentContext, pkgs);
+ }
+
+ /**
+ * Returns the Type representing the primitive type double
+ */
+ public org.eclipse.jdt.internal.core.builder.IType doubleType() {
+ return fDevelopmentContext.fDoubleType;
+ }
+
+ /**
+ * Compares this Image handle against the specified object. Returns
+ * true if the objects are the same. Two Image handles are the same if
+ * they belong to the same development context, and if they are both
+ * non-state-specific or are both state-specific on the same state.
+ * See Handle.equals() for more details.
+ */
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof ImageImpl))
+ return false;
+
+ ImageImpl image = (ImageImpl) o;
+ return fDevelopmentContext.equals(image.fDevelopmentContext);
+ }
+
+ /**
+ * Returns the Type representing the primitive type float
+ */
+ public org.eclipse.jdt.internal.core.builder.IType floatType() {
+ return fDevelopmentContext.fFloatType;
+ }
+
+ /**
+ * Returns an array containing Type objects representing all
+ * classes and interfaces in the given ImageContext.
+ * This includes public and default (package) access top-level
+ * classes, inner classes, and local inner classes.
+ * The result is the intersection of all classes present in this image
+ * and the classes in the ImageContext, so the resulting classes
+ * are all present in the image.
+ * The resulting Types are in no particular order.
+ */
+ public IType[] getAllClasses(IImageContext context) {
+ StateImpl state = (StateImpl) getDevelopmentContext().getCurrentState();
+ IPackage[] pkgs =
+ (context == null
+ ? state.getPackageMap().getAllPackagesAsArray()
+ : context.getPackages());
+ java.util.Vector result = new java.util.Vector(pkgs.length * 25);
+ for (int i = 0; i < pkgs.length; ++i) {
+ TypeStructureEntry[] entries = state.getAllTypesForPackage(pkgs[i]);
+ // entries is null if package is missing
+ if (entries != null) {
+ for (int j = 0, len = entries.length; j < len; ++j) {
+ result.addElement(entries[j].getType());
+ }
+ }
+ }
+ // convert the Vector to an array
+ IType[] types = new IType[result.size()];
+ result.copyInto(types);
+ return types;
+ }
+
+ /**
+ * Returns an array of all packages present in the image. Note that this
+ * method defies the concept of a potentially infinite image, and should only
+ * be used by clients that must operate over the entire image (search, code assist)
+ */
+ public IPackage[] getAllPackages() {
+ StateImpl state = (StateImpl) fDevelopmentContext.getCurrentState();
+ return state.getPackageMap().getAllPackagesAsArray();
+ }
+
+ /**
+ * @see IImage
+ */
+ public IType[] getBuiltClasses(IPath path) {
+ return nonStateSpecific(((IImage) inCurrentState()).getBuiltClasses(path));
+ }
+
+ /**
+ * Return the internal representation of the development context that owns this object
+ */
+ JavaDevelopmentContextImpl getInternalDC() {
+ return fDevelopmentContext;
+ }
+
+ /**
+ * Returns a handle representing the package with the given
+ * name. For named packages, this is the fully qualified
+ * name. For unnamed packages, it is some internal identifying
+ * string.
+ * See <em>The Java Language Specification</em> section 7.4.1 and
+ * 7.4.2 for more details.
+ * This is a handle-only method; the specified package
+ * may or may not actually be present in the image.
+ */
+ public IPackage getPackageHandle(String name, boolean isUnnamed) {
+ return new PackageImpl(fDevelopmentContext, name, isUnnamed);
+ }
+
+ /**
+ * Returns an array of Package objects representing all
+ * packages contained in the given ImageContext.
+ * The result is the intersection of the packages present in this image
+ * and the packages in the ImageContext, so the resulting packages
+ * are all present in the image.
+ * The resulting Packages are in no particular order.
+ */
+ public IPackage[] getPackages(IImageContext context) {
+ if (context == null) {
+ return ((StateImpl) fDevelopmentContext.getCurrentState())
+ .getAllPackagesAsArray();
+ }
+ return nonStateSpecific(((IImage) inCurrentState()).getPackages(context));
+ }
+
+ /**
+ * Returns a consistent hash code for this object
+ */
+ public int hashCode() {
+ return fDevelopmentContext.hashCode();
+ }
+
+ /**
+ * Returns the state wrapped handle
+ */
+ public IHandle inState(IState state) {
+ return state.getImage();
+ }
+
+ /**
+ * Returns the Type representing the primitive type int
+ */
+ public org.eclipse.jdt.internal.core.builder.IType intType() {
+ return fDevelopmentContext.fIntType;
+ }
+
+ /**
+ * kind method comment.
+ */
+ public int kind() {
+ return K_JAVA_IMAGE;
+ }
+
+ /**
+ * Returns the Type representing the primitive type long
+ */
+ public org.eclipse.jdt.internal.core.builder.IType longType() {
+ return fDevelopmentContext.fLongType;
+ }
+
+ /**
+ * Returns the Type representing the primitive type short
+ */
+ public org.eclipse.jdt.internal.core.builder.IType shortType() {
+ return fDevelopmentContext.fShortType;
+ }
+
+ /**
+ * Returns a string representation of the image handle.
+ */
+ public String toString() {
+ return "image";
+ }
+
+ /**
+ * Returns the Type representing the primitive type void
+ */
+ public org.eclipse.jdt.internal.core.builder.IType voidType() {
+ return fDevelopmentContext.fVoidType;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ImageImplSWH.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ImageImplSWH.java
new file mode 100644
index 0000000000..95ab3943aa
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ImageImplSWH.java
@@ -0,0 +1,285 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+
+import org.eclipse.jdt.internal.core.builder.*;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+public class ImageImplSWH extends StateSpecificHandleImpl implements IImage {
+ ImageImpl fHandle;
+ /**
+ * Internal - Create a new Image
+ */
+ ImageImplSWH(StateImpl state, ImageImpl handle) {
+ fState = state;
+ fHandle = handle;
+ }
+
+ /**
+ * booleanType method comment.
+ */
+ public IType booleanType() {
+ return fState.fBooleanType;
+ }
+
+ /**
+ * Returns the Type representing the primitive type byte
+ */
+ public IType byteType() {
+ return fState.fByteType;
+ }
+
+ /**
+ *Returns the Type representing the primitive type char
+ */
+ public IType charType() {
+ return fState.fCharType;
+ }
+
+ /**
+ * Returns an Image Context consisting of all the given packages.
+ * This object and the packages must all be non-state-specific.
+ * This is a handle-only operation. The packages need not
+ * be present in the image.
+ */
+ public IImageContext createImageContext(IPackage[] packages)
+ throws StateSpecificException {
+ throw new StateSpecificException();
+
+ }
+
+ /**
+ * Returns the Type representing the primitive type double
+ */
+ public IType doubleType() {
+ return fState.fDoubleType;
+ }
+
+ /**
+ * Returns the Type representing the primitive type float
+ */
+ public IType floatType() {
+ return fState.fFloatType;
+ }
+
+ /**
+ * Returns an array containing Type objects representing all
+ * classes and interfaces in the given ImageContext.
+ * This includes public and default (package) access top-level
+ * classes, inner classes, and local inner classes.
+ * The result is the intersection of all classes present in this image
+ * and the classes in the ImageContext, so the resulting classes
+ * are all present in the image.
+ * The resulting Types are in no particular order.
+ */
+ public IType[] getAllClasses(IImageContext context) {
+ StateImpl state = fState;
+ IPackage[] pkgs =
+ (context == null
+ ? state.getPackageMap().getAllPackagesAsArray()
+ : context.getPackages());
+
+ java.util.Vector result = new java.util.Vector(pkgs.length * 25);
+ for (int i = 0; i < pkgs.length; i++) {
+ TypeStructureEntry[] entries = state.getAllTypesForPackage(pkgs[i]);
+ // entries is null if package is missing
+ if (entries != null) {
+ for (int j = 0, len = entries.length; j < len; ++j) {
+ result.addElement(entries[j].getType().inState(state));
+ }
+ }
+ }
+ // convert the Vector to an array
+ IType[] types = new IType[result.size()];
+ result.copyInto(types);
+ return types;
+ }
+
+ /**
+ * Returns an array of all packages present in the image. Note that this
+ * method defies the concept of a potentially infinite image, and should only
+ * be used by clients that must operate over the entire image (search, code assist)
+ */
+ public IPackage[] getAllPackages() {
+ IPackage[] pkgs = fState.getPackageMap().getAllPackagesAsArray();
+ int pkgCount = pkgs.length;
+ IPackage[] swh = new IPackage[pkgCount];
+ for (int i = 0; i < pkgCount; i++) {
+ swh[i] = (IPackage) pkgs[i].inState(fState);
+ }
+ return swh;
+ }
+
+ /**
+ * @see IImage
+ */
+ public IType[] getBuiltClasses(IPath path) {
+ Vector vResult = new Vector();
+ // try {
+ String extension = path.getFileExtension().toLowerCase();
+ if (extension.equals("java") || extension.equals("class")) {
+ IPath pkgPath = path.removeLastSegments(1);
+ IPackage pkg = fState.getPathMap().packageHandleFromPath(pkgPath);
+ TypeStructureEntry[] tsEntries = fState.getAllTypesForPackage(pkg);
+ if (tsEntries != null) { // present?
+ for (int i = 0, len = tsEntries.length; i < len; ++i) {
+ TypeStructureEntry tsEntry = tsEntries[i];
+ if (path.equals(tsEntry.getSourceEntry().getPath())) {
+ vResult.addElement(tsEntry.getType().inState(fState));
+ }
+ }
+ }
+ } else
+ if (fState.isZipElement(path)) {
+ IPackage[] pkgs = fState.getPathMap().packageHandlesFromPath(path);
+ for (int i = 0; i < pkgs.length; ++i) {
+ IPackage pkg = pkgs[i];
+ TypeStructureEntry[] tsEntries = fState.getAllTypesForPackage(pkg);
+ if (tsEntries != null) { // present?
+ for (int j = 0, len = tsEntries.length; j < len; ++j) {
+ TypeStructureEntry tsEntry = tsEntries[j];
+ if (path.equals(tsEntry.getSourceEntry().getPath())) {
+ vResult.addElement(tsEntry.getType().inState(fState));
+ }
+ }
+ }
+ }
+ } else {
+ if (path.equals(fState.getProject().getFullPath())) {
+ try {
+ IResource[] members = fState.getProject().members();
+ for (int i = 0, max = members.length; i < max; i++) {
+ IType[] tempResult = getBuiltClasses(members[i].getFullPath());
+ for (int j = 0; j < tempResult.length; ++j) {
+ vResult.addElement(tempResult[j]);
+ }
+ }
+ } catch (CoreException e) {
+ //couldn't access the project -- ignore and return empty array
+ }
+ } else { // package
+ IPackage pkg = fState.getPathMap().packageHandleFromPath(path);
+ TypeStructureEntry[] tsEntries = fState.getAllTypesForPackage(pkg);
+ if (tsEntries != null) { // present?
+ for (int i = 0, len = tsEntries.length; i < len; ++i) {
+ TypeStructureEntry tsEntry = tsEntries[i];
+ if (path.isPrefixOf(tsEntry.getSourceEntry().getPath())) {
+ vResult.addElement(tsEntry.getType().inState(fState));
+ }
+ }
+ }
+ }
+ }
+ // }
+ // catch (ResourceAccessException e) {
+ // fState.resourceAccessException(e);
+ // }
+ IType[] result = new IType[vResult.size()];
+ vResult.copyInto(result);
+ return result;
+ }
+
+ /**
+ * Returns a handle representing the package with the given
+ * name. For named packages, this is the fully qualified
+ * name. For unnamed packages, it is some internal identifying
+ * string.
+ * See <em>The Java Language Specification</em> section 7.4.1 and
+ * 7.4.2 for more details.
+ * This is a handle-only method; the specified package
+ * may or may not actually be present in the image.
+ *
+ * @parameter name the name of the package.
+ * @parameter isUnnamed a boolean indicating whether the package is unnamed.
+ * @see IPackage#getName
+ * @see IHandle
+ */
+ public IPackage getPackageHandle(String name, boolean isUnnamed) {
+ return (IPackage) fHandle.getPackageHandle(name, isUnnamed).inState(fState);
+ }
+
+ /**
+ * Returns an array of Package objects representing all
+ * packages contained in the given ImageContext.
+ * The result is the intersection of the packages present in this image
+ * and the packages in the ImageContext, so the resulting packages
+ * are all present in the image.
+ * The resulting Packages are in no particular order.
+ */
+ public IPackage[] getPackages(IImageContext context) {
+ if (context == null) {
+ return getAllPackages();
+ }
+ IPackage[] ctxPkgs = context.getPackages();
+ Vector result = new Vector();
+ for (int i = 0; i < ctxPkgs.length; i++) {
+ IPackage pkgSWH = (IPackage) ctxPkgs[i].inState(fState);
+ if (pkgSWH.isPresent())
+ result.addElement(pkgSWH);
+ }
+ // convert the Vector to an array
+ IPackage[] pkgs = new IPackage[result.size()];
+ result.copyInto(pkgs);
+ return pkgs;
+ }
+
+ /**
+ * Returns the Type representing the primitive type int
+ */
+ public IType intType() {
+ return fState.fIntType;
+ }
+
+ /**
+ * Returns whether the image is present.
+ */
+ public boolean isPresent() {
+ /* the image is always present */
+ return true;
+ }
+
+ /**
+ * kind method comment.
+ */
+ public int kind() {
+ return K_JAVA_IMAGE;
+ }
+
+ /**
+ * Returns the Type representing the primitive type long
+ */
+ public IType longType() {
+ return fState.fLongType;
+ }
+
+ /**
+ * Returns the non state specific handle
+ */
+ public IHandle nonStateSpecific() {
+ return fHandle;
+ }
+
+ /**
+ * Returns the Type representing the primitive type short
+ */
+ public IType shortType() {
+ return fState.fShortType;
+ }
+
+ /**
+ * Returns the Type representing the primitive type void
+ */
+ public IType voidType() {
+ return fState.fVoidType;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/IncrementalImageBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/IncrementalImageBuilder.java
new file mode 100644
index 0000000000..f4469f952d
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/IncrementalImageBuilder.java
@@ -0,0 +1,2025 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.IBinaryMethod;
+import org.eclipse.jdt.internal.compiler.env.IBinaryType;
+import org.eclipse.jdt.internal.compiler.env.IConstants;
+import org.eclipse.jdt.core.ElementChangedEvent;
+import org.eclipse.jdt.core.IClassFile;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.internal.core.builder.*;
+import org.eclipse.jdt.internal.core.builder.IType;
+import org.eclipse.jdt.internal.core.builder.NotPresentException;
+import org.eclipse.jdt.internal.core.lookup.ReferenceInfo;
+
+import org.eclipse.jdt.internal.compiler.util.*;
+import org.eclipse.jdt.internal.core.*;
+
+import java.util.*;
+
+/**
+ * The incremental image builder
+ */
+public class IncrementalImageBuilder extends AbstractImageBuilder {
+ protected IProject fNewProject;
+ protected IImageContext fImageContext;
+
+ /**
+ * The source deltas between old and new workspaces
+ * Maps from IProject to IResourceDelta for the project
+ */
+ protected Hashtable fSourceDeltas;
+
+ /**
+ * The image delta between old and new states
+ */
+ protected IDelta fImageDelta = null;
+
+ /**
+ * The image context of the last call to getImageDelta()
+ */
+ protected IImageContext fContextOfLastDelta = null;
+
+ /**
+ * Vector of IPath of source packages or zip files
+ * that have been added since old state.
+ * The path is relative to new state.
+ */
+ protected Vector fAddedPkgOrZips;
+
+ /**
+ * Vector of IPath of source packages or zip files
+ * that have been removed since old state.
+ * The path is relative of old state.
+ */
+ protected Vector fRemovedPkgOrZips;
+
+ /**
+ * Vector of ResourceDeltas representing changed source packages or zip files
+ * since old state.
+ */
+ protected Vector fChangedPkgOrZips;
+
+ /**
+ * Vector of IPackage handles of builder packages
+ * that have been added since old state.
+ */
+ protected Vector fAddedPackageHandles;
+
+ /**
+ * Vector of IPackage handles of builder packages
+ * that have been removed since old state.
+ */
+ protected Vector fRemovedPackageHandles;
+
+ /**
+ * Vector of IPackage handles of builder packages
+ * that have changes since old state.
+ */
+ protected Vector fChangedPackageHandles;
+
+ /**
+ * Set of affected IPackage: added, removed, directly changed or indirectly changed.
+ */
+ protected Hashtable fAffectedPackages;
+
+ /**
+ * Vector of SourceEntry representing added classes since old state.
+ */
+ protected Vector fAddedClasses;
+
+ /**
+ * Vector of SourceEntry representing removed classes since old state.
+ */
+ protected Vector fRemovedClasses;
+
+ /**
+ * Vector of SourceEntry representing changed classes since old state.
+ */
+ protected Vector fChangedClasses;
+
+ /**
+ * Vector of IPaths representing changed zips since old state.
+ */
+ protected Vector fChangedZips;
+
+ /**
+ * Table of IType -> BuilderType for types that are being compiled,
+ * so that old structure can be compared to new structure during
+ * indictment processing
+ */
+ protected Hashtable fBuilderTypeTable;
+ /**
+ * Creates a new incremental image builder on the given new workspace.
+ * The builder will build all classes that have changed since the old state,
+ * within the given image context.
+ */
+ protected IncrementalImageBuilder(
+ StateImpl oldState,
+ IProject newProject,
+ IImageContext context) {
+ fDC = (JavaDevelopmentContextImpl) oldState.getDevelopmentContext();
+ fOldState = oldState;
+ fNewProject = newProject;
+ fImageContext = context;
+ fBuilderTypeTable = new Hashtable(11);
+ }
+
+ /**
+ * Given an element delta for a changed package, add the package elements
+ * for changing elements to the table, keyed by package handle and file name.
+ * Added and removed elements are ignored.
+ */
+ protected void addChangedFileNamesFromChangedPackage(
+ IResourceDelta pkgDelta,
+ Hashtable table) {
+ IPackage[] pkgs =
+ fNewState.getPathMap().packageHandlesFromPath(pkgDelta.getFullPath());
+ for (int p = 0; p < pkgs.length; ++p) {
+ IPackage pkg = pkgs[p];
+ Hashtable pkgTable = (Hashtable) table.get(pkg);
+ if (pkgTable == null) {
+ pkgTable = new Hashtable(11);
+ table.put(pkg, pkgTable);
+ }
+ IResourceDelta[] elementDeltas =
+ pkgDelta.getAffectedChildren(IResourceDelta.CHANGED);
+ for (int i = 0; i < elementDeltas.length; ++i) {
+ IResourceDelta elementDelta = elementDeltas[i];
+ // Only add if the contents are changing.
+ if ((elementDelta.getFlags() & IResourceDelta.CONTENT) != 0) {
+ IPath path = elementDelta.getFullPath();
+ String extension = path.getFileExtension();
+ if (extension != null) {
+ if (extension.equalsIgnoreCase("java")
+ || extension.equalsIgnoreCase("class")) {
+ SourceEntry entry = new SourceEntry(path, null, null);
+ PackageElement element = new PackageElement(pkg, entry);
+ pkgTable.put(entry.getFileName(), element);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds the new classes for this build to the state.
+ */
+ protected void addNewClasses() {
+ for (Enumeration e = fAddedClasses.elements(); e.hasMoreElements();) {
+ addSourceElement((SourceEntry) e.nextElement());
+ }
+ }
+
+ /**
+ * Adds the given source element to the new state's tables
+ * and dependency graph.
+ */
+ protected void addSourceElement(SourceEntry newEntry) {
+ if (newEntry.isSource()) {
+ PackageElement element = fNewState.packageElementFromSourceEntry(newEntry);
+ IPackage pkg = element.getPackage();
+
+ /* the addition must be in a package which is in the class path */
+ Assert.isTrue(fNewState.getPackageMap().containsPackage(pkg));
+ DependencyGraph graph = fNewState.getInternalDependencyGraph();
+ graph.add(element);
+ fWorkQueue.add(element);
+ }
+ }
+
+ /**
+ * Applies the deltas to the old state to build the new state.
+ * The old state and new state have been set.
+ * The new state knows its workspace and build context.
+ * This is the method that actually does the incremental build
+ */
+ public void applySourceDelta(Hashtable deltas) {
+ fNotifier = new BuildNotifier(fDC, false);
+ fNotifier.begin();
+ fNotifier.subTask("Preparing for build");
+ fSourceDeltas = deltas;
+ fNewState = fOldState.copy(fNewProject, fImageContext);
+
+ // options might have changed since last builder run, thus refresh them
+ fCompilerOptions =
+ JavaModelManager.convertConfigurableOptions(JavaCore.getOptions());
+ fNewState.setCompilerOptions(fCompilerOptions);
+
+ try {
+ /* find out what has changed at the package level */
+ fNotifier.subTask("Analyzing packages");
+ computeAllPackages();
+ checkCancel();
+
+ /* update the package map */
+ updatePackageMap();
+ fNewState.canonicalizeBuildContext();
+ fNotifier.updateProgressDelta(0.05f);
+ checkCancel();
+
+ /* Update the source element table and namespace table for the removed and changed packages.
+ * The tables are simply deleted. They will be rebuilt lazily for changed packages. */
+ for (Enumeration e = fRemovedPackageHandles.elements(); e.hasMoreElements();) {
+ IPackage pkgHandle = (IPackage) e.nextElement();
+ fNewState.getSourceElementTable().removePackage(pkgHandle);
+ }
+ recomputeSourceEntriesForChangedPackages();
+ checkCancel();
+ fWorkQueue = new WorkQueue();
+
+ /* rebuild the namespaces and issue indictments for changes */
+ computeNamespaceChanges();
+ // 1G220B5 - force compilation of all their dependents as well - only one level deeper
+ for (Enumeration e = fWorkQueue.getElementsToCompile().elements();
+ e.hasMoreElements();
+ ) {
+ markDependentsAsNeedingCompile(e.nextElement());
+ }
+
+ /* find out what has changed at the package element level */
+ fNotifier.subTask("Analyzing sources");
+ computeAllClasses();
+ checkCancel();
+
+ /* All dependents of changed zips will need compiling */
+ markDependentsOfChangedZips();
+
+ /* remove old classes and get affected JCUs */
+ removeOldClasses();
+ checkCancel();
+
+ /* flag changed classes and get compilation units to compile */
+ updateChangedClasses();
+ checkCancel();
+
+ /* adding new classes might hide (equivalent to delete) old classes */
+ addNewClasses();
+ checkCancel();
+
+ float amountPerIteration = 0.60f;
+ // Approximation of n + (n/4) + (n/16) + ... = 0.85
+
+ /* keep compiling until there is nothing left to compile */
+ Vector vToCompile = fWorkQueue.getElementsToCompile();
+ while (vToCompile.size() != 0) {
+ fNotifier.setProgressPerCompilationUnit(amountPerIteration / vToCompile.size());
+ compile(vToCompile);
+ vToCompile = fWorkQueue.getElementsToCompile();
+ amountPerIteration *= 0.25f;
+ }
+
+ // not using PrincipalStructureByPackageTable
+ // propagatePrincipalStructureByPackageTable();
+
+ // Force all in build context
+ /*
+ Don't force -- we're not doing lazy builds.
+
+ if (fAddedPackageHandles.size() > 0 || fChangedPackageHandles.size() > 0) {
+ for (int i = 0; i < fAddedPackageHandles.size(); ++i) {
+ IPackage pkg = (IPackage) fAddedPackageHandles.elementAt(i);
+ maybeForce(pkg);
+ }
+ for (int i = 0; i < fChangedPackageHandles.size(); ++i) {
+ IPackage pkg = (IPackage) fChangedPackageHandles.elementAt(i);
+ maybeForce(pkg);
+ }
+ }
+ */
+ /* Update resources in binary output */
+ IResourceDelta projectDelta = (IResourceDelta) deltas.get(fNewProject);
+ if (projectDelta != null) {
+ ProjectResourceCopier copier =
+ new ProjectResourceCopier(fNewState.getJavaProject(), fDC, fNotifier, 0.10f);
+ copier.updateAffectedResources(projectDelta);
+ }
+
+ /* Removals and recompilations can leave unused namespace nodes in the
+ * dependency graph. Clean them up. */
+ cleanupUnusedNamespaceNodes();
+ checkCancel();
+
+ /* Copy resource to binary output */
+ //copyResources(projectDelta, 0.05f);
+
+ fNotifier.done();
+ } finally {
+ cleanUp();
+ }
+ }
+
+ /**
+ * Applies the delta to the old state
+ * to build the new state. The old state and new state have been set.
+ * The new state knows its workspace and build context.
+ * This is the method that actually does the incremental build
+ */
+ public void applySourceDelta(IResourceDelta projectDelta) {
+ Hashtable deltas = new Hashtable(11);
+ deltas.put(fNewProject, projectDelta);
+ applySourceDelta(deltas);
+ }
+
+ /**
+ * The given source element has changed and will be compiled.
+ * Flag the node in the dependency graph, and store all compilation
+ * units that will need compiling as a result of the change.
+ */
+ protected void changedSourceElement(SourceEntry newEntry) {
+ PackageElement element = fNewState.packageElementFromSourceEntry(newEntry);
+ if (element.isSource()) {
+ fWorkQueue.add(element);
+ }
+
+ /* remove problems for this source entry */
+ SourceEntry oldEntry = fOldState.getSourceEntry(element);
+ fNewState.getProblemReporter().removeProblems(oldEntry);
+ }
+
+ /**
+ * Since the image builder is given as a result, let go of
+ * any unneeded structures.
+ */
+ protected void cleanUp() {
+ super.cleanUp();
+ // Don't clear package level information because it's needed to compute the image delta.
+ fSourceDeltas = null;
+ fAddedClasses = fRemovedClasses = fChangedClasses = null;
+ }
+
+ /**
+ * Removals and recompilations can leave unused namespace nodes in the
+ * dependency graph. Clean them up.
+ */
+ protected void cleanupUnusedNamespaceNodes() {
+ if (fRemovedClasses.size() > 0 || fChangedClasses.size() > 0) {
+ PackageMap packageMap = fNewState.getPackageMap();
+ DependencyGraph graph = fNewState.getInternalDependencyGraph();
+ Vector unused = graph.getUnusedNamespaceNodes();
+ for (Enumeration e = unused.elements(); e.hasMoreElements();) {
+ NamespaceNode node = (NamespaceNode) e.nextElement();
+ IPackage pkg = node.getPackage();
+ if (!packageMap.containsPackage(pkg)) {
+ graph.removePackage(pkg);
+ }
+ }
+ }
+ }
+
+ /**
+ * Compare the visibility and gender of the two types.
+ * Returns true if equal, false if not.
+ */
+ protected boolean compareVisibilityAndGender(
+ TypeStructureEntry tsEntry,
+ org.eclipse.jdt.core.IType type)
+ throws JavaModelException {
+ try {
+ /* This relies on visibility bits being the same between the image builder and the java model. */
+ IType oldType = (IType) tsEntry.getType().inState(fNewState);
+ final int visVlags =
+ IConstants.AccPublic | IConstants.AccPrivate | IConstants.AccProtected;
+ int oldVis = oldType.getModifiers() & visVlags;
+ int newVis = type.getFlags() & visVlags;
+ return oldVis == newVis && oldType.isInterface() == type.isInterface();
+ } catch (NotPresentException e) {
+ // Old state may be missing. See 1FVQGL1: ITPJCORE:WINNT - SEVERE - Error saving java file
+ return false;
+ }
+ }
+
+ /**
+ * A unit is being (re)compiled. Save any previous type structure.
+ */
+ protected void compiling(CompilerCompilationUnit unit) {
+
+ /* Save old binaries if they exist */
+ SourceEntry sEntry = unit.getSourceEntry();
+ PackageElement element = fNewState.packageElementFromSourceEntry(sEntry);
+ if (fOldState.getSourceEntry(element) != null) {
+ saveBinaryTypes(element);
+ }
+ }
+
+ /**
+ * Computes the added, removed, changed classes for this incremental build.
+ * Vectors contain SourceEntry objects for each source element being added,
+ * removed, or changed.
+ *
+ * Takes into account package fragments, and only yields elements which are visible
+ *
+ * It's important to do this computation using the computed namespaces rather than
+ * directly from the source element tables, since types may be removed during namespace
+ * computation.
+ */
+ protected void computeAllClasses() {
+ fAddedClasses = new Vector();
+ fRemovedClasses = new Vector();
+ fChangedClasses = new Vector();
+ fChangedZips = new Vector(1);
+
+ /* do for each added builder package */
+ for (Enumeration e = fAddedPackageHandles.elements(); e.hasMoreElements();) {
+ IPackage pkg = (IPackage) e.nextElement();
+ SourceEntry[] entries = fNewState.getSourceEntries(pkg);
+ if (entries != null) {
+ for (int i = 0; i < entries.length; ++i) {
+ fAddedClasses.addElement(entries[i]);
+ }
+ }
+ }
+
+ /* do for each removed builder package */
+ for (Enumeration e = fRemovedPackageHandles.elements(); e.hasMoreElements();) {
+ IPackage pkg = (IPackage) e.nextElement();
+ // Don't force the package's table.
+ // If the package's table was not forced in the old state,
+ // there should be no work to do for its classes.
+ if (fOldState.getSourceElementTable().containsPackage(pkg)) {
+ SourceEntry[] entries = fOldState.getSourceEntries(pkg);
+ if (entries != null) {
+ for (int i = 0; i < entries.length; ++i) {
+ fRemovedClasses.addElement(entries[i]);
+ }
+ }
+ }
+ }
+
+ /* build table of changed package elements, keyed by package */
+ Hashtable changeTable = new Hashtable(fChangedPkgOrZips.size() * 2 + 1);
+ for (Enumeration e = fChangedPkgOrZips.elements(); e.hasMoreElements();) {
+ IResourceDelta changedPkgOrZip = (IResourceDelta) e.nextElement();
+ IPath path = changedPkgOrZip.getFullPath();
+
+ // ask the state if it is a ZIP file only if it is present in this state
+ if (fNewState.isZipElement(path)) {
+ /**
+ * Don't do any finer grained change calculation,
+ * all dependents of the zip and its namespaces
+ * will be recompiled
+ */
+ fChangedZips.addElement(path);
+ } else {
+ addChangedFileNamesFromChangedPackage(changedPkgOrZip, changeTable);
+ }
+ }
+
+ /* do for each changed builder package */
+ for (Enumeration e = fChangedPackageHandles.elements(); e.hasMoreElements();) {
+ IPackage pkg = (IPackage) e.nextElement();
+ Hashtable changesForPkg = (Hashtable) changeTable.get(pkg);
+ Hashtable fileNames = new Hashtable();
+ SourceEntry[] oldEntries = fOldState.getSourceEntries(pkg);
+ if (oldEntries != null) {
+ for (int i = 0; i < oldEntries.length; ++i) {
+ SourceEntry oldEntry = oldEntries[i];
+ fileNames.put(oldEntry.getFileName(), oldEntry);
+ }
+ }
+ SourceEntry[] newEntries = fNewState.getSourceEntries(pkg);
+ if (newEntries != null) {
+ for (int i = 0; i < newEntries.length; ++i) {
+ SourceEntry newEntry = newEntries[i];
+ String fileName = newEntry.getFileName();
+ SourceEntry oldEntry = (SourceEntry) fileNames.remove(fileName);
+ if (oldEntry != null) {
+ // Present in old and new. Has it changed?
+ if (!newEntry.equals(oldEntry)) {
+ // It has changed path, so treat it as a removal and an addition
+ fRemovedClasses.addElement(oldEntry);
+ fAddedClasses.addElement(newEntry);
+ } else
+ if (changesForPkg != null && changesForPkg.containsKey(fileName)) {
+ fChangedClasses.addElement(newEntry);
+ }
+ } else {
+ // Present only in new
+ fAddedClasses.addElement(newEntry);
+ }
+ }
+ }
+ // Remaining ones are removed.
+ for (Enumeration ee = fileNames.elements(); ee.hasMoreElements();) {
+ fRemovedClasses.addElement(ee.nextElement());
+ }
+ }
+ }
+
+ /**
+ * Computes the added, removed, changed packages and zips
+ * for this incremental build.
+ * Looks only in the union of the old and the new classpaths.
+ * Folders outside this union are ignored.
+ */
+ protected void computeAllPackages() {
+ fAddedPkgOrZips = new Vector();
+ fRemovedPkgOrZips = new Vector();
+ fChangedPkgOrZips = new Vector();
+ IPackageFragmentRoot[] oldRoots =
+ fOldState.getPackageFragmentRootsInClassPath();
+ fNewState.readClassPath(); // TBD: Only read it if changed.
+ IPackageFragmentRoot[] newRoots =
+ fNewState.getPackageFragmentRootsInClassPath();
+ for (Enumeration e = fSourceDeltas.elements(); e.hasMoreElements();) {
+ IResourceDelta delta = (IResourceDelta) e.nextElement();
+ computeAllPackages(delta, oldRoots, newRoots);
+ }
+ }
+
+ protected void computeAllPackages(
+ IResourceDelta delta,
+ IPackageFragmentRoot[] oldRoots,
+ IPackageFragmentRoot[] newRoots) {
+ int status = delta.getKind();
+ IPath path = delta.getFullPath();
+ IResource rootResource = null;
+ switch (delta.getKind()) {
+ case IResourceDelta.ADDED :
+ /* Look for this package only in the new roots */
+ for (int i = 0; i < newRoots.length; i++) {
+ rootResource = null;
+ try {
+ rootResource = newRoots[i].getUnderlyingResource();
+ } catch (JavaModelException e) {
+ }
+ if (rootResource != null && rootResource.getFullPath().isPrefixOf(path)) {
+ fAddedPkgOrZips.addElement(path);
+ break;
+ }
+ }
+ break;
+ case IResourceDelta.REMOVED :
+ /* Look for this package only in the old roots */
+ for (int i = 0; i < oldRoots.length; i++) {
+ rootResource = null;
+ try {
+ rootResource = oldRoots[i].getUnderlyingResource();
+ } catch (JavaModelException e) {
+ }
+ if (rootResource != null && rootResource.getFullPath().isPrefixOf(path)) {
+ fRemovedPkgOrZips.addElement(path);
+ break;
+ }
+ }
+ break;
+ case IResourceDelta.CHANGED :
+ /* Look for this package in the union of both sets of roots */
+ boolean found = false;
+ for (int i = 0; i < newRoots.length; i++) {
+ rootResource = null;
+ try {
+ rootResource = newRoots[i].getUnderlyingResource();
+ } catch (JavaModelException e) {
+ }
+ if (rootResource != null && rootResource.getFullPath().isPrefixOf(path)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ for (int i = 0; i < oldRoots.length; i++) {
+ rootResource = null;
+ try {
+ oldRoots[i].getUnderlyingResource();
+ } catch (JavaModelException e) {
+ }
+ if (rootResource != null && rootResource.getFullPath().isPrefixOf(path)) {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (found) {
+ /* Only include changes if it's not an archive, or if it's an archive and the contents really changed */
+ if (!fNewState.isZipElement(path)
+ || (delta.getFlags() & IResourceDelta.CONTENT) != 0) {
+ fChangedPkgOrZips.addElement(delta);
+ }
+ }
+ break;
+ }
+ IResourceDelta[] children = delta.getAffectedChildren();
+ for (int i = 0; i < children.length; ++i) {
+ String extension = children[i].getFullPath().getFileExtension();
+ if (extension == null
+ || extension.equalsIgnoreCase("zip")
+ || extension.equalsIgnoreCase("jar")) {
+ // TBD: Currently rely on empty extension indicating folder
+ computeAllPackages(children[i], oldRoots, newRoots);
+ }
+ }
+ }
+
+ /**
+ * Computes namespace changes for each added, removed and changed class file or JCU.
+ * The appropriate namespace node is informed of the changes, and it
+ * may invalidate its dependents where necessary. JCUs that need compiling
+ * as a result of invalidations are stored by the state.
+ * Must process removed types here, even though in most cases there will already
+ * be an explicit dependency on the removed type, because it is possible for others
+ * to have a namespace dependency but not a type dependency (e.g. in the case of errors).
+ */
+ protected void computeNamespaceChanges() {
+
+ for (Enumeration e = fSourceDeltas.elements(); e.hasMoreElements();) {
+ IResourceDelta delta = (IResourceDelta) e.nextElement();
+ JavaModelManager.getJavaModelManager().closeAffectedElements(delta);
+ }
+
+ // Should really only process packages in image context here,
+ // but in general other packages may depend on namespaces being added,
+ // not just those being removed and changed. So for now, process everything.
+
+ // The computations here must be based on the computed namespaces rather than
+ // directly off of the namespace contributions of affected source elements
+ // since the namespace computation may remove items due to conflicts.
+
+ int numPackages =
+ fAddedPackageHandles.size()
+ + fRemovedPackageHandles.size()
+ + fChangedPackageHandles.size();
+ if (numPackages == 0) {
+ fNotifier.updateProgressDelta(0.10f);
+ return;
+ }
+ float progressDelta = 0.10f / numPackages;
+
+ // Process changes in the set of package prefixes
+ if (fAddedPackageHandles.size() > 0 || fRemovedPackageHandles.size() > 0) {
+ computePackagePrefixChanges();
+ }
+
+ // Process added packages
+ for (Enumeration addedPkgs = fAddedPackageHandles.elements();
+ addedPkgs.hasMoreElements();
+ ) {
+ IPackage pkg = (IPackage) addedPkgs.nextElement();
+ fNotifier.subTask("Analyzing " + PackageImpl.readableName(pkg));
+
+ // Mark all dependents of missing namespace as needing compile.
+ markDependentsAsNeedingCompile(pkg);
+
+ // If any types currently exist with the same name as this package,
+ // they must be recompiled
+ markOverlappingTypesAsNeedingCompile(pkg);
+ fNotifier.updateProgressDelta(progressDelta);
+ fNotifier.checkCancel();
+ }
+
+ // Process removed packages
+ for (Enumeration removedPkgs = fRemovedPackageHandles.elements();
+ removedPkgs.hasMoreElements();
+ ) {
+ IPackage pkg = (IPackage) removedPkgs.nextElement();
+ fNotifier.subTask("Analyzing " + PackageImpl.readableName(pkg));
+
+ // Mark all dependents of namespace as needing compile.
+ markDependentsAsNeedingCompile(pkg);
+
+ // If any types currently exist with the same name as this package,
+ // they must be recompiled
+ markOverlappingTypesAsNeedingCompile(pkg);
+ fNotifier.updateProgressDelta(progressDelta);
+ fNotifier.checkCancel();
+ }
+
+ // Process changed packages
+ for (Enumeration changedPkgs = fChangedPackageHandles.elements();
+ changedPkgs.hasMoreElements();
+ ) {
+ IPackage pkg = (IPackage) changedPkgs.nextElement();
+ fNotifier.subTask("Analyzing " + PackageImpl.readableName(pkg));
+ computeNamespaceChanges(pkg);
+ fNotifier.updateProgressDelta(progressDelta);
+ fNotifier.checkCancel();
+ }
+ }
+
+ /**
+ * Computes the names with namespace changes for the given type.
+ */
+ protected void computeNamespaceChanges(
+ Hashtable oldTSEntries,
+ String parentTypeName,
+ org.eclipse.jdt.core.IType type,
+ Vector vTypeNames)
+ throws JavaModelException {
+ String typeName = type.getElementName();
+ if (parentTypeName != null) {
+ int len = parentTypeName.length() + typeName.length() + 1;
+ typeName =
+ new StringBuffer(len)
+ .append(parentTypeName)
+ .append("$")
+ .append(typeName)
+ .toString();
+ }
+ /* Remove it so that only non-matching ones remain in the table. */
+ TypeStructureEntry tsEntry = (TypeStructureEntry) oldTSEntries.remove(typeName);
+ if (tsEntry == null || !compareVisibilityAndGender(tsEntry, type)) {
+ vTypeNames.addElement(typeName);
+ }
+ org.eclipse.jdt.core.IType[] memberTypes = type.getTypes();
+ for (int i = 0; i < memberTypes.length; ++i) {
+ computeNamespaceChanges(oldTSEntries, typeName, memberTypes[i], vTypeNames);
+ }
+ }
+
+ /**
+ * Computes the names with namespace changes for the given element.
+ * Handles the cases where the element is added, removed, or changed.
+ */
+ protected void computeNamespaceChanges(
+ PackageElement element,
+ Vector vTypeNames) {
+ Hashtable oldTSEntries = new Hashtable(5);
+ SourceEntry oldSourceEntry = fOldState.getSourceEntry(element);
+ if (oldSourceEntry != null) {
+ // Ignore entries from zip files, since zip file changes are handled wholesale elsewhere.
+ if (oldSourceEntry.getZipEntryName() == null) {
+ org.eclipse.jdt.internal.core.builder.IType[] oldTypes =
+ fOldState.getInternalDependencyGraph().getTypes(element);
+ if (oldTypes != null) {
+ for (int i = 0; i < oldTypes.length; ++i) {
+ TypeStructureEntry tsEntry =
+ fOldState.getTypeStructureEntry(oldTypes[i], false);
+ if (tsEntry != null) {
+ oldTSEntries.put(tsEntry.getType().getSimpleName(), tsEntry);
+ }
+ }
+ }
+ }
+ }
+ SourceEntry newSourceEntry = fNewState.getSourceEntry(element);
+ if (newSourceEntry != null) {
+ // Ignore entries from zip files, since zip file changes are handled wholesale elsewhere.
+ if (oldSourceEntry.getZipEntryName() == null) {
+ /* use this if JavaModel is broken
+ String fileName = element.getFileName();
+ fileName = fileName.substring(0, fileName.indexOf('.'));
+ FakeType[] types = new FakeType[] {new FakeType(fileName)};
+ try {
+ computeNamespaceChanges(oldTSEntries, null, types[0], vTypeNames);
+ } catch (NotPresentException e) {} // ignore
+ */
+
+ IJavaElement javaElement = fNewState.getJavaElement(newSourceEntry);
+ if (javaElement instanceof ICompilationUnit) {
+ ICompilationUnit unit = (ICompilationUnit) javaElement;
+ try {
+ org.eclipse.jdt.core.IType[] types = unit.getTypes();
+ for (int i = 0; i < types.length; ++i) {
+ computeNamespaceChanges(oldTSEntries, null, types[i], vTypeNames);
+ }
+ } catch (JavaModelException e) {
+ // TBD: ignore
+ }
+ } else {
+ if (javaElement instanceof IClassFile) {
+ IClassFile classFile = (IClassFile) javaElement;
+ try {
+ computeNamespaceChanges(oldTSEntries, null, classFile.getType(), vTypeNames);
+ } catch (JavaModelException e) {
+ // TBD: ignore
+ }
+ }
+ }
+ }
+ }
+ for (Enumeration e = oldTSEntries.keys(); e.hasMoreElements();) {
+ String name = (String) e.nextElement();
+ vTypeNames.addElement(name);
+ }
+ }
+
+ /**
+ * Computes namespace changes for each added, removed and changed class file or JCU
+ * in an affected package.
+ */
+ protected void computeNamespaceChanges(IPackage pkg) {
+
+ /**
+ * Must remove syntax problems for all source entries in this package
+ * in the old state, regardless of whether they contributed to the old
+ * state's namespace. This must be done before computing the new namespace
+ * because the computation may reveal new errors that we don't want to remove.
+ */
+ Hashtable oldTable = new Hashtable(21);
+ SourceEntry[] oldEntries = fOldState.getSourceEntries(pkg);
+ if (oldEntries != null) {
+ for (int i = 0; i < oldEntries.length; i++) {
+ SourceEntry oldEntry = oldEntries[i];
+ fNewState.getProblemReporter().removeSyntaxErrors(oldEntry);
+ oldTable.put(oldEntry.getFileName(), oldEntry);
+ }
+ }
+ Vector vTypeNames = new Vector();
+ SourceEntry[] newEntries = fNewState.getSourceEntries(pkg);
+ if (newEntries != null) {
+ Dictionary sourceChanges = getSourceChanges(pkg);
+ for (int i = 0; i < newEntries.length; ++i) {
+ SourceEntry newEntry = newEntries[i];
+ SourceEntry oldEntry = (SourceEntry) oldTable.remove(newEntry.getFileName());
+ if (oldEntry == null) {
+ /* Added. Issue indictment based only on file name. */
+ vTypeNames.addElement(newEntry.getName());
+ } else {
+ if (!oldEntry.equals(newEntry)
+ || sourceChanges.get(newEntry.getPath()) != null) {
+ /* Changed. Issue indictments by comparing source types with previously built types. */
+ PackageElement element = new PackageElement(pkg, newEntry);
+ computeNamespaceChanges(element, vTypeNames);
+ }
+ }
+ }
+ }
+ /* Only removed source entries should remain in oldTable now. */
+ for (Enumeration e = oldTable.elements(); e.hasMoreElements();) {
+ SourceEntry oldEntry = (SourceEntry) e.nextElement();
+ /* Removed. Issue indictment based only on file name. */
+ vTypeNames.addElement(oldEntry.getName());
+ }
+ if (vTypeNames.isEmpty()) {
+ return;
+ }
+ IndictmentSet indicts = new IndictmentSet();
+ Hashtable nestedIndictsTable = null;
+ for (Enumeration e = vTypeNames.elements(); e.hasMoreElements();) {
+ String name = (String) e.nextElement();
+ int lastDollar = name.lastIndexOf('$');
+ if (lastDollar == -1) {
+ indicts.add(Indictment.createTypeIndictment(name));
+ } else {
+ // Nested type. Issue indictments as if containing type was a package.
+ // Dependencies on missing member types look like namespace dependencies on
+ // package with same name as enclosing type.
+ String qualification = name.substring(0, lastDollar);
+ // Convert qualification from $ separated to . separated.
+ // For example if name = "A$B$C", typeName = "C" and qualification = "A.B".
+ qualification = qualification.replace('$', '.');
+ String typeName = name.substring(lastDollar + 1);
+
+ // Issue indictments, not relative to current package.
+ // This catches dependencies on missing types in same package (e.g. ref is A.B).
+ IPackage nestedPkg = fDC.getImage().getPackageHandle(qualification, false);
+ nestedPkg = fNewState.canonicalize(nestedPkg);
+ if (nestedIndictsTable == null) {
+ nestedIndictsTable = new Hashtable(11);
+ }
+ IndictmentSet nestedIndicts = (IndictmentSet) nestedIndictsTable.get(nestedPkg);
+ if (nestedIndicts == null) {
+ nestedIndicts = new IndictmentSet();
+ nestedIndictsTable.put(nestedPkg, nestedIndicts);
+ }
+ nestedIndicts.add(Indictment.createTypeIndictment(typeName));
+
+ // Issue indictments, relative to current package (only if not unnamed package).
+ // This catches dependencies on missing types in other packages (e.g. ref is some.other.pkg.A.B).
+ if (!pkg.isUnnamed()) {
+ nestedPkg =
+ fDC.getImage().getPackageHandle(pkg.getName() + '.' + qualification, false);
+ if (nestedIndictsTable == null) {
+ nestedIndictsTable = new Hashtable(11);
+ }
+ nestedIndicts = (IndictmentSet) nestedIndictsTable.get(nestedPkg);
+ if (nestedIndicts == null) {
+ nestedIndicts = new IndictmentSet();
+ nestedIndictsTable.put(nestedPkg, nestedIndicts);
+ }
+ nestedIndicts.add(Indictment.createTypeIndictment(typeName));
+ }
+ }
+ }
+ if (!indicts.isEmpty()) {
+ issueIndictments(pkg, indicts, false);
+ }
+ if (nestedIndictsTable != null) {
+ for (Enumeration e = nestedIndictsTable.keys(); e.hasMoreElements();) {
+ IPackage nestedPkg = (IPackage) e.nextElement();
+ IndictmentSet nestedIndicts = (IndictmentSet) nestedIndictsTable.get(nestedPkg);
+ issueIndictments(pkg, nestedIndicts, false);
+ }
+ }
+ }
+
+ /**
+ * Compute the added and removed package prefixes (not actual packages)
+ * and issue the appropriate indictments on the namespaces.
+ */
+ protected void computePackagePrefixChanges() {
+ Hashtable oldTable = computePackagePrefixes(fOldState.getPackageMap());
+ Hashtable newTable = computePackagePrefixes(fNewState.getPackageMap());
+ for (Enumeration e = oldTable.elements(); e.hasMoreElements();) {
+ String name = (String) e.nextElement();
+ if (newTable.remove(name) == null) {
+ int lastDot = name.lastIndexOf('.');
+ if (lastDot != -1) {
+ String parentName = name.substring(0, lastDot);
+ String simpleName = name.substring(lastDot + 1);
+ IPackage parentPkg = fDC.getImage().getPackageHandle(parentName, false);
+ IndictmentSet indictments = new IndictmentSet();
+ indictments.add(Indictment.createTypeIndictment(simpleName));
+ issueIndictments(parentPkg, indictments, false);
+ }
+ }
+ }
+ for (Enumeration e = newTable.elements(); e.hasMoreElements();) {
+ String name = (String) e.nextElement();
+ int lastDot = name.lastIndexOf('.');
+ if (lastDot != -1) {
+ String parentName = name.substring(0, lastDot);
+ String simpleName = name.substring(lastDot + 1);
+ IPackage parentPkg = fDC.getImage().getPackageHandle(parentName, false);
+ IndictmentSet indictments = new IndictmentSet();
+ indictments.add(Indictment.createTypeIndictment(simpleName));
+ issueIndictments(parentPkg, indictments, false);
+ }
+ }
+ }
+
+ /**
+ * Returns a set of strings containing the names of all packages
+ * in the image, and all their prefixes.
+ */
+ protected Hashtable computePackagePrefixes(PackageMap packageMap) {
+ Hashtable prefixes = new Hashtable(packageMap.size() * 3 + 1);
+ for (Enumeration e = packageMap.getAllPackages(); e.hasMoreElements();) {
+ IPackage pkg = (IPackage) e.nextElement();
+ if (!pkg.isUnnamed()) {
+ String name = pkg.getName();
+ while (!prefixes.containsKey(name)) {
+ prefixes.put(name, name);
+ int i = name.lastIndexOf('.');
+ if (i == -1)
+ break;
+ name = name.substring(0, i);
+ }
+ }
+ }
+ return prefixes;
+ }
+
+ /**
+ * For debugging only.
+ */
+ static void dump(IResourceDelta delta) {
+ StringBuffer sb = new StringBuffer();
+ IPath path = delta.getFullPath();
+ for (int i = path.segmentCount(); --i > 0;) {
+ sb.append(" ");
+ }
+ switch (delta.getKind()) {
+ case IResourceDelta.ADDED :
+ sb.append('+');
+ break;
+ case IResourceDelta.REMOVED :
+ sb.append('-');
+ break;
+ case IResourceDelta.CHANGED :
+ sb.append('*');
+ break;
+ case IResourceDelta.NO_CHANGE :
+ sb.append('=');
+ break;
+ default :
+ sb.append('?');
+ break;
+ }
+ sb.append(path);
+ System.out.println(sb.toString());
+ IResourceDelta[] children = delta.getAffectedChildren();
+ for (int i = 0; i < children.length; ++i) {
+ dump(children[i]);
+ }
+ }
+
+ /**
+ * Returns an enumeration of the packages that have been affected
+ * by the build.
+ */
+ protected Enumeration getAffectedPackages() {
+ return fAffectedPackages.keys();
+ }
+
+ /**
+ * Returns a builder type for the given old and new type structure entries.
+ * Either old or new entries may be null (but not both).
+ * This method should only be called if there is no associated builder
+ * type already in the builder type table.
+ */
+ protected BuilderType getBuilderType(
+ TypeStructureEntry oldEntry,
+ TypeStructureEntry newEntry) {
+ IType handle = null;
+ BuilderType type = null;
+ if (oldEntry == null) {
+ /* must have been added */
+ Assert.isNotNull(newEntry);
+ type = new NewBuilderType(this, newEntry);
+ handle = newEntry.getType();
+ } else {
+ if (newEntry == null) {
+ /* must have been deleted */
+ Assert.isNotNull(oldEntry);
+ type = new OldBuilderType(this, oldEntry);
+ handle = oldEntry.getType();
+ } else {
+ if (oldEntry.fSourceEntry.equals(newEntry.fSourceEntry)) {
+ /* unchanged */
+ type = new UnmodifiedBuilderType(this, oldEntry);
+ handle = oldEntry.getType();
+ } else {
+ /* modified */
+ IBinaryType oldBinary = fOldState.getBinaryTypeOrNull(oldEntry);
+ type = new ModifiedBuilderType(this, oldEntry, oldBinary);
+ handle = oldEntry.getType();
+ }
+ }
+ }
+ fBuilderTypeTable.put(handle, type);
+ return type;
+ }
+
+ /**
+ * Returns a builder type for the given type.
+ */
+ protected BuilderType getBuilderType(IType type) {
+ BuilderType builderType = (BuilderType) fBuilderTypeTable.get(type);
+ if (builderType != null) {
+ return builderType;
+ }
+ return getBuilderType(
+ fOldState.getTypeStructureEntry(type, false),
+ fNewState.getTypeStructureEntry(type, false));
+ }
+
+ /**
+ * Returns an object describing the differences between the old
+ * state and the new state, otherwise returns null. The delta is
+ * restricted to the given ImageContext. This image delta will
+ * include entries for all program elements that are present in:
+ * <pre>
+ * (oldState UNION newState) INTERSECT imageContext
+ *</pre>
+ * That is, it will include each program element that is present in one or the other
+ * state and also in the given image context.
+ * Any delta objects navigated to from the result are restricted
+ * to the same ImageContext.
+ * Note that there is no necessary relationship between the image context
+ * supplied and the build contexts of the old and new states.
+ */
+ public IDelta getImageDelta(IImageContext imageContext) {
+ if (fImageDelta == null
+ || !Util.equalOrNull(imageContext, fContextOfLastDelta)) {
+ fImageDelta = new DeltaImpl(this, imageContext);
+ fContextOfLastDelta = imageContext;
+ }
+ return fImageDelta;
+ }
+
+ /**
+ * Returns a set of paths of files which are changing in the given package.
+ */
+ protected Dictionary getSourceChanges(IPackage pkgHandle) {
+ Dictionary set = new Hashtable(30);
+
+ /* do for each fragment of this package */
+ IPath[] newFrags = fNewState.getPackageMap().getFragments(pkgHandle);
+ for (int i = 0; i < newFrags.length; i++) {
+ IPath fragPath = newFrags[i];
+
+ /* find the JCUs for this package */
+ IResourceDelta[] fileDeltas = null;
+ for (Enumeration e = fChangedPkgOrZips.elements(); e.hasMoreElements();) {
+ IResourceDelta pkgDelta = (IResourceDelta) e.nextElement();
+ if (pkgDelta.getFullPath().equals(fragPath)) {
+ /* A zip file is changing. Don't bother optimizing this case -- too complex. */
+ if (!fNewState.isZipElement(fragPath)) {
+ fileDeltas = pkgDelta.getAffectedChildren(IResourceDelta.CHANGED);
+ }
+ break;
+ }
+ }
+ if (fileDeltas != null) {
+ /* do for each changed file in this fragment */
+ for (int j = 0; j < fileDeltas.length; j++) {
+ IResourceDelta fileDelta = fileDeltas[j];
+ // See 1FVSC75: ITPJCORE:ALL - SCENARIO B1 - Builder should check F_CONTENT on changed files
+ if (fileDelta.getKind() == IResourceDelta.CHANGED
+ && (fileDelta.getFlags() & IResourceDelta.CONTENT) != 0) {
+ IPath path = fileDelta.getFullPath();
+
+ /* skip non-java resources */
+ String extension = path.getFileExtension();
+ if (extension != null
+ && (extension.equalsIgnoreCase("java") || extension.equalsIgnoreCase("class"))) {
+ set.put(path, path);
+ }
+ }
+ }
+ }
+ }
+ return set;
+ }
+
+ protected boolean hasPackageMapChanges() {
+ if (!Util
+ .equalArraysOrNull(
+ fOldState.getPackageFragmentRootsInClassPath(),
+ fNewState.getPackageFragmentRootsInClassPath())) {
+ return true;
+ }
+
+ /* Has package or zip been added / removed ? */
+ if (fRemovedPkgOrZips.size() > 0 || fAddedPkgOrZips.size() > 0) {
+ return true;
+ }
+
+ /* if there is a changed zip file, assume package map changes */
+ for (Enumeration e = fChangedPkgOrZips.elements(); e.hasMoreElements();) {
+ IResourceDelta changed = (IResourceDelta) e.nextElement();
+ String extension = changed.getFullPath().getFileExtension();
+ if (extension != null) {
+ if (extension.equalsIgnoreCase("zip") || extension.equalsIgnoreCase("jar")) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if there is a change to the list of source entries in this package, false
+ * otherwise. This is meant to be a fast optimization, to determine
+ * whether the source entries for this package need to be recomputed. This
+ * method works solely against the source workspace delta. When in doubt,
+ * it is always okay to return true here.
+ */
+ protected boolean hasSourceEntryChanges(IPackage pkgHandle) {
+ IPath[] oldFrags = fOldState.getPackageMap().getFragments(pkgHandle);
+ IPath[] newFrags = fNewState.getPackageMap().getFragments(pkgHandle);
+ if (!Util.equalArraysOrNull(oldFrags, newFrags)) {
+ /* The set of package fragments has changed. Don't bother optimizing this case -- too complex. */
+ return true;
+ }
+
+ /* do for each fragment of this package */
+ for (int i = 0; i < newFrags.length; i++) {
+ IPath fragPath = newFrags[i];
+
+ /* find the JCUs for this package */
+ IResourceDelta[] fileDeltas = null;
+ for (Enumeration e = fChangedPkgOrZips.elements(); e.hasMoreElements();) {
+ IResourceDelta pkgDelta = (IResourceDelta) e.nextElement();
+ if (pkgDelta.getFullPath().equals(fragPath)) {
+ /* A zip file is changing. Don't bother optimizing this case -- too complex. */
+ if (fNewState.isZipElement(fragPath)) {
+ return true;
+ }
+ fileDeltas = pkgDelta.getAffectedChildren();
+ break;
+ }
+ }
+ if (fileDeltas == null) {
+ /**
+ * It's a more complex interaction between zips, for example
+ * the package may be added in one zip and removed from another.
+ * Don't bother optimizing this case -- too complex.
+ */
+ return true;
+ }
+
+ /* do for each file in this fragment in the new workspace */
+ for (int j = 0; j < fileDeltas.length; j++) {
+ IPath path = fileDeltas[j].getFullPath();
+
+ /* skip java resources */
+ String extension = path.getFileExtension();
+ if (extension != null) {
+ if ((extension.equalsIgnoreCase("java")
+ || extension.equalsIgnoreCase("class"))) {
+ /* if there is an added or removed jcu or binary, the source entries have changed */
+ int status = fileDeltas[j].getKind();
+ if (status == IResourceDelta.ADDED || status == IResourceDelta.REMOVED) {
+ return true;
+ }
+ /* it's a change, but it may be changing local status */
+ if (fileDeltas[j].getResource().isLocal(IResource.DEPTH_ZERO)
+ != fOldState.contains(new SourceEntry(path, null, null))) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Issues indictments to the dependents of the specified element.
+ * If transitive is true, they are issued to all dependents transitively,
+ * otherwise they are issued only to immediate dependents.
+ * The trial process is run as the indictments are issued.
+ * Any newly-convicted compilation units are added to the to-be-compiled list.
+ */
+ protected void issueIndictments(
+ Object element,
+ IndictmentSet indicts,
+ boolean transitive) {
+ DependencyGraph graph = fNewState.getInternalDependencyGraph();
+ Object[] dependents = graph.getDependents(element);
+ if (dependents.length > 0) {
+ Hashtable seen = new Hashtable(11);
+ seen.put(element, element); // Don't visit the given element
+
+ for (int i = 0; i < dependents.length; ++i) {
+ issueIndictments(graph, dependents[i], indicts, transitive, seen);
+ }
+ }
+ }
+
+ /**
+ * Issues indictments to the specified element.
+ * If transitive is true, they are issued to all dependents transitively,
+ * otherwise they are issued only to this element.
+ * The trial process is run as the indictments are issued.
+ * Any newly-convicted compilation units are added to the to-be-compiled list.
+ */
+ protected void issueIndictments(
+ DependencyGraph graph,
+ Object element,
+ IndictmentSet indicts,
+ boolean transitive,
+ Hashtable seen) {
+ // Only issue indictments to compilation units.
+ if (element instanceof PackageElement) {
+ PackageElement pkgElement = (PackageElement) element;
+ if (pkgElement.isSource()) {
+ // Have we already seen this one?
+ if (!seen.containsKey(element)) {
+ seen.put(element, element);
+ // Is it already in the queue?
+ if (!fWorkQueue.contains(pkgElement)) {
+ // If it's not being removed, conduct the trial.
+ if (fNewState.getSourceEntry(pkgElement) != null) {
+ if (tryUnit(pkgElement, indicts)) {
+ fWorkQueue.add(pkgElement);
+ }
+ }
+ }
+
+ // Recurse if transitive
+ if (transitive) {
+ Object[] dependents = graph.getDependents(element);
+ for (int i = 0; i < dependents.length; ++i) {
+ issueIndictments(graph, dependents[i], indicts, transitive, seen);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Mark the immediate dependents of the given element
+ * as needing to be compiled (if not marked so already),
+ * and add any newly marked ones to the list.
+ */
+ protected void markDependentsAsNeedingCompile(Object element) {
+ DependencyGraph graph = fNewState.getInternalDependencyGraph();
+ Object[] deps = graph.getDependents(element);
+ for (int i = 0; i < deps.length; ++i) {
+ if (deps[i] instanceof PackageElement) {
+ PackageElement pkgElement = (PackageElement) deps[i];
+ if (pkgElement.isSource()) {
+ if (!fWorkQueue.contains(pkgElement)) {
+ // Mark it, if it's not being removed.
+ if (fNewState.getSourceEntry(pkgElement) != null) {
+ fWorkQueue.add(pkgElement);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * All elements that refer to changed zips, or packages
+ * referred to by changed zips, must be recompiled.
+ * This is conservative, but since the old zip structure
+ * is not available, we can't do much better.
+ */
+ protected void markDependentsOfChangedZips() {
+
+ PathMap oldPathMap = fOldState.getPathMap();
+ PathMap newPathMap = fNewState.getPathMap();
+
+ /* do for each changed zip */
+ for (Enumeration e = fChangedZips.elements(); e.hasMoreElements();) {
+ IPath zip = (IPath) e.nextElement();
+
+ /* mark dependents of packages in old zip */
+ IPackage[] pkgs = oldPathMap.packageHandlesFromPath(zip);
+ for (int i = 0; i < pkgs.length; i++) {
+ markDependentsAsNeedingCompile(pkgs[i]);
+ }
+
+ /* mark dependents of packages in new zip */
+ pkgs = newPathMap.packageHandlesFromPath(zip);
+ for (int i = 0; i < pkgs.length; i++) {
+ markDependentsAsNeedingCompile(pkgs[i]);
+ }
+
+ /* mark dependents of the zip itself */
+ markDependentsAsNeedingCompile(zip);
+ }
+
+ /* also handle zips which were removed from class path */
+ IPath[] paths = oldPathMap.getPaths();
+ for (int i = 0; i < paths.length; ++i) {
+ IPath zip = paths[i];
+ if (fOldState.isZipElement(zip) && !newPathMap.hasPath(zip)) {
+
+ /* mark dependents of packages in old zip */
+ IPackage[] pkgs = oldPathMap.packageHandlesFromPath(zip);
+ for (int j = 0; j < pkgs.length; j++) {
+ markDependentsAsNeedingCompile(pkgs[j]);
+ }
+
+ /* mark dependents of the zip itself */
+ markDependentsAsNeedingCompile(zip);
+ }
+ }
+ }
+
+ /**
+ * The given package is being added or removed. Make sure that no types
+ * exist with the same name as this package. If any such types
+ * exist, mark them as needing compilation and add them to the
+ * compile vector.
+ */
+ protected void markOverlappingTypesAsNeedingCompile(IPackage pkg) {
+ String pkgName = pkg.getName();
+ int lastDot;
+ while ((lastDot = pkgName.lastIndexOf('.')) > 0) {
+
+ /* try to get a compilation unit for this package name */
+ PackageElement element =
+ fNewState.getCompilationUnitFromName(
+ pkgName,
+ fNewState.defaultPackageForProject());
+ if (element != null) {
+ fWorkQueue.add(element);
+ }
+
+ /* strip off a package level */
+ pkgName = pkgName.substring(0, lastDot);
+ }
+ }
+
+ /**
+ * Force compilation of everything in the given package (non-state-specific handle),
+ * if indicated by the build context.
+ */
+ protected void maybeForce(IPackage pkg) {
+ ImageContextImpl imageContext = (ImageContextImpl) fNewState.getBuildContext();
+ if (imageContext == null
+ ? pkg.inState(fNewState).isPresent()
+ : imageContext.containsPackage(pkg)) {
+ // fNotifier.subTask("Forcing " + pkg.getName());
+ fNewState.getAllTypesForPackage(pkg);
+ checkCancel();
+ }
+ }
+
+ /**
+ * Propagate the principal structure by package table,
+ * being sure to exclude any affected packages.
+ */
+ protected void propagatePrincipalStructureByPackageTable() {
+ Hashtable newTable =
+ (Hashtable) fOldState.getPrincipalStructureByPackageTable().clone();
+ for (Enumeration e = fAffectedPackages.keys(); e.hasMoreElements();) {
+ IPackage pkg = (IPackage) e.nextElement();
+ newTable.remove(pkg);
+ }
+ fNewState.setPrincipalStructureByPackageTable(newTable);
+ }
+
+ /**
+ * Recomputes the source entries for changed packages. As an optimization,
+ * only recompute the source entries for packages that may actually have
+ * changes to their source entries.
+ */
+ protected void recomputeSourceEntriesForChangedPackages() {
+ for (Enumeration e = fChangedPackageHandles.elements(); e.hasMoreElements();) {
+ IPackage pkg = (IPackage) e.nextElement();
+ if (hasSourceEntryChanges(pkg)) {
+ fNewState.getSourceElementTable().removePackage(pkg);
+ // Now force it.
+ fNewState.getSourceEntries(pkg);
+ }
+ }
+ }
+
+ /**
+ * Remove all types and compilation units from the new state
+ * that do not exist in the new workspace. Keep track of any
+ * types that will need to be compiled as a result of the change.
+ */
+ protected void removeOldClasses() {
+ for (Enumeration e = fRemovedClasses.elements(); e.hasMoreElements();) {
+ SourceEntry entry = (SourceEntry) e.nextElement();
+ removeSourceElement(entry);
+ }
+ }
+
+ /**
+ * Removes the given source element from the new state's tables
+ * and dependency graph. Marks all JCUs that depend on the removed element.
+ */
+ protected void removeSourceElement(SourceEntry entry) {
+ PackageElement element = fOldState.packageElementFromSourceEntry(entry);
+ SourceEntry oldEntry = fOldState.getSourceEntry(element);
+ if (oldEntry == null) {
+ // It didn't exist in the old state (strange).
+ return;
+ }
+
+ // delete problems for this entry
+ // only delete non-syntax problems, since new syntax problems may have already
+ // been generated during namespace computations
+ fNewState.getProblemReporter().removeNonSyntaxErrors(oldEntry);
+
+ /* remove type descriptor for types that belong to this source element */
+ DependencyGraph graph = fNewState.getInternalDependencyGraph();
+ Hashtable structureTable = fNewState.getPrincipalStructureTable();
+ IType[] types = graph.getTypes(element);
+ if (types != null) {
+ for (int i = 0; i < types.length; ++i) {
+ IType type = types[i];
+ structureTable.remove(type);
+ if (!element.isBinary()) {
+ fNewState.getBinaryOutput().deleteBinary(type);
+ }
+ }
+ }
+ markDependentsAsNeedingCompile(element);
+ graph.remove(element);
+
+ // The element has already been removed from the source element table.
+ // So don't do any source element table or fragment logic here.
+
+ // Don't delete the namespace for the package here, because it cannot be rebuilt lazily
+ // since the package may be in process of being removed.
+ }
+
+ /**
+ * Hang onto the binary types for this source, because it will be compiled
+ */
+ protected void saveBinaryTypes(PackageElement element) {
+ DependencyGraph graph = fOldState.getInternalDependencyGraph();
+ IType[] types = graph.getTypes(element);
+ for (int i = 0; i < types.length; i++) {
+ IType type = types[i];
+ BuilderType builderType = (BuilderType) fBuilderTypeTable.get(type);
+
+ if (builderType == null || !builderType.isAffected()) {
+ TypeStructureEntry oldEntry = fOldState.getTypeStructureEntry(type, false);
+ Assert.isNotNull(oldEntry);
+
+ /* create and store the builder type */
+ // Allow it to be missing. See 1FW1S0Y: ITPJCORE:ALL - Java builder builds when non-Java files affected
+ IBinaryType oldBinary = fOldState.getBinaryTypeOrNull(oldEntry);
+ builderType = new ModifiedBuilderType(this, oldEntry, oldBinary);
+ fBuilderTypeTable.put(type, builderType);
+
+ /* remove the principal structure entry in the new state */
+ fNewState.getPrincipalStructureTable().remove(type);
+
+ /* nuke the binary because it will soon be stale */
+ fNewState.getBinaryOutput().deleteBinary(type);
+ }
+ }
+ }
+
+ /**
+ * Sort the compilation units by topological order.
+ */
+ protected void sort(PackageElement[] compileArray) {
+ DependencyGraph graph = fNewState.getInternalDependencyGraph();
+ int len = compileArray.length;
+ int[] sortOrder = new int[len];
+ for (int i = 0; i < len; ++i) {
+ sortOrder[i] = graph.getOrder(compileArray[i]);
+ }
+ Util.sort(compileArray, sortOrder);
+ }
+
+ /**
+ * Returns a string describe the builder
+ * @see IImageBuilder
+ */
+ public String toString() {
+ return "incremental image builder for:\n"
+ + "\tnew state: "
+ + getNewState()
+ + "\n"
+ + "\told state: "
+ + getOldState();
+ }
+
+ /**
+ * If this type is a subtype is the originator of an abstract method
+ * indictment, it must be compiled
+ */
+ protected boolean tryAbstractMethodIndictments(
+ PackageElement unit,
+ IndictmentSet indictments) {
+ final boolean GUILTY = true, INNOCENT = false;
+ IType[] trialTypes = indictments.getAbstractMethodOriginators();
+ if (trialTypes.length == 0) {
+ return false;
+ }
+ /* if problems were detected, some innerclasses might not have been generated,
+ thus the state would not reflect their presence, and even if guilty could not
+ be convicted (also see 1GA6CV7) */
+ Vector problemVector =
+ fOldState.getProblemReporter().getProblemVector(fOldState.getSourceEntry(unit));
+ if (problemVector != null) {
+ Enumeration problems = problemVector.elements();
+ while (problems.hasMoreElements()) {
+ IProblemDetail problem = (IProblemDetail) problems.nextElement();
+ if ((problem.getSeverity() & IProblemDetail.S_ERROR) != 0)
+ return GUILTY;
+ }
+ }
+
+ /* do for each type in this package element */
+ IType[] types = fOldState.getInternalDependencyGraph().getTypes(unit);
+ for (int i = 0, imax = types.length; i < imax; i++) {
+ IType type = types[i];
+ TypeStructureEntry tsEntry = fOldState.getTypeStructureEntry(type, false);
+
+ /* shouldn't happen, but trust nobody! */
+ if (tsEntry == null) {
+ continue;
+ }
+ IType oldType = (IType) type.inState(fOldState);
+ int flags = oldType.getModifiers();
+
+ /* interfaces aren't affected by method additions/removals in super interfaces,
+ other than for compatibility checking, which is handled elsewhere */
+ if (oldType.isInterface()) {
+ continue;
+ }
+
+ /* only check superclasses if this class is not abstract, */
+ /* because abstract classes aren't affected by abstract method additions/removals */
+ /* on their superclasses, only on their superinterfaces */
+ boolean checkSuperclasses = (flags & IConstants.AccAbstract) == 0;
+
+ /* do for each abstract method originator */
+ BuilderType builderType = getBuilderType(type);
+ for (int j = 0, jmax = trialTypes.length; j < jmax; ++j) {
+ IType trialType = trialTypes[j];
+ if (checkSuperclasses) {
+ if (builderType.hasSuperclass(trialType)) {
+ return GUILTY;
+ }
+ }
+ if (builderType.hasSuperInterface(trialType)) {
+ return GUILTY;
+ }
+ }
+ }
+
+ /* no supertypes convicted this package element, so it must be innocent */
+ return INNOCENT;
+ }
+
+ /**
+ * If a subtype of the originator of a method indictment redefines
+ * the method for which there is an indictment, it must be recompiled.
+ * This is also true if any superinterfaces of the subtype defines
+ * an indicted method.
+ */
+ protected boolean tryMethodDeclarations(
+ BuilderType builderType,
+ IndictmentSet indictments) {
+ final boolean GUILTY = true, INNOCENT = false;
+
+ /* try the methods of this type */
+ IBinaryType oldBinary = builderType.getOldBinaryType();
+ if (oldBinary == null)
+ return GUILTY;
+
+ IBinaryMethod[] methods = oldBinary.getMethods();
+ if (methods != null) {
+ for (int k = 0; k < methods.length; k++) {
+ if (indictments.tryMethodDeclaration(methods[k])) {
+ return GUILTY;
+ }
+ }
+ }
+
+ /* recurse on superinterfaces */
+ char[][] interfaces = oldBinary.getInterfaceNames();
+ if (interfaces != null) {
+ for (int i = 0; i < interfaces.length; i++) {
+ BuilderType supr =
+ getBuilderType(
+ BinaryStructure.getType(
+ builderType.getNewState(),
+ builderType.getNewTypeStructureEntry(),
+ interfaces[i]));
+ if (tryMethodDeclarations(supr, indictments)) {
+ return GUILTY;
+ }
+ }
+ }
+ return INNOCENT;
+ }
+
+ /**
+ * If a subtype of the originator of a method indictment redefines
+ * the method for which there is an indictment, it must be recompiled.
+ */
+ protected boolean tryMethodDeclarations(
+ PackageElement unit,
+ IndictmentSet indictments) {
+ final boolean GUILTY = true, INNOCENT = false;
+ IType[] methodIndictmentOwners = indictments.getMethodIndictmentOwners();
+ if (methodIndictmentOwners.length == 0) {
+ return INNOCENT;
+ }
+ /* if problems were detected, some innerclasses might not have been generated,
+ thus the state would not reflect their presence, and even if guilty could not
+ be convicted (also see 1GA6CV7) */
+ Vector problemVector =
+ fOldState.getProblemReporter().getProblemVector(fOldState.getSourceEntry(unit));
+ if (problemVector != null) {
+ Enumeration problems = problemVector.elements();
+ while (problems.hasMoreElements()) {
+ IProblemDetail problem = (IProblemDetail) problems.nextElement();
+ if ((problem.getSeverity() & IProblemDetail.S_ERROR) != 0)
+ return GUILTY;
+ }
+ }
+ IType[] types = fOldState.getInternalDependencyGraph().getTypes(unit);
+ for (int i = 0; i < types.length; ++i) {
+ boolean found = false;
+ BuilderType trialType = getBuilderType(types[i]);
+ for (int j = 0, len = methodIndictmentOwners.length; j < len; ++j) {
+ //note this is conservative because owners are not matched to their methods
+ if (trialType.hasSuperType(methodIndictmentOwners[j])) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ if (tryMethodDeclarations(trialType, indictments)) {
+ return GUILTY;
+ }
+ }
+ }
+ return INNOCENT;
+ }
+
+ /**
+ * Conducts a trial on a single compilation unit. Returns true if the unit
+ * is guilty. The sentence is compilation without possibility of parole.
+ */
+ protected boolean tryUnit(PackageElement unit, IndictmentSet indictments) {
+
+ /* innocent unless proven guilty */
+ final boolean GUILTY = true, INNOCENT = false;
+
+ /* quick test to see if there's no indictments */
+ if (indictments.isEmpty()) {
+ return INNOCENT;
+ }
+
+ /* automatically guilty if there is an upstream hierarchy change */
+ if (indictments.hasHierarchyIndictment()) {
+ return GUILTY;
+ }
+
+ /* gather the evidence */
+ ReferenceInfo evidence = fNewState.getReferencesForPackageElement(unit);
+
+ /* Unable to index unit, convict and let compiler try it */
+ if (evidence == null) {
+ return GUILTY;
+ }
+ if (indictments.tryAllEvidence(evidence)) {
+ return GUILTY;
+ }
+
+ /**
+ * If a subtype of the originator of a method indictment redefines
+ * the method for which there is an indictment, it must be recompiled.
+ */
+ if (tryMethodDeclarations(unit, indictments)) {
+ return GUILTY;
+ }
+
+ /**
+ * If this type is a subtype of the originator of an abstract method
+ * indictment, it may need to be recompiled.
+ */
+ if (tryAbstractMethodIndictments(unit, indictments)) {
+ return GUILTY;
+ }
+
+ /**
+ * If there have been changes to constructors in the direct superclass,
+ * it must be recompiled.
+ */
+ if (tryZeroArgConstructorInSuperclass(unit, indictments)) {
+ return GUILTY;
+ }
+
+ /* evidence is exhausted and unit has not been convicted */
+ return INNOCENT;
+ }
+
+ /**
+ * If there have been changes to the zero-arg constructor in the superclass of any types in the CU,
+ * the CU must be recompiled. This handles refs by default constructors and implicit super invocations in
+ * constructors, which aren't covered by the normal method indictments since they
+ * generate no evidence of refs to the super constructor.
+ */
+ protected boolean tryZeroArgConstructorInSuperclass(
+ PackageElement unit,
+ IndictmentSet indictments) {
+ if (!indictments.hasConstructorIndictments()) {
+ return false;
+ }
+ IType[] types = fOldState.getInternalDependencyGraph().getTypes(unit);
+ for (int i = 0; i < types.length; ++i) {
+ IType superclass = getBuilderType(types[i]).getSuperclass();
+ if (superclass != null) {
+ String key = '<' + superclass.getDeclaredName() + ">/0";
+ if (indictments.tryMethodEvidence(key.toCharArray())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Processes changed classes in the state. Stores compilation
+ * units that need to be compiled as a result of the changes.
+ */
+ protected void updateChangedClasses() {
+ for (Enumeration e = fChangedClasses.elements(); e.hasMoreElements();) {
+ SourceEntry entry = (SourceEntry) e.nextElement();
+ changedSourceElement(entry);
+ }
+ }
+
+ /**
+ * Updates or rebuilds the package map with the affected package fragments.
+ * After, the added/removed/changed builder packages are known.
+ */
+ protected void updatePackageMap() {
+ // Simply rebuild if adding or removing packages, rather than trying to do this
+ // incrementally, which is tricky. E.g. a package should not really be added if its
+ // project does not appear in the class path.
+ boolean rebuild = hasPackageMapChanges();
+ if (rebuild) {
+ fNewState.buildInitialPackageMap();
+ }
+
+ /* Set of affected package handles */
+ Vector affected = new Vector();
+
+ /* Process changed package fragments (package map not affected). *
+ * Due to changing class paths, a package which is changing in the source *
+ * may actually be added / removed rather than changed. Figure out which. */
+ for (Enumeration e = fChangedPkgOrZips.elements(); e.hasMoreElements();) {
+ IResourceDelta delta = (IResourceDelta) e.nextElement();
+ IPackage[] pkgHandles = null;
+
+ /* Look in the new state only if the package has not been removed */
+ if (delta.getKind() != IResourceDelta.REMOVED) {
+ pkgHandles = fNewState.getPathMap().packageHandlesFromPath(delta.getFullPath());
+ for (int i = 0; i < pkgHandles.length; i++) {
+ if (!affected.contains(pkgHandles[i])) {
+ affected.addElement(pkgHandles[i]);
+ }
+ }
+ }
+ /* Look in the old state only if the package has not been added */
+ if (delta.getKind() != IResourceDelta.ADDED) {
+ pkgHandles = fOldState.getPathMap().packageHandlesFromPath(delta.getFullPath());
+ for (int i = 0; i < pkgHandles.length; i++) {
+ if (!affected.contains(pkgHandles[i])) {
+ affected.addElement(pkgHandles[i]);
+ }
+ }
+ }
+ }
+
+ /* Partition affected packages into added/removed/changed */
+ fAddedPackageHandles = new Vector();
+ fRemovedPackageHandles = new Vector();
+ fChangedPackageHandles = new Vector();
+ PackageMap oldMap = fOldState.getPackageMap();
+ PackageMap newMap = fNewState.getPackageMap();
+ for (Enumeration e = affected.elements(); e.hasMoreElements();) {
+ IPackage pkg = (IPackage) e.nextElement();
+ if (oldMap.containsPackage(pkg)) {
+ if (newMap.containsPackage(pkg)) {
+ fChangedPackageHandles.addElement(pkg);
+ } else {
+ fRemovedPackageHandles.addElement(pkg);
+ }
+ } else {
+ if (newMap.containsPackage(pkg)) {
+ fAddedPackageHandles.addElement(pkg);
+ } else {
+ // This can occur if there are changes to a package
+ // which does not appear in either the old or new class path.
+ // Ignore it.
+ }
+ }
+ }
+
+ /* Check for added/removed/changed packages due to added/removed fragments and/or class path changes */
+ if (rebuild) {
+ for (Enumeration e = oldMap.getAllPackages(); e.hasMoreElements();) {
+ IPackage pkg = (IPackage) e.nextElement();
+ IPath[] newFragments = newMap.getFragments(pkg);
+ if (newFragments == null) {
+ // package has been removed due to class path change;
+ // may also have been removed due to source change
+ if (!fRemovedPackageHandles.contains(pkg)) {
+ fRemovedPackageHandles.addElement(pkg);
+ }
+ } else
+ if (!Util.equalArraysOrNull(oldMap.getFragments(pkg), newFragments)) {
+ // package has changed package fragments due to class path change;
+ // may also have source change
+ if (!fChangedPackageHandles.contains(pkg)) {
+ fChangedPackageHandles.addElement(pkg);
+ }
+ }
+ }
+ for (Enumeration e = newMap.getAllPackages(); e.hasMoreElements();) {
+ IPackage pkg = (IPackage) e.nextElement();
+ if (!oldMap.containsPackage(pkg)) {
+ // package has been added due to class path change;
+ // may also have been added due to source change
+ if (!fAddedPackageHandles.contains(pkg)) {
+ fAddedPackageHandles.addElement(pkg);
+ }
+ }
+ }
+ }
+
+ /* Add all affected packages to fAffectedPackages. */
+ fAffectedPackages = new Hashtable(11);
+ for (Enumeration e = fAddedPackageHandles.elements(); e.hasMoreElements();) {
+ IPackage pkg = (IPackage) e.nextElement();
+ fAffectedPackages.put(pkg, pkg);
+ }
+ for (Enumeration e = fRemovedPackageHandles.elements(); e.hasMoreElements();) {
+ IPackage pkg = (IPackage) e.nextElement();
+ fAffectedPackages.put(pkg, pkg);
+ }
+ for (Enumeration e = fChangedPackageHandles.elements(); e.hasMoreElements();) {
+ IPackage pkg = (IPackage) e.nextElement();
+ fAffectedPackages.put(pkg, pkg);
+ }
+ }
+
+ /**
+ * Stores the results of a compilation in the appropriate state tables.
+ * Keeps track of what compilation units need to be compiled as a result
+ * of the changes.
+ */
+ protected void updateState(ConvertedCompilationResult[] results) {
+ int n = results.length;
+ PackageElement[] oldUnits = new PackageElement[n];
+ PackageElement[] newUnits = new PackageElement[n];
+ IType[][] oldTypeList = new IType[n][];
+
+ // Preparation
+ DependencyGraph oldGraph = fOldState.getInternalDependencyGraph();
+ DependencyGraph newGraph = fNewState.getInternalDependencyGraph();
+
+ for (int i = 0; i < n; i++) {
+ PackageElement element = results[i].getPackageElement();
+
+ // Be sure the package is in the set of affected packages.
+ // It may not be if this unit was recompiled in a package
+ // other than the ones which have direct changes.
+ IPackage pkg = element.getPackage();
+ fAffectedPackages.put(pkg, pkg);
+
+ // Be sure to look up the source entries in the old and new state,
+ // since they may be different.
+ SourceEntry oldSourceEntry = fOldState.getSourceEntry(element);
+ oldUnits[i] =
+ (oldSourceEntry == null
+ ? null
+ : fOldState.packageElementFromSourceEntry(oldSourceEntry));
+ SourceEntry newSourceEntry = fNewState.getSourceEntry(element);
+ newUnits[i] = fNewState.packageElementFromSourceEntry(newSourceEntry);
+ if (oldUnits[i] != null) {
+ oldTypeList[i] = oldGraph.getTypes(oldUnits[i]);
+ }
+ }
+
+ // Remove old problems and principal structure from new state before
+ // storing new results.
+ for (int i = 0; i < n; i++) {
+ if (oldUnits[i] != null) {
+ SourceEntry sEntry = fOldState.getSourceEntry(oldUnits[i]);
+ fNewState.getProblemReporter().removeNonSyntaxErrors(sEntry);
+ }
+ if (oldTypeList[i] != null) {
+ IType[] oldTypes = oldTypeList[i];
+ for (int j = 0; j < oldTypes.length; ++j) {
+ fNewState.getPrincipalStructureTable().remove(oldTypes[j]);
+ }
+ }
+ }
+
+ super.updateState(results);
+
+ // now calculate the changes
+ for (int i = 0; i < n; i++) {
+ PackageElement unit = newUnits[i];
+ if (unit == null) {
+ // Unit isn't visible. Shouldn't have gotten this far. Skip it.
+ continue;
+ }
+
+ /**
+ * Assumption: namespace changes have been dealt with before
+ * compilation. Compilation units that were removed have already generated
+ * type collaborator indictments. Here, we are only concerned
+ * with changes within each compilation unit.
+ */
+
+ TypeStructureEntry[] newTSEntries = results[i].getTypes();
+ IndictmentSet indictments = new IndictmentSet();
+
+ /* do for each type generated by unit in old state */
+ IType[] oldTypes = oldTypeList[i];
+ if (oldTypes != null) {
+ for (int j = 0; j < oldTypes.length; ++j) {
+ IType oldType = oldTypes[j];
+ boolean found = false;
+ for (int k = 0; k < newTSEntries.length; ++k) {
+ if (newTSEntries[k] != null && newTSEntries[k].getType().equals(oldType)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ getBuilderType(oldType).computeIndictments(indictments);
+ }
+ }
+ }
+
+ /* do for each type in result */
+ for (int j = 0; j < newTSEntries.length; j++) {
+ TypeStructureEntry newTSEntry = newTSEntries[j];
+ if (newTSEntry != null) {
+ /* compute the indictments for this type */
+ IType type = newTSEntry.getType();
+ BuilderType bType = getBuilderType(type);
+
+ /* the new tsEntry wasn't known at compilation time */
+ if (bType.getNewTypeStructureEntry() == null) {
+ bType.setNewTypeStructureEntry(newTSEntry);
+ }
+ bType.computeIndictments(indictments);
+ }
+ }
+ if (!indictments.isEmpty()) {
+ issueIndictments(unit, indictments, false);
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/Indictment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/Indictment.java
new file mode 100644
index 0000000000..ff906db81c
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/Indictment.java
@@ -0,0 +1,155 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.core.Assert;
+import org.eclipse.jdt.internal.core.builder.*;
+
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+import org.eclipse.jdt.internal.core.Util;
+
+/**
+ * Abstract indictment class. All indictments have a name and
+ * certain behaviour in common.
+ */
+public abstract class Indictment {
+ protected char[] fName;
+ protected int fKind;
+
+ public static final int K_TYPE = 0;
+ public static final int K_METHOD = 1;
+ public static final int K_FIELD = 2;
+ public static final int K_ABSTRACT_METHOD = 3;
+ public static final int K_HIERARCHY = 4;
+ /**
+ * Creates a new indictment with the given name
+ */
+ protected Indictment(char[] name) {
+ fName = name;
+ }
+
+ /**
+ * Creates and returns an indictment.
+ * @param type the originating type of the added or removed abstract
+ * methods.
+ */
+ public static Indictment createAbstractMethodIndictment(IType type) {
+ return new AbstractMethodCollaboratorIndictment(type);
+ }
+
+ /**
+ * Creates and returns an indictment.
+ */
+ public static Indictment createFieldIndictment(IBinaryField field) {
+ return new FieldCollaboratorIndictment(field.getName());
+ }
+
+ /**
+ * Creates and returns an indictment.
+ */
+ public static Indictment createHierarchyIndictment(IBinaryType type) {
+ return new TypeHierarchyIndictment(BinaryStructure.getDeclaredName(type));
+ }
+
+ /**
+ * Creates and returns a method indictment.
+ * Returns null if no indictment should be issued for the method.
+ */
+ public static Indictment createMethodIndictment(
+ IType owner,
+ IBinaryType type,
+ IBinaryMethod method) {
+ /* Is it a clinit? */
+ if (method.getSelector().length > 0
+ && method.getSelector()[0] == '<'
+ && !method.isConstructor()) {
+ return null;
+ }
+ int parmCount = Util.getParameterCount(method.getMethodDescriptor());
+ char[] name;
+ if (method.isConstructor()) {
+ name = CharOperation.concat('<', BinaryStructure.getDeclaredName(type), '>');
+ } else {
+ name = method.getSelector();
+ }
+ return new MethodCollaboratorIndictment(owner, name, parmCount);
+ }
+
+ /**
+ * Creates and returns an indictment.
+ * If the binary type is known, use createTypeIndictment(IBinaryType) instead.
+ * This should only be used when the type is known to be a package member.
+ * The name must be a top level, unqualified name.
+ */
+ public static Indictment createTypeIndictment(String name) {
+ Assert.isTrue(name.indexOf('.') == -1);
+ return new TypeCollaboratorIndictment(name.toCharArray());
+ }
+
+ /**
+ * Creates and returns an indictment.
+ */
+ public static Indictment createTypeIndictment(IBinaryNestedType type) {
+ return new TypeCollaboratorIndictment(BinaryStructure.getDeclaredName(type));
+ }
+
+ /**
+ * Creates and returns an indictment.
+ */
+ public static Indictment createTypeIndictment(IBinaryType type) {
+ return new TypeCollaboratorIndictment(BinaryStructure.getDeclaredName(type));
+ }
+
+ /**
+ * Returns true if indictments are equal, false otherwise
+ */
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null)
+ return false;
+ if (!this.getClass().equals(o.getClass()))
+ return false;
+
+ Indictment i = (Indictment) o;
+ return this.fName.equals(i.fName);
+ }
+
+ /**
+ * Returns the key used by IndictmentSet to organize indictments.
+ */
+ char[] getKey() {
+ return fName;
+ }
+
+ /**
+ * Returns what kind of indictment this is
+ */
+ public abstract int getKind();
+ /**
+ * Returns the key to use for method indictments, where the method has the given
+ * name and parameter count.
+ */
+ static char[] getMethodIndictmentKey(char[] methodName, int parmCount) {
+ return (Util.toString(methodName) + '/' + parmCount).toCharArray();
+ }
+
+ /**
+ * Returns the indictment name. Either the name of a field, method,
+ * type or interface. All type names are unqualified.
+ */
+ public String getName() {
+ return new String(fName);
+ }
+
+ /**
+ * Returns a hashcode for the indictment
+ */
+ public int hashCode() {
+ return getKind() * 10 + fName.hashCode();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/IndictmentSet.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/IndictmentSet.java
new file mode 100644
index 0000000000..2c587f1d81
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/IndictmentSet.java
@@ -0,0 +1,314 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.core.Assert;
+import org.eclipse.jdt.internal.core.builder.IType;
+import org.eclipse.jdt.internal.core.lookup.ReferenceInfo;
+
+import org.eclipse.jdt.internal.compiler.util.*;
+import org.eclipse.jdt.internal.core.Util;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+/**
+ * Represents a set of indictments that reside on a node
+ * in the dependency graph. The keys are strings of the form:
+ * "<indictment name>", values are indictment objects.
+ */
+public class IndictmentSet {
+ /* the tables of indictments */
+ protected HashtableOfObject fTypesTable;
+ protected HashtableOfObject fMethodsTable;
+ protected HashtableOfObject fFieldsTable;
+
+ protected IType[] fMethodOwnersArray;
+
+ protected Hashtable fAbstractMethodTable;
+ protected Hashtable fMethodOwners;
+ protected boolean fHasConstructorIndictments;
+
+ /* whether there is an upstream hierarchy change */
+ private boolean fHierarchyChange = false;
+ public void add(Indictment i) {
+ // allow null, since certain methods are not indicted (class initializers)
+ if (i != null) {
+ switch (i.getKind()) {
+ case Indictment.K_HIERARCHY :
+ fHierarchyChange = true;
+ break;
+ case Indictment.K_TYPE :
+ if (fTypesTable == null)
+ fTypesTable = new HashtableOfObject(11);
+ fTypesTable.put(i.getKey(), i);
+ break;
+ case Indictment.K_METHOD :
+ if (fMethodsTable == null)
+ fMethodsTable = new HashtableOfObject(11);
+ fMethodsTable.put(i.getKey(), i);
+ IType owner = ((MethodCollaboratorIndictment) i).getOwner();
+ if (fMethodOwners == null)
+ fMethodOwners = new Hashtable(11);
+ fMethodOwners.put(owner, owner);
+ fMethodOwnersArray = null;
+ if (i.getName().startsWith("<")) {
+ fHasConstructorIndictments = true;
+ }
+ break;
+ case Indictment.K_FIELD :
+ if (fFieldsTable == null)
+ fFieldsTable = new HashtableOfObject(11);
+ fFieldsTable.put(i.getKey(), i);
+ break;
+ case Indictment.K_ABSTRACT_METHOD :
+ if (fAbstractMethodTable == null)
+ fAbstractMethodTable = new Hashtable(11);
+ fAbstractMethodTable.put(i.getKey(), i);
+ break;
+ default :
+ Assert.isTrue(false, "Unexpected kind of indictment");
+ break;
+ }
+ }
+ }
+
+ /**
+ * Maximum conservatism. Convict all dependents.
+ */
+ public void convictAll() {
+ // TBD: Should have separate flag for this.
+ fHierarchyChange = true;
+ }
+
+ /**
+ * Returns the originators of all abstract method indictments.
+ * If any of these returned types are direct supertypes of the
+ * type on trial, it is found guilty.
+ */
+ public IType[] getAbstractMethodOriginators() {
+ if (fAbstractMethodTable == null) {
+ return new IType[0];
+ }
+ int length = fAbstractMethodTable.size();
+ if (length == 0) {
+ return new IType[0];
+ }
+ IType[] toReturn = new IType[length];
+ int i = 0;
+ for (Enumeration e = fAbstractMethodTable.elements();
+ e.hasMoreElements();
+ i++) {
+ toReturn[i] =
+ ((AbstractMethodCollaboratorIndictment) e.nextElement()).getType();
+ }
+
+ return toReturn;
+ }
+
+ /**
+ * Returns the types for which method indictments were issued.
+ */
+ public IType[] getMethodIndictmentOwners() {
+ if (fMethodOwnersArray == null) {
+ if (fMethodsTable == null) {
+ fMethodOwnersArray = new IType[0];
+ } else {
+ fMethodOwnersArray = new IType[fMethodOwners.size()];
+ int count = 0;
+ for (Enumeration e = fMethodOwners.elements(); e.hasMoreElements();) {
+ fMethodOwnersArray[count++] = (IType) e.nextElement();
+ }
+ }
+ }
+ return fMethodOwnersArray;
+ }
+
+ /**
+ * Returns true if there are any constructor indictments, false otherwise.
+ */
+ public boolean hasConstructorIndictments() {
+ return fHasConstructorIndictments;
+ }
+
+ /**
+ * Returns true if there is a type hierarchy indictment, false otherwise.
+ */
+ public boolean hasHierarchyIndictment() {
+ return fHierarchyChange;
+ }
+
+ /**
+ * Returns true if the indictment set has no indictments, false otherwise.
+ */
+ public boolean isEmpty() {
+ return fMethodsTable == null
+ && fFieldsTable == null
+ && fTypesTable == null
+ && fAbstractMethodTable == null
+ && !fHierarchyChange;
+ }
+
+ /**
+ * Resets the contents of the indictment set. Allows re-use of objects
+ * and saves on garbage.
+ */
+ public void reset() {
+ fMethodsTable = null;
+ fFieldsTable = null;
+ fTypesTable = null;
+ fAbstractMethodTable = null;
+ fHierarchyChange = false;
+ }
+
+ /**
+ * Returns a string representation of the instance.
+ */
+ public String toString() {
+ return "IndictmentSet("
+ + "\n hierarchyChange: "
+ + fHierarchyChange
+ + "\n types:\n"
+ + fTypesTable
+ + "\n interfaces:\n"
+ + fAbstractMethodTable
+ + "\n methods:\n"
+ + fMethodsTable
+ + "\n fields:\n"
+ + fFieldsTable
+ + "\n)";
+
+ }
+
+ /**
+ * Tries all the evidence in the given set of references against the indictments.
+ * Returns true if any evidence matches an indictment, and false otherwise.
+ */
+ public boolean tryAllEvidence(ReferenceInfo references) {
+ char[][] names = references.getNames();
+ byte[] kinds = references.getKinds();
+ int numRefs = names.length;
+
+ /* try all references */
+ for (int i = 0; i < numRefs; i++) {
+ switch (kinds[i]) {
+ case ReferenceInfo.REFTYPE_unknown :
+ case ReferenceInfo.REFTYPE_class :
+ case ReferenceInfo.REFTYPE_type :
+ /* try type indictments */
+ if (fTypesTable != null && fTypesTable.containsKey(names[i])) {
+ return true;
+ }
+ if (kinds[i] != ReferenceInfo.REFTYPE_unknown)
+ break;
+ case ReferenceInfo.REFTYPE_var :
+ /* try field indictments */
+ if (fFieldsTable != null && fFieldsTable.containsKey(names[i])) {
+ return true;
+ }
+ if (kinds[i] != ReferenceInfo.REFTYPE_unknown)
+ break;
+ case ReferenceInfo.REFTYPE_call :
+ /* try method indictments */
+ if (fMethodsTable != null && fMethodsTable.containsKey(names[i])) {
+ return true;
+ }
+ if (kinds[i] != ReferenceInfo.REFTYPE_unknown)
+ break;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Tries an ambiguous name against the set of available indictments. Returns
+ * true if there is a match (guilty), and false if there is no match (not
+ * guilty).
+ */
+ public boolean tryAmbiguousEvidence(char[] name) {
+ if (fFieldsTable == null && fTypesTable == null) {
+ return false;
+ }
+
+ // Try all segments of name
+ int i = 0;
+ int j = CharOperation.indexOf('.', name);
+ while (j >= 0) {
+ char[] segment = CharOperation.subarray(name, i, j);
+ if (tryFieldEvidence(segment) || tryTypeEvidence(segment)) {
+ return true;
+ }
+ i = j + 1;
+ j = CharOperation.indexOf('.', name, i);
+ }
+ char[] segment = CharOperation.subarray(name, i, name.length - 1);
+ return tryFieldEvidence(segment) || tryTypeEvidence(segment);
+ }
+
+ /**
+ * Tries a field name against the set of available indictments. Returns
+ * true if there is a match (guilty), and false if there is no match (not
+ * guilty).
+ */
+ public boolean tryFieldEvidence(char[] name) {
+ return fFieldsTable != null && fFieldsTable.containsKey(name);
+ }
+
+ /**
+ * Tries a method declaration against the set of available indictments.
+ * Returns true if there is a match (guilty), and false if there is no match
+ * (not guilty).
+ */
+ public boolean tryMethodDeclaration(IBinaryMethod method) {
+ if (fMethodsTable != null) {
+ char[] key =
+ Indictment.getMethodIndictmentKey(
+ method.getSelector(),
+ Util.getParameterCount(method.getMethodDescriptor()));
+ if (fMethodsTable.get(key) != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Tries a method name against the set of available indictments. Returns
+ * true if there is a match (guilty), and false if there is no match (not
+ * guilty).
+ * @parm name String of form:
+ * constructor: "<" + NameOfType + ">/" + NumberOfParameters
+ * method: NameOfMethod + "/" + NumberOfParameters
+ */
+ public boolean tryMethodEvidence(char[] name) {
+ return fMethodsTable != null && fMethodsTable.containsKey(name);
+ }
+
+ /**
+ * Tries a type name against the set of available indictments. Returns
+ * true if there is a match (guilty), and false if there is no match (not
+ * guilty).
+ */
+ public boolean tryTypeEvidence(char[] name) {
+ if (fTypesTable != null) {
+ if (fTypesTable.containsKey(name)) {
+ return true;
+ }
+
+ /* it may be a qualified name */
+ int lastDot = CharOperation.lastIndexOf('.', name);
+ if (lastDot != -1) {
+ char[] key = CharOperation.subarray(name, lastDot + 1, name.length - 1);
+ if (fTypesTable.containsKey(key)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/JCUNode.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/JCUNode.java
new file mode 100644
index 0000000000..cf188968d1
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/JCUNode.java
@@ -0,0 +1,101 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.builder.*;
+
+import java.util.*;
+
+/**
+ *
+ */
+public class JCUNode extends AbstractNode {
+ /* The compilation unit */
+ PackageElement fUnit;
+
+ /* The types that belong to the compilation unit */
+ IType[] fTypes;
+
+ /* empty types list */
+ protected static final IType[] fgNoTypes = new IType[0];
+ public JCUNode(PackageElement unit) {
+ fUnit = unit;
+ fTypes = fgNoTypes;
+ }
+
+ public JCUNode(PackageElement unit, IType[] types) {
+ fUnit = unit;
+
+ /* never let types be null */
+ fTypes = types == null ? fgNoTypes : types;
+ }
+
+ /**
+ * Returns a copy of this node, without copying dependencies. Used
+ * by DependencyGraph.copy().
+ */
+ public AbstractNode copy() {
+ return new JCUNode(fUnit, fTypes);
+ }
+
+ /**
+ * Returns the element which this node represents.
+ */
+ public Object getElement() {
+ return fUnit;
+ }
+
+ /**
+ * Returns the number of bytes that this node uses.
+ * For debugging and profiling purposes only.
+ */
+ int getFootprint() {
+ int size = super.getFootprint();
+
+ /* slot for package element */
+ size += 4;
+
+ /* slots for types */
+ if (fTypes != null) {
+ size += fTypes.length * 4;
+ }
+ return size;
+ }
+
+ /**
+ * Returns what kind of node this is.
+ */
+ public int getKind() {
+ return JCU_NODE;
+ }
+
+ public PackageElement getPackageElement() {
+ return fUnit;
+ }
+
+ /**
+ * Returns the types that belong to this compilation unit
+ */
+ public IType[] getTypes() {
+ return fTypes;
+ }
+
+ /**
+ * Sets the types that belong to this compilation unit
+ */
+ public void setTypes(IType[] types) {
+ /* never let types be null */
+ fTypes = types == null ? fgNoTypes : types;
+ }
+
+ /**
+ * Prints a string representation of the node. This method is for debugging
+ * purposes only.
+ */
+ public String toString() {
+ return "JCUNode(" + fUnit.getFileName() + ")";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/JavaBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/JavaBuilder.java
new file mode 100644
index 0000000000..78a151854f
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/JavaBuilder.java
@@ -0,0 +1,369 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.core.builder.*;
+import org.eclipse.jdt.internal.core.*;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * The Java Image Builder, which is a VA/Base builder.
+ */
+public class JavaBuilder extends IncrementalProjectBuilder {
+
+ /**
+ * Flag indicating whether to persist built states between sessions.
+ */
+ public static final boolean SAVE_ENABLED = true;
+ /**
+ * Constructs a new Java Builder.
+ */
+ public JavaBuilder() {
+ }
+
+ /**
+ * Run the Java Image Builder.
+ */
+ protected IProject[] build(int kind, Map map, IProgressMonitor monitor)
+ throws CoreException {
+
+ if (!this.getProject().exists())
+ return new IProject[0];
+ //if (!((JavaProject)getJavaProject()).hasSource()) return new IProject[0];
+
+ JavaDevelopmentContextImpl dc = getDevelopmentContext();
+ dc.setProgressMonitor(monitor);
+ boolean ok = false;
+ try {
+ if (kind == FULL_BUILD) {
+ fullBuild(dc, monitor);
+ } else {
+ Hashtable deltas = checkIncrementalBuild(monitor);
+ if (deltas == null) {
+ fullBuild(dc, monitor);
+ } else {
+ incrementalBuild(dc, deltas, monitor);
+ }
+ }
+ ok = true;
+ } catch (ImageBuilderInternalException e) {
+ // Fix for 1FW2XY6: ITPJCORE:ALL - Image builder wrappers CoreException
+ if (e.getThrowable() instanceof CoreException) {
+ throw (CoreException) e.getThrowable();
+ } else {
+ throw new CoreException(
+ new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, "Java Builder", e));
+ }
+ } catch (OperationCanceledException e) {
+ // Do nothing for now, and avoid propagating the exception.
+ // The finally block ensures we will do a full build next time.
+ // See 1FVJ5Z8: ITPCORE:ALL - How should builders handle cancel?
+ } finally {
+ // Don't let DC hang onto progress monitor.
+ dc.setProgressMonitor(null);
+ if (!ok) {
+ // If the build failed, clear out the previously built state,
+ // forcing a full build next time.
+ setLastBuiltState(null);
+ }
+ if (monitor != null)
+ monitor.subTask("Java build completed");
+ }
+ return getRequiredProjects(getLastBuiltState(monitor));
+ }
+
+ /**
+ * Checks whether we can do an incremental build.
+ * Returns a hashtable containing all the required deltas if yes, null if no.
+ *
+ * @return hashtable mapping from IProject to IResourceDelta for all required project deltas, or null
+ */
+ protected Hashtable checkIncrementalBuild(IProgressMonitor monitor)
+ throws CoreException {
+ IState oldState = getLastBuiltState(monitor);
+ if (oldState == null) {
+ //System.out.println("No previous built state for: "+getProject().getName());
+ return null;
+ }
+ Hashtable deltas = new Hashtable(11);
+ IProject project = getProject();
+
+ if (monitor != null)
+ monitor.subTask(
+ "Reading resource change information for :" + project.getName());
+ IResourceDelta delta = getDelta(project);
+ if (delta == null) {
+ //System.out.println("Missing delta for: "+ project.getName());
+ if (monitor != null)
+ monitor.subTask("");
+ return null;
+ } else {
+ deltas.put(project, delta);
+ }
+ IProject[] prereqs = getRequiredProjects(oldState);
+ for (int i = 0; i < prereqs.length; ++i) {
+ if (monitor != null)
+ monitor.subTask(
+ "Reading resource change information for :" + prereqs[i].getName());
+ delta = getDelta(prereqs[i]);
+ if (delta == null) {
+ //System.out.println("Missing delta for: "+ prereqs[i].getName());
+ if (monitor != null)
+ monitor.subTask("");
+ return null;
+ } else {
+ deltas.put(prereqs[i], delta);
+ }
+ }
+ if (monitor != null)
+ monitor.subTask("");
+ return deltas;
+ }
+
+ /**
+ * Returns true if the class path has changed since the last built state.
+ */
+ protected boolean classpathChanged(IState lastBuiltState)
+ throws CoreException {
+ try {
+ IPackageFragmentRoot[] oldRoots =
+ ((StateImpl) lastBuiltState).getPackageFragmentRootsInClassPath();
+ IPackageFragmentRoot[] newRoots =
+ ((JavaProject) getJavaProject()).getBuilderRoots(null);
+ return !Util.equalArraysOrNull(oldRoots, newRoots);
+ } catch (JavaModelException e) {
+ throw new CoreException(
+ new Status(
+ IStatus.ERROR,
+ JavaCore.PLUGIN_ID,
+ Platform.PLUGIN_ERROR,
+ "Project " + getProject().getFullPath() + " not present",
+ e));
+ }
+ }
+
+ /**
+ * Runs a full build.
+ */
+ protected void fullBuild(
+ JavaDevelopmentContextImpl dc,
+ IProgressMonitor monitor)
+ throws CoreException {
+ IProject project = getProject();
+ //System.out.println("FULL build of: "+project.getName());
+
+ /* create problem reporter and clear all problems */
+ IProblemReporter problemReporter = new MarkerProblemReporter(project, dc);
+ problemReporter.removeProblems(project);
+
+ /* create and invoke the batch builder */
+ // Pass the compiler options, needed for 1FVXS80: ITPJCORE:ALL - .class files are missing their LocalVariableTable
+ ConfigurableOption[] options =
+ JavaModelManager.convertConfigurableOptions(JavaCore.getOptions());
+ setLastBuiltState(null); // free possible existing state
+ IImageBuilder builder = dc.createState(project, null, problemReporter, options);
+ setLastBuiltState(builder.getNewState());
+ }
+
+ /**
+ * Returns the development context to use for this builder.
+ */
+ protected JavaDevelopmentContextImpl getDevelopmentContext() {
+ return (JavaDevelopmentContextImpl) JavaModelManager
+ .getJavaModelManager()
+ .getDevelopmentContext(getProject());
+ }
+
+ /**
+ * Returns the Java view of the project.
+ */
+ protected IJavaProject getJavaProject() {
+ return JavaCore.create(getProject());
+ }
+
+ /**
+ * Returns the last built state for this builder.
+ */
+ protected IState getLastBuiltState(IProgressMonitor monitor) {
+ return JavaModelManager.getJavaModelManager().getLastBuiltState(
+ getProject(),
+ monitor);
+ }
+
+ /**
+ * Returns a problem factory for the given locale.
+ */
+ public IProblemFactory getProblemFactory(Locale locale) {
+ return ProblemFactory.getProblemFactory(locale);
+ }
+
+ /**
+ * Returns the prerequisite projects for the given built state.
+ * Returns an empty array if state is null.
+ *
+ * @param the state or null
+ */
+ protected IProject[] getRequiredProjects(IState state) {
+ if (state == null) {
+ return new IProject[0];
+ }
+ // This must not assume the given state is the current one.
+ // It may be the old state.
+ IProject project = getProject();
+ IProject[] all = ((StateImpl) state).getClassPathProjects();
+ Vector v = new Vector();
+ for (int i = 0; i < all.length; ++i) {
+ if (!all[i].equals(project)) {
+ v.addElement(all[i]);
+ }
+ }
+ IProject[] result = new IProject[v.size()];
+ v.copyInto(result);
+ return result;
+ }
+
+ /**
+ * Runs an incremental build.
+ *
+ * @param deltas maps from IProject to IResourceDelta for this builder's project and all prerequisite projects
+ */
+ protected void incrementalBuild(
+ JavaDevelopmentContextImpl dc,
+ Hashtable deltas,
+ IProgressMonitor monitor)
+ throws CoreException {
+ IProject project = getProject();
+ //System.out.println("INCREMENTAL build of: "+project.getName());
+ StateImpl oldState = (StateImpl) getLastBuiltState(monitor);
+ if (needIncrementalBuild(oldState, deltas)) {
+ IncrementalImageBuilder builder =
+ new IncrementalImageBuilder(oldState, project, null);
+ builder.applySourceDelta(deltas);
+ setLastBuiltState(builder.getNewState());
+ } else {
+ /* Still update resources in binary output */
+ BuildNotifier notifier =
+ new BuildNotifier((JavaDevelopmentContextImpl) dc, false);
+ notifier.begin();
+ try {
+ ProjectResourceCopier copier =
+ new ProjectResourceCopier(getJavaProject(), dc, notifier, 1.0f);
+ IResourceDelta change = (IResourceDelta) deltas.get(project);
+ copier.updateAffectedResources(change);
+ } finally {
+ notifier.done();
+ }
+ }
+ }
+
+ /**
+ * Checks whether this is an empty delta as far as the builder is concerned.
+ */
+ protected boolean isEmpty(IResourceDelta change) {
+ // Made checks more selective for 1FW1S0Y: ITPJCORE:ALL - Java builder builds when non-Java files affected
+ if (change == null)
+ return true;
+ int kind = change.getKind();
+ boolean isAdded = kind == IResourceDelta.ADDED;
+ boolean isRemoved = kind == IResourceDelta.REMOVED;
+ boolean isChanged = kind == IResourceDelta.CHANGED;
+ int flags = change.getFlags();
+ boolean contentChanged = isChanged && (flags & IResourceDelta.CONTENT) != 0;
+ String extension = change.getFullPath().getFileExtension();
+ boolean isJavaOrClassFile =
+ extension != null
+ && (extension.equalsIgnoreCase("java") || extension.equalsIgnoreCase("class"));
+ boolean isArchive =
+ extension != null
+ && (extension.equalsIgnoreCase("zip") || extension.equalsIgnoreCase("jar"));
+
+ // care about added, removed and modified (content actually modified) .java and .class files
+ if (isJavaOrClassFile && (isAdded || isRemoved || contentChanged))
+ return false;
+ // care about added, removed and modified (content actually modified) .jar and .zip files
+ if (isArchive && (isAdded || isRemoved || contentChanged))
+ return false;
+
+ // care about all folder additions and removals since they may represent package fragments
+ IResource resource = change.getResource();
+ if (resource != null) {
+ int type = resource.getType();
+ // may have been a container previously if its type is changing
+ boolean isFolder =
+ (flags & IResourceDelta.TYPE) != 0 || type == IResource.FOLDER;
+ if (isFolder && (isAdded || isRemoved))
+ return false;
+ }
+ // recurse on children
+ IResourceDelta[] children = change.getAffectedChildren();
+ for (int i = 0; i < children.length; ++i) {
+ if (!isEmpty(children[i]))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Checks whether an incremental build is really necessary.
+ */
+ protected boolean needIncrementalBuild(StateImpl oldState, Hashtable deltas)
+ throws CoreException {
+ if (classpathChanged(oldState)) {
+ return true;
+ }
+ for (Enumeration e = deltas.elements(); e.hasMoreElements();) {
+ IResourceDelta delta = (IResourceDelta) e.nextElement();
+ if (!isEmpty(delta)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the output location has changed since the last built state.
+ */
+ protected boolean outputLocationChanged(IState lastBuiltState)
+ throws CoreException {
+ try {
+ IPath oldOutputLocation = ((StateImpl) lastBuiltState).getOutputLocation();
+ IPath newOutputLocation = getJavaProject().getOutputLocation();
+ return !oldOutputLocation.equals(newOutputLocation);
+ } catch (JavaModelException e) {
+ throw new CoreException(
+ new Status(
+ IStatus.ERROR,
+ JavaCore.PLUGIN_ID,
+ Platform.PLUGIN_ERROR,
+ "Project " + getProject().getFullPath() + " not present",
+ e));
+ }
+ }
+
+ protected void setLastBuiltState(IState state) {
+ JavaModelManager.getJavaModelManager().setLastBuiltState(getProject(), state);
+ }
+
+ /**
+ * String representation for debugging purposes
+ */
+ public String toString() {
+ IState lastBuiltState = getLastBuiltState(null);
+ if (lastBuiltState == null) {
+ return "JavaBuilder(no built state)";
+ } else {
+ return "JavaBuilder(" + lastBuiltState + ")";
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/JavaDevelopmentContextImpl.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/JavaDevelopmentContextImpl.java
new file mode 100644
index 0000000000..8f04c48dcd
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/JavaDevelopmentContextImpl.java
@@ -0,0 +1,476 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.jdt.internal.core.builder.*;
+import java.io.*;
+import java.util.*;
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.internal.core.util.IProgressListener;
+import org.eclipse.jdt.internal.compiler.ConfigurableOption;
+import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
+
+public class JavaDevelopmentContextImpl implements IDevelopmentContext {
+
+ /**
+ * The default current state
+ */
+ protected StateImpl fCurrentState;
+
+ /**
+ * A handle to the image for this develoment context
+ */
+ private IImage fImage = new ImageImpl(this);
+
+ /**
+ * The binary broker output for storing compiled binaries
+ */
+ private BinaryBrokerOutput fBinaryBrokerOutput;
+
+ /**
+ * The build monitor for tracking what has been compiled -- only used for testing
+ */
+ private IBuildMonitor fBuildMonitor;
+
+ /**
+ * The progress monitor. It is the client's responsibility to set
+ * the monitor.
+ */
+ private IProgressMonitor fProgressMonitor = null;
+
+ /**
+ * List of build listeners which get notified when things are (re)compiled or removed.
+ */
+ private Vector fBuildListeners = new Vector(1);
+
+ /**
+ * The default package.
+ */
+ private final IPackage fDefaultPackage =
+ fImage.getPackageHandle("java.lang", false);
+
+ /**
+ * The root class handle
+ */
+ private final IType fRootClass = fDefaultPackage.getClassHandle("Object");
+
+ /**
+ * Primitive types
+ */
+ final IType fVoidType = new PrimitiveTypeHandleImpl(this, 'V');
+ final IType fIntType = new PrimitiveTypeHandleImpl(this, 'I');
+ final IType fByteType = new PrimitiveTypeHandleImpl(this, 'B');
+ final IType fCharType = new PrimitiveTypeHandleImpl(this, 'C');
+ final IType fDoubleType = new PrimitiveTypeHandleImpl(this, 'D');
+ final IType fFloatType = new PrimitiveTypeHandleImpl(this, 'F');
+ final IType fLongType = new PrimitiveTypeHandleImpl(this, 'J');
+ final IType fShortType = new PrimitiveTypeHandleImpl(this, 'S');
+ final IType fBooleanType = new PrimitiveTypeHandleImpl(this, 'Z');
+
+ /**
+ * Whether the compiler is in the call stack.
+ */
+ boolean inCompiler;
+ /**
+ * Create a new Java DC.
+ */
+ public JavaDevelopmentContextImpl() {
+ }
+
+ /**
+ * @see IDevelopmentContext
+ */
+ public void addBuildListener(IBuildListener buildListener) {
+ fBuildListeners.addElement(buildListener);
+ }
+
+ /**
+ * Returns a class type handle corresponding to the given
+ * (fully qualified) class type name.
+ */
+ protected IType classTypeFromName(final String name) {
+
+ /* strip off the leading "L" and trailing ";" */
+ String localName = name.substring(1, name.length() - 1);
+ int lastDot = localName.lastIndexOf('.');
+ IPackage pkg;
+ if (lastDot == -1) {
+ pkg = getImage().getPackageHandle(IPackageFragment.DEFAULT_PACKAGE_NAME, true);
+ } else {
+ pkg = this.packageHandleFromSignature(localName.substring(0, lastDot));
+ }
+ return pkg.getClassHandle(localName.substring(lastDot + 1, localName.length()));
+ }
+
+ /**
+ * @see IDevelopmentContext
+ */
+ public IImageBuilder createState(
+ IProject project,
+ IImageContext buildContext) {
+ return createState(project, buildContext, (IProblemReporter) null);
+ }
+
+ /**
+ * @see IDevelopmentContext
+ */
+ public IImageBuilder createState(
+ IProject project,
+ IImageContext buildContext,
+ IProblemReporter problemReporter) {
+ return createState(
+ project,
+ buildContext,
+ problemReporter,
+ getDefaultCompilerOptions());
+ }
+
+ /**
+ * @see IDevelopmentContext
+ */
+ public IImageBuilder createState(
+ IProject project,
+ IImageContext buildContext,
+ IProblemReporter problemReporter,
+ ConfigurableOption[] compilerOptions) {
+ StateImpl state = new StateImpl(this, project, buildContext);
+ BatchImageBuilder builder = new BatchImageBuilder(state, compilerOptions);
+ if (problemReporter != null) {
+ state.setProblemReporter(problemReporter);
+ }
+ builder.build();
+ return builder;
+ }
+
+ /**
+ * @see IDevelopmentContext
+ */
+ public void garbageCollect(IState[] statesInUse) {
+ getBinaryOutput().garbageCollect(statesInUse);
+ }
+
+ /**
+ * Returns the binary broker for this development context.
+ * Returns null if none has been assigned to the DC.
+ */
+ public IBinaryBroker getBinaryBroker() {
+ if (fBinaryBrokerOutput == null)
+ return null;
+ else
+ return fBinaryBrokerOutput.getBinaryBroker();
+ }
+
+ /**
+ * Workaround for 1GAMR1K: ITPCORE:Platform should be more fault tolerant
+ */
+ byte[] getBinaryFromFileSystem(org.eclipse.core.resources.IFile file) {
+ try {
+ String osPath = file.getLocation().toOSString();
+ InputStream input = new java.io.FileInputStream(osPath);
+ return org.eclipse.jdt.internal.core.Util.readContentsAsBytes(input);
+ } catch (IOException e) {
+ return new byte[0];
+ }
+ }
+
+ /**
+ * Returns the binary output for this development context.
+ */
+ public BinaryOutput getBinaryOutput() {
+ return fBinaryBrokerOutput;
+ }
+
+ /**
+ * Returns the vector of build listeners.
+ */
+ protected Vector getBuildListeners() {
+ return fBuildListeners;
+ }
+
+ /**
+ * Returns the build monitor.
+ */
+ public IBuildMonitor getBuildMonitor() {
+ return fBuildMonitor;
+ }
+
+ public IState getCurrentState() throws NotPresentException {
+ if (fCurrentState == null) {
+ throw new NotPresentException("no current state");
+ }
+ return fCurrentState;
+ }
+
+ /**
+ * Reads the default compiler options.
+ */
+ protected static ConfigurableOption[] getDefaultCompilerOptions() {
+ ConfigurableOption[] options = Compiler.getDefaultOptions(Locale.getDefault());
+
+ /**
+ * Ugly because this requires knowledge of the compiler's
+ * internal problem representation.
+ */
+ setCompilerOption(options, 11, 1);
+ setCompilerOption(options, 12, 1);
+ return options;
+ }
+
+ /**
+ * Returns the default package handle (java.lang).
+ */
+ protected IPackage getDefaultPackage() {
+ return fDefaultPackage;
+ }
+
+ /**
+ * Returns the image handle
+ */
+ public IImage getImage() {
+ return fImage;
+ }
+
+ /**
+ * Returns the progress monitor. Returns null if one hasn't been set.
+ */
+ public IProgressMonitor getProgressMonitor() {
+ return fProgressMonitor;
+ }
+
+ protected IType getRootClassHandle() {
+ return fRootClass;
+ }
+
+ /**
+ * Process an internal exception: if we're being called by the compiler, throw an AbortCompilation
+ * otherwise throw an internal image builder exception.
+ */
+ protected RuntimeException internalException(String message) {
+ ImageBuilderInternalException imageBuilderException =
+ new ImageBuilderInternalException(message);
+ if (this.inCompiler) {
+ return new AbortCompilation(true, imageBuilderException);
+ } else {
+ return imageBuilderException;
+ }
+ }
+
+ /**
+ * Process an internal exception: if we're being called by the compiler, throw an AbortCompilation
+ * otherwise throw an internal image builder exception.
+ */
+ protected RuntimeException internalException(Throwable t) {
+ ImageBuilderInternalException imageBuilderException =
+ new ImageBuilderInternalException(t);
+ if (this.inCompiler) {
+ return new AbortCompilation(true, imageBuilderException);
+ } else {
+ return imageBuilderException;
+ }
+ }
+
+ /**
+ * Returns a new package handle for the given signature.
+ */
+ public IPackage packageHandleFromSignature(String signature) {
+ return new PackageImpl(this, signature, false);
+ }
+
+ /**
+ * Returns the parameter type handles, extracted from the given method
+ * or constructor signature. Parameter names can either be fully
+ * qualified VM type names, or DC API source signature names. The
+ * class java.lang.String would be represented as either:
+ * VM name: Ljava.lang.String;
+ * DC name: QString;
+ */
+ protected IType[] parameterTypesFromSignature(final String signature) {
+ Vector typeVector = new Vector();
+
+ /* The signature looks like this:
+ * name(<parm1><parm2><parm3>...)<return type>
+ */
+
+ /* extract parameters from signature */
+ String localSig =
+ signature.substring(signature.indexOf('(') + 1, signature.lastIndexOf(')'));
+
+ /* parse each parameter */
+ while (localSig.length() > 0) {
+
+ /*
+ * Each parameter can be defined by the following productions:
+ * parameter: arrayType
+ * arrayType: [arrayType OR type
+ * type: L<classname>; OR <single character for base type>
+ */
+
+ /* skip array characters */
+ int position = 0;
+ while (localSig.charAt(position) == '[') {
+ position++;
+ }
+ IType parmType;
+ char c = localSig.charAt(position);
+ if (c == 'L' || c == 'Q') {
+ /* its a class type */
+ int endIndex = localSig.indexOf(";") + 1;
+ parmType = classTypeFromName(localSig.substring(position, endIndex));
+ localSig = localSig.substring(endIndex);
+ } else {
+ /* its a base type */
+ parmType = primitiveTypeFromTypeCode(localSig.charAt(position));
+ localSig = localSig.substring(position + 1);
+ }
+
+ /* if its an array type */
+ if (position != 0) {
+ parmType = new ArrayTypeHandleImpl((TypeImpl) parmType, position);
+ }
+ typeVector.addElement(parmType);
+ }
+
+ /* convert results vector to an array */
+ IType[] results = new IType[typeVector.size()];
+ typeVector.copyInto(results);
+ return results;
+ }
+
+ /**
+ * Returns a primitive type handle corresponding to the given type code char.
+ * Returns nulll if type code is not a valid primitive type code.
+ */
+ protected IType primitiveTypeFromTypeCode(char typeCode) {
+ switch (typeCode) {
+ case 'V' :
+ return fVoidType;
+ case 'I' :
+ return fIntType;
+ case 'B' :
+ return fByteType;
+ case 'C' :
+ return fCharType;
+ case 'D' :
+ return fDoubleType;
+ case 'F' :
+ return fFloatType;
+ case 'J' :
+ return fLongType;
+ case 'S' :
+ return fShortType;
+ case 'Z' :
+ return fBooleanType;
+ default :
+ return null;
+ }
+ }
+
+ /**
+ * @see IDevelopmentContext
+ */
+ public void removeBuildListener(IBuildListener buildListener) {
+ fBuildListeners.removeElement(buildListener);
+ }
+
+ /**
+ * @see IDevelopmentContext.
+ */
+ public IState restoreState(IProject project, DataInputStream in)
+ throws IOException {
+ try {
+ return new StateSnap().read(this, project, in);
+ } catch (RuntimeException e) {
+ System.out.println("RuntimeException restoring state:");
+ e.printStackTrace();
+ throw e;
+ } catch (Error e) {
+ System.out.println("Error restoring state:");
+ e.printStackTrace();
+ throw e;
+ }
+ }
+
+ /**
+ * @see IDevelopmentContext.
+ */
+ public void saveState(IState state, DataOutputStream out) throws IOException {
+ try {
+ new StateSnap().save((StateImpl) state, out);
+ } catch (IOException e) {
+ System.out.println("IOException saving state: ");
+ e.printStackTrace();
+ throw e;
+ } catch (RuntimeException e) {
+ System.out.println("RuntimeException saving state: ");
+ e.printStackTrace();
+ throw e;
+ } catch (Error e) {
+ System.out.println("Error saving state:");
+ e.printStackTrace();
+ throw e;
+ }
+ }
+
+ /**
+ * Sets the binary broker for this developent context
+ */
+ public void setBinaryBroker(IBinaryBroker broker) {
+ if (broker == null)
+ fBinaryBrokerOutput = null;
+ else
+ fBinaryBrokerOutput = new BinaryBrokerOutput(broker);
+ }
+
+ /**
+ * Sets the build monitor. The build monitor is a hook used
+ * by the test suites to test the image builder's efficiency.
+ */
+ public void setBuildMonitor(IBuildMonitor monitor) {
+ fBuildMonitor = monitor;
+ }
+
+ /**
+ * Sets the build progress listener for this development context
+ */
+ public void setBuildProgressListener(IProgressListener listener) {
+ }
+
+ /**
+ * Sets a compiler option. This seems awkward.
+ */
+ protected static void setCompilerOption(
+ ConfigurableOption[] options,
+ int optionID,
+ int valueIndex) {
+ for (int i = 0; i < options.length; i++) {
+ if (options[i].getID() == optionID) {
+ options[i].setValueIndex(valueIndex);
+ return;
+ }
+ }
+ }
+
+ /**
+ * setCurrentState method comment.
+ */
+ public void setCurrentState(IState state) {
+ fCurrentState = (StateImpl) state;
+ }
+
+ /**
+ * Sets the progress monitor for all build activities.
+ */
+ public void setProgressMonitor(IProgressMonitor monitor) {
+ fProgressMonitor = monitor;
+ }
+
+ public String toString() {
+ return "a JavaDevelopmentContextImpl(" + fCurrentState + ")";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/MarkerProblemReporter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/MarkerProblemReporter.java
new file mode 100644
index 0000000000..39ac0f483c
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/MarkerProblemReporter.java
@@ -0,0 +1,299 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+
+import org.eclipse.jdt.internal.core.builder.*;
+import org.eclipse.jdt.core.*;
+
+import java.util.*;
+
+/**
+ * An <code>IProblemReporter</code> that reports problems using the <code>IMarker</code> API.
+ * It keeps the problems backed in a ProblemTable as well, since the marker manager only
+ * maintains problems for the last built state.
+ * In particular, the test suite requires that problems be retrieved for previously built states,
+ * and for currently built states (batch and incremental builds of the same workspace).
+ */
+public class MarkerProblemReporter implements IProblemReporter {
+ protected IProject fProject;
+ protected ProblemTable fProblemTable = new ProblemTable();
+ private IDevelopmentContext dc;
+ /**
+ * Creates a new MarkerProblemReporter that is not initialized.
+ * Used only during deserialization.
+ */
+ public MarkerProblemReporter() {
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.core.builder.IProblemReporter
+ */
+ public IProblemReporter copy() {
+ /* The copy still reports to the same marker manager, since there's only one,
+ * but the backing problem table is copied. */
+ MarkerProblemReporter copy = new MarkerProblemReporter(fProject, this.dc);
+ copy.fProblemTable = (ProblemTable) fProblemTable.copy();
+ return copy;
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.core.builder.IProblemReporter
+ */
+ public Enumeration getAllProblems() {
+ return fProblemTable.getAllProblems();
+ }
+
+ /**
+ * Returns the extra flags for the given marker.
+ */
+ protected int getFlags(IMarker marker) throws CoreException {
+ if (!marker.exists())
+ return 0;
+ Integer flags = (Integer) marker.getAttribute(IJavaModelMarker.FLAGS);
+ return flags == null ? 0 : flags.intValue();
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.core.builder.IProblemReporter
+ */
+ public Enumeration getImageProblems() {
+ return fProblemTable.getImageProblems();
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.core.builder.IProblemReporter
+ */
+ public Enumeration getProblemKeys() {
+ return fProblemTable.getProblemKeys();
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.core.builder.IProblemReporter
+ */
+ public Enumeration getProblems(Object sourceID) {
+ return fProblemTable.getProblems(sourceID);
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.core.builder.IProblemReporter
+ */
+ public Vector getProblemVector(Object sourceID) {
+ return fProblemTable.getProblemVector(sourceID);
+ }
+
+ /**
+ * Returns the resource for the given source ID.
+ * Returns null if the source ID is not a SourceEntry or resource,
+ * or if the resource could not be found.
+ */
+ protected IResource getResource(Object sourceID) {
+ if (sourceID instanceof IResource) {
+ return (IResource) sourceID;
+ }
+ if (!(sourceID instanceof SourceEntry))
+ return null;
+ SourceEntry entry = (SourceEntry) sourceID;
+ IPath path = entry.getPath();
+ if (path.isAbsolute()) {
+ if (fProject.getFullPath().isPrefixOf(path)) {
+ return fProject.getWorkspace().getRoot().getFile(path);
+ }
+ } else {
+ return fProject.getFile(path);
+ }
+ return null;
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.core.builder.IProblemReporter
+ */
+ public boolean hasProblems(Object sourceID) {
+ return fProblemTable.hasProblems(sourceID);
+ }
+
+ /**
+ * Creates a marker from the given problem detail and add it to the resource.
+ * The marker is as follows:
+ * - its type is T_PROBLEM
+ * - its plugin ID is the JavaBuilder's plugin ID
+ * - its message is the problem's message
+ * - its priority reflects the severity of the problem
+ * - its range is the problem's range
+ * - it has an extra attribute "ID" which holds the problem's id
+ */
+ protected void markerFromProblemDetail(
+ IResource resource,
+ IProblemDetail problem)
+ throws CoreException {
+
+ IMarker marker =
+ resource.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
+
+ marker.setAttribute(IMarker.MESSAGE, problem.getMessage());
+
+ int sev = problem.getSeverity();
+ marker.setAttribute(
+ IMarker.SEVERITY,
+ ((sev & IProblemDetail.S_ERROR) != 0
+ ? IMarker.SEVERITY_ERROR
+ : IMarker.SEVERITY_WARNING));
+ if ((sev & ProblemDetailImpl.S_SYNTAX_ERROR) != 0) {
+ setFlags(marker, ProblemDetailImpl.S_SYNTAX_ERROR);
+ }
+ marker.setAttribute("ID", new Integer(problem.getID()));
+
+ int start = problem.getStartPos();
+ marker.setAttribute(IMarker.CHAR_START, new Integer(start));
+ marker.setAttribute(IMarker.CHAR_END, new Integer(problem.getEndPos() + 1));
+ marker.setAttribute(IMarker.LINE_NUMBER, new Integer(problem.getLineNumber()));
+
+ // compute a user-friendly location
+ IJavaElement element = JavaCore.create(resource);
+ if (element instanceof ICompilationUnit) {
+ // try to find a finer grain element
+ ICompilationUnit unit = (ICompilationUnit) element;
+ IJavaElement fragment = unit.getElementAt(start);
+ if (fragment != null)
+ element = fragment;
+ }
+ String location = null;
+ if (element instanceof org.eclipse.jdt.internal.core.JavaElement) {
+ location = ((org.eclipse.jdt.internal.core.JavaElement) element).readableName();
+ }
+ if (location != null)
+ marker.setAttribute(IMarker.LOCATION, location);
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.core.builder.IProblemReporter
+ */
+ public void putProblem(Object sourceID, IProblemDetail problem) {
+ /* Delegate first to the backing problem table. */
+ fProblemTable.putProblem(sourceID, problem);
+
+ /* Now update the markers. */
+ IResource resource = getResource(sourceID);
+ if (resource != null) {
+ try {
+ markerFromProblemDetail(resource, problem);
+ } catch (CoreException e) {
+ throw ((JavaDevelopmentContextImpl) this.dc).internalException(e);
+ }
+ }
+ }
+
+ /**
+ * Remove problem markers for the given element. If removeSyntaxErrors is true, remove only syntax errors,
+ * otherwise remove only non-syntax errors.
+ */
+ protected void removeMarkers(Object sourceID, boolean removeSyntaxErrors) {
+ IResource resource = getResource(sourceID);
+ if (resource != null && resource.exists()) {
+ try {
+ IMarker[] markers =
+ resource.findMarkers(
+ IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER,
+ false,
+ IResource.DEPTH_INFINITE);
+ if (markers.length > 0) {
+ Vector toRemove = new Vector(markers.length);
+ for (int i = 0; i < markers.length; i++) {
+ IMarker marker = markers[i];
+ try {
+ boolean isSyntaxError =
+ (getFlags(marker) & ProblemDetailImpl.S_SYNTAX_ERROR) != 0;
+ if (isSyntaxError == removeSyntaxErrors) {
+ toRemove.addElement(marker);
+ }
+ } catch (CoreException e) { // marker state cannot be accessed - ignore it
+ }
+ }
+ if (toRemove.size() > 0) {
+ IMarker[] markersToRemove = new IMarker[toRemove.size()];
+ toRemove.copyInto(markersToRemove);
+ resource.getWorkspace().deleteMarkers(markersToRemove);
+ }
+ }
+ } catch (CoreException e) { // silently absorb CoreException during marker deletion
+ }
+ }
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.core.builder.IProblemReporter
+ */
+ public void removeNonSyntaxErrors(Object sourceID) {
+ /* Delegate first to the backing problem table. */
+ fProblemTable.removeNonSyntaxErrors(sourceID);
+
+ removeMarkers(sourceID, false);
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.core.builder.IProblemReporter
+ */
+ public void removeProblems(Object sourceID) {
+ /* Delegate first to the backing problem table. */
+ fProblemTable.removeProblems(sourceID);
+
+ /* Now update the markers. */
+ IResource resource = getResource(sourceID);
+ if (resource != null) {
+ try {
+ // See PR 1G2NPUH
+ // If the resource doesn't exist, we don't want to try to remove markers for it.
+ // Simply ignore. This test is done to prevent from having an exception.
+ if (resource.exists())
+ resource.deleteMarkers(
+ IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER,
+ false,
+ IResource.DEPTH_INFINITE);
+ } catch (CoreException e) {
+ throw ((JavaDevelopmentContextImpl) this.dc).internalException(e);
+ }
+ }
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.core.builder.IProblemReporter
+ */
+ public void removeSyntaxErrors(Object sourceID) {
+ /* Delegate first to the backing problem table. */
+ fProblemTable.removeSyntaxErrors(sourceID);
+
+ removeMarkers(sourceID, true);
+ }
+
+ /**
+ * Sets the extra flags for the given marker.
+ */
+ protected void setFlags(IMarker marker, int flags) throws CoreException {
+ // Don't take space if no extra flags.
+ marker.setAttribute(
+ IJavaModelMarker.FLAGS,
+ flags == 0 ? null : new Integer(flags));
+ }
+
+ /**
+ * Creates a new MarkerProblemReporter that reports problems as markers
+ * against the given project.
+ */
+ public MarkerProblemReporter(IProject project, IDevelopmentContext dc) {
+ initialize(project, dc);
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.core.builder.IProblemReporter
+ */
+ public void initialize(IProject project, IDevelopmentContext dc) {
+ this.fProject = project;
+ this.dc = dc;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/MethodCollaboratorIndictment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/MethodCollaboratorIndictment.java
new file mode 100644
index 0000000000..8bb2b8a97b
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/MethodCollaboratorIndictment.java
@@ -0,0 +1,80 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.builder.IType;
+
+class MethodCollaboratorIndictment extends Indictment {
+ protected IType fOwner;
+ protected int fParmCount;
+ /**
+ * Creates a new MethodCollaboratorIndictment.
+ */
+ protected MethodCollaboratorIndictment(
+ IType owner,
+ char[] name,
+ int parmCount) {
+ super(getMethodIndictmentKey(name, parmCount));
+ fOwner = owner;
+ fParmCount = parmCount;
+ }
+
+ /**
+ * Returns true if indictments are equal, false otherwise
+ */
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null)
+ return false;
+ if (!this.getClass().equals(o.getClass()))
+ return false;
+
+ MethodCollaboratorIndictment f = (MethodCollaboratorIndictment) o;
+ return (this.fName.equals(f.fName)) && (this.fParmCount == f.fParmCount);
+ }
+
+ /**
+ * Returns what kind of indictment this is
+ */
+ public int getKind() {
+ return K_METHOD;
+ }
+
+ /**
+ * Returns the owning type of the method.
+ */
+ public IType getOwner() {
+ return fOwner;
+ }
+
+ /**
+ * Returns the number of parameters to the method.
+ */
+ public int getParmCount() {
+ return fParmCount;
+ }
+
+ /**
+ * Returns a hashcode for the indictment
+ */
+ public int hashCode() {
+ return super.hashCode() + fParmCount;
+ }
+
+ /**
+ * Returns a string representation of this class. For debugging purposes
+ * only (NON-NLS).
+ */
+ public String toString() {
+ StringBuffer buf = new StringBuffer("MethodIndictment(");
+ buf.append(fName);
+ buf.append('/');
+ buf.append(fParmCount);
+ buf.append(')');
+ return buf.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/MethodImpl.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/MethodImpl.java
new file mode 100644
index 0000000000..98c4631c2d
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/MethodImpl.java
@@ -0,0 +1,114 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.builder.*;
+
+public class MethodImpl extends AbstractMemberHandle implements IMethod {
+ public MethodImpl(ClassOrInterfaceHandleImpl owner, String signature) {
+ fOwner = owner;
+ fSignature = signature;
+ }
+
+ MethodImpl(ClassOrInterfaceHandleImpl owner, String name, IType[] paramTypes) {
+ fOwner = owner;
+ fSignature = computeSignature(name, paramTypes);
+ }
+
+ /**
+ * Returns an array of Type objects that represent the types of
+ * the checked exceptions thrown by the method
+ * represented by this Method object.
+ * Unchecked exceptions are not included in the result, even if
+ * they are declared in the source.
+ * Returns an array of length 0 if the method throws no checked
+ * exceptions.
+ * The resulting Types are in no particular order.
+ */
+ public IType[] getExceptionTypes() {
+ return nonStateSpecific(((IMethod) inCurrentState()).getExceptionTypes());
+ }
+
+ /**
+ * Returns the simple name of the member represented by this object.
+ * If this Member represents a constructor, this returns
+ * the simple name of its declaring class.
+ * This is a handle-only method.
+ */
+ public String getName() {
+ String sig = getSignature();
+ return sig.substring(0, sig.indexOf('('));
+ }
+
+ /**
+ * Returns an array of Type objects that represent the formal
+ * parameter types, in declaration order, of the method
+ * represented by this Method object.
+ * Returns an array of length 0 if the underlying method takes
+ * no parameters. This is a handle-only method.
+ */
+ public IType[] getParameterTypes() {
+ return getInternalDC().parameterTypesFromSignature(getSignature());
+ }
+
+ /**
+ * Returns a Type object that represents the formal return type
+ * of the method represented by this Method object.
+ */
+ public IType getReturnType() {
+ IType wrapped = ((IMethod) inCurrentState()).getReturnType();
+ return (IType) wrapped.nonStateSpecific();
+ }
+
+ /**
+ * Returns a string representing the constructor's parameters in the
+ * unqualified source signature format.
+ */
+ protected String getSourceParameters() {
+ String sourceSig = "(";
+
+ /* append parameter types to signature */
+ IType[] parms = getParameterTypes();
+ for (int i = 0; i < parms.length; i++) {
+ sourceSig += parms[i].getSimpleName().replace('L', 'Q');
+ }
+ sourceSig += ")";
+ return sourceSig;
+ }
+
+ /**
+ * Returns a state specific version of this handle in the given state.
+ */
+ public IHandle inState(IState s)
+ throws org.eclipse.jdt.internal.core.builder.StateSpecificException {
+
+ return new MethodImplSWH((StateImpl) s, this);
+ }
+
+ /**
+ * Returns a constant indicating what kind of handle this is.
+ */
+ public int kind() {
+ return K_JAVA_METHOD;
+ }
+
+ /**
+ * toString method comment.
+ */
+ public String toString() {
+ StringBuffer sb = new StringBuffer(getDeclaringClass().getName());
+ sb.append('.').append(getName()).append('(');
+ IType[] paramTypes = getParameterTypes();
+ for (int i = 0; i < paramTypes.length; ++i) {
+ if (i != 0) {
+ sb.append(',');
+ }
+ sb.append(paramTypes[i].getName());
+ }
+ sb.append(')');
+ return sb.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/MethodImplSWH.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/MethodImplSWH.java
new file mode 100644
index 0000000000..951ce780f7
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/MethodImplSWH.java
@@ -0,0 +1,170 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.core.builder.*;
+
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+import org.eclipse.jdt.internal.core.Util;
+
+public class MethodImplSWH extends AbstractMemberHandleSWH implements IMethod {
+ MethodImpl fHandle;
+ /**
+ * Internal - Creates a new method handle in the given state
+ */
+ MethodImplSWH(StateImpl state, MethodImpl handle) {
+ fState = state;
+ fHandle = handle;
+ }
+
+ /**
+ * Internal - Returns the IBinaryMethod for this method.
+ */
+ protected IBinaryMethod getBinaryMethod() throws NotPresentException {
+ return getBinaryMethod(getTypeStructureEntry());
+ }
+
+ /**
+ * Internal - Returns the IBinaryMethod for this method.
+ */
+ protected IBinaryMethod getBinaryMethod(TypeStructureEntry tsEntry)
+ throws NotPresentException {
+ IBinaryType t = fState.getBinaryType(getTypeStructureEntry());
+ IBinaryMethod m = BinaryStructure.getMethod(t, fHandle.fSignature);
+ if (m == null) {
+ throw new NotPresentException();
+ } else {
+ return m;
+ }
+ }
+
+ /**
+ * Returns an array of Type objects that represent the types of
+ * the checked exceptions thrown by the underlying method
+ * represented by this Method object.
+ * Unchecked exceptions are not included in the result, even if
+ * they are declared in the source.
+ * Returns an array of length 0 if the constructor throws no checked
+ * exceptions.
+ * The resulting Types are in no particular order.
+ */
+ public IType[] getExceptionTypes() {
+ TypeStructureEntry tsEntry = getTypeStructureEntry();
+ char[][] exceptions = getBinaryMethod(tsEntry).getExceptionTypeNames();
+ PackageImpl pkg = fHandle.fOwner.fOwner;
+ int len = exceptions.length;
+ IType[] results = new IType[len];
+ for (int i = 0; i < len; i++) {
+ results[i] =
+ (IType) fState
+ .typeNameToHandle(tsEntry, Util.convertTypeSignature(exceptions[i]))
+ .inState(fState);
+ }
+ return results;
+ }
+
+ /**
+ * Internal - Returns the non state specific handle
+ */
+ IMember getHandle() {
+ return fHandle;
+ }
+
+ /**
+ * Returns the Java language modifiers for the member
+ * represented by this object, as an integer.
+ */
+ public int getModifiers() {
+ return getBinaryMethod().getModifiers() & 0xFFFF;
+ }
+
+ /**
+ * Returns the name of the method.
+ */
+ public String getName() {
+ return fHandle.getName();
+ }
+
+ /**
+ * Returns an array of Type objects that represent the formal
+ * parameter types, in declaration order, of the method
+ * represented by this Method object.
+ * Returns an array of length 0 if the underlying method takes
+ * no parameters. This is a handle-only method.
+ */
+ public IType[] getParameterTypes() {
+ IType[] unwrapped = fHandle.getParameterTypes();
+ IType[] results = new IType[unwrapped.length];
+ for (int i = 0; i < unwrapped.length; i++) {
+ results[i] = (IType) unwrapped[i].inState(fState);
+ }
+ return results;
+ }
+
+ /**
+ * Returns a Type object that represents the formal return type
+ * of the method represented by this Method object.
+ */
+ public IType getReturnType() {
+ TypeStructureEntry tsEntry = getTypeStructureEntry();
+ char[] sig = getBinaryMethod(tsEntry).getMethodDescriptor();
+ int i = CharOperation.lastIndexOf(')', sig);
+ if (i == -1) {
+ // should not happen
+ return getDevelopmentContext().getImage().voidType();
+ }
+ sig = CharOperation.subarray(sig, i + 1, sig.length);
+ return (IType) fState
+ .typeSignatureToHandle(tsEntry, Util.convertTypeSignature(sig))
+ .inState(fState);
+ }
+
+ /**
+ * Returns true if the member represented by this object is
+ * deprecated, false otherwise. A deprecated object is one that
+ * has a @ deprecated tag in its doc comment.
+ */
+ public boolean isDeprecated() {
+ return (getBinaryMethod().getModifiers() & IConstants.AccDeprecated) != 0;
+ }
+
+ /**
+ * Returns true if the object represented by the receiver is present
+ * in the development context, false otherwise. If the receiver is
+ * state-specific, checks whether it is present in this object's state,
+ * otherwise checks whether it is present in the current state of the
+ * development context.
+ */
+ public boolean isPresent() {
+ TypeStructureEntry entry =
+ fState.getTypeStructureEntry(fHandle.getDeclaringClass(), true);
+ if (entry == null) {
+ return false;
+ }
+ IBinaryType t = fState.getBinaryType(entry);
+ IBinaryMethod m = BinaryStructure.getMethod(t, fHandle.fSignature);
+ return m != null;
+ }
+
+ /**
+ * Returns true if the member represented by this object is
+ * synthetic, false otherwise. A synthetic object is one that
+ * was invented by the compiler, but was not declared in the source.
+ * See <em>The Inner Classes Specification</em>.
+ * A synthetic object is not the same as a fictitious object.
+ */
+ public boolean isSynthetic() throws NotPresentException {
+ return (getBinaryMethod().getModifiers() & IConstants.AccSynthetic) != 0;
+ }
+
+ /**
+ * Returns the non state specific handle
+ */
+ public IHandle nonStateSpecific() {
+ return fHandle;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ModifiedBuilderType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ModifiedBuilderType.java
new file mode 100644
index 0000000000..661c3a6fd2
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ModifiedBuilderType.java
@@ -0,0 +1,283 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.core.builder.IType;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+/**
+ * A type that exists in both old and new states.
+ * This type definitly has been or will be
+ * compiled during this incremental build. These
+ * types must hang onto their old structure because
+ * the builder will overwrite it with the new structure
+ * after compilation.
+ */
+public class ModifiedBuilderType extends BuilderType {
+ /**
+ * The tsEntry in the new state
+ */
+ protected TypeStructureEntry fNewTSEntry;
+
+ /**
+ * The tsEntry for this type in the old state
+ */
+ protected TypeStructureEntry fOldTSEntry;
+
+ /**
+ * The structure of this type in the old state
+ */
+ protected IBinaryType fOldStructure;
+ /**
+ * Creates a new ModifiedBuilderType. The new tsEntry is not
+ * yet known because the type hasn't yet been compiled.
+ */
+ public ModifiedBuilderType(
+ IncrementalImageBuilder builder,
+ TypeStructureEntry oldEntry,
+ IBinaryType oldBinary) {
+ super(builder, false, false);
+ fOldTSEntry = oldEntry;
+ fOldStructure = oldBinary;
+ }
+
+ /**
+ * Adds the indictments for the descriptor's type, methods,
+ * and fields. Usually used when a type has been added or removed.
+ */
+ public void computeAllIndictments(IndictmentSet set) {
+
+ /* indictment for the type */
+ IType type = fOldTSEntry.getType();
+ set.add(Indictment.createTypeIndictment(fOldStructure));
+
+ /* indictments for all fields */
+ IBinaryField[] fields = fOldStructure.getFields();
+ if (fields != null) {
+ for (int i = 0; i < fields.length; i++) {
+ set.add(Indictment.createFieldIndictment(fields[i]));
+ }
+ }
+
+ /* indictments for all methods */
+ IBinaryMethod[] methods = fOldStructure.getMethods();
+ if (methods != null) {
+ for (int i = 0; i < methods.length; i++) {
+ set.add(Indictment.createMethodIndictment(type, fOldStructure, methods[i]));
+ }
+ }
+ }
+
+ /**
+ * Computes the indictments for the fields of this type
+ */
+ public void computeFieldIndictments(
+ IndictmentSet indictments,
+ IBinaryType newType,
+ IType typeHandle) {
+
+ /* create a set of all old fields */
+ HashtableOfObject oldFieldsTable = new HashtableOfObject(11);
+ IBinaryField[] oldFields = fOldStructure.getFields();
+ if (oldFields != null) {
+ for (int i = 0; i < oldFields.length; i++) {
+ oldFieldsTable.put(oldFields[i].getName(), oldFields[i]);
+ }
+ }
+
+ /* check if each new field was in old field list */
+ IBinaryField[] newFields = newType.getFields();
+ if (newFields != null) {
+ for (int i = 0; i < newFields.length; i++) {
+ IBinaryField newField = newFields[i];
+ IBinaryField oldField = (IBinaryField) oldFieldsTable.get(newField.getName());
+ if (oldField == null) {
+ /* it's a new field -- create a indictment */
+ indictments.add(Indictment.createFieldIndictment(newField));
+ } else {
+ /* if it has it changed, issue an indictment */
+ oldFieldsTable.put(oldField.getName(), null);
+ // TBD: there is no remove on HashtableOfObject
+ if (!BinaryStructure.compare(oldField, newField)) {
+ indictments.add(Indictment.createFieldIndictment(oldField));
+ }
+ }
+ }
+ }
+
+ /* remaining old fields have been deleted -- create indictments */
+ Object[] remaining = oldFieldsTable.valueTable;
+ for (int i = remaining.length; i-- > 0;) {
+ if (remaining[i] != null) {
+ IBinaryField oldField = (IBinaryField) remaining[i];
+ indictments.add(Indictment.createFieldIndictment(oldField));
+ }
+ }
+ }
+
+ /**
+ * Computes the indictments for this type
+ */
+ public void computeIndictments(IndictmentSet indictments) {
+ if (getOldBinaryType() == null) {
+ // Don't know old structure. Must convict all dependents.
+ // Needed for 1FVQGL1: ITPJCORE:WINNT - SEVERE - Error saving java file
+ indictments.convictAll();
+ return;
+ }
+
+ if (fNewTSEntry == null) {
+ /* a new type could not be generated */
+ computeAllIndictments(indictments);
+ return;
+ }
+
+ IBinaryType newType = getNewState().getBinaryType(fNewTSEntry);
+ IType typeHandle = (IType) fOldTSEntry.getType();
+
+ /* see if there's a change to supertype hierarchy */
+ boolean hierarchyChange = detectHierarchyChange();
+
+ /* add the hierarchy indictment if there were any changes */
+ if (hierarchyChange) {
+ indictments.add(Indictment.createHierarchyIndictment(newType));
+ }
+
+ /* if type modifiers (including deprecated flag) have changed */
+ if (fOldStructure.getModifiers() != newType.getModifiers()) {
+ /* issue a type collaborator indictment */
+ indictments.add(Indictment.createTypeIndictment(newType));
+ }
+
+ /* compute indictments for members */
+ computeMethodIndictments(indictments, newType, typeHandle);
+ computeFieldIndictments(indictments, newType, typeHandle);
+ }
+
+ /**
+ * Computes the method indictments for this type
+ */
+ public void computeMethodIndictments(
+ IndictmentSet indictments,
+ IBinaryType newType,
+ IType typeHandle) {
+
+ boolean issueAbstractMethodIndictment = false;
+ if ((fOldStructure.getModifiers() & IConstants.AccAbstract)
+ != (newType.getModifiers() & IConstants.AccAbstract)) {
+ issueAbstractMethodIndictment = true;
+ }
+
+ /* create a set of all old methods */
+ HashtableOfObject oldMethodsTable = new HashtableOfObject(21);
+ IBinaryMethod[] oldMethods = fOldStructure.getMethods();
+ if (oldMethods != null) {
+ for (int i = 0; i < oldMethods.length; i++) {
+ IBinaryMethod oldMethod = oldMethods[i];
+ char[] sig =
+ CharOperation.concat(oldMethod.getSelector(), oldMethod.getMethodDescriptor());
+ oldMethodsTable.put(sig, oldMethod);
+ }
+ }
+
+ /* check if each new method was in old method list */
+ IBinaryMethod[] newMethods = newType.getMethods();
+ if (newMethods != null) {
+ for (int i = 0; i < newMethods.length; i++) {
+ IBinaryMethod newMethod = (IBinaryMethod) newMethods[i];
+ char[] sig =
+ CharOperation.concat(newMethod.getSelector(), newMethod.getMethodDescriptor());
+ IBinaryMethod oldMethod = (IBinaryMethod) oldMethodsTable.get(sig);
+ if (oldMethod == null) {
+ /* it's a new method -- issue an indictment */
+ indictments.add(
+ Indictment.createMethodIndictment(typeHandle, newType, newMethod));
+
+ /* if the new method is abstract, issue an abstract method indictment too */
+ if ((newMethod.getModifiers() & IConstants.AccAbstract) != 0) {
+ issueAbstractMethodIndictment = true;
+ }
+ } else {
+ /* if it has it changed, issue an indictment */
+ oldMethodsTable.put(sig, null);
+ // TBD: there is no remove on HashtableOfObject
+ if (!BinaryStructure.compare(oldMethod, newMethod)) {
+ indictments.add(
+ Indictment.createMethodIndictment(typeHandle, fOldStructure, oldMethod));
+ }
+ /* if an existing method changes its abstract state, issue an abstract method indictment too */
+ if ((oldMethod.getModifiers() & IConstants.AccAbstract)
+ != (newMethod.getModifiers() & IConstants.AccAbstract)) {
+ issueAbstractMethodIndictment = true;
+ }
+ }
+ }
+ }
+
+ /* remaining old methods have been deleted -- issue indictments */
+ Object[] remaining = oldMethodsTable.valueTable;
+ for (int i = remaining.length; i-- > 0;) {
+ if (remaining[i] != null) {
+ IBinaryMethod oldMethod = (IBinaryMethod) remaining[i];
+ indictments.add(
+ Indictment.createMethodIndictment(typeHandle, fOldStructure, oldMethod));
+
+ /* if old method is abstract, issue an abstract method indictment too */
+ if ((oldMethod.getModifiers() & IConstants.AccAbstract) != 0) {
+ issueAbstractMethodIndictment = true;
+ }
+ }
+ }
+
+ /* issue abstract method indictment now, if need be */
+ if (issueAbstractMethodIndictment) {
+ indictments.add(Indictment.createAbstractMethodIndictment(typeHandle));
+ }
+ }
+
+ /**
+ * Returns the tsEntry in the new state
+ */
+ public TypeStructureEntry getNewTypeStructureEntry() {
+ if (fNewTSEntry == null) {
+ if (fOldTSEntry != null) {
+ fNewTSEntry =
+ fBuilder.fNewState.getTypeStructureEntry(fOldTSEntry.getType(), false);
+ }
+ }
+ return fNewTSEntry;
+ }
+
+ /**
+ * Returns the binary type in the old state
+ */
+ public IBinaryType getOldBinaryType() {
+ return fOldStructure;
+ }
+
+ /**
+ * Returns the old tsEntry
+ */
+ public TypeStructureEntry getOldTypeStructureEntry() {
+ return fOldTSEntry;
+ }
+
+ /**
+ * Sets the tsEntry in the new state
+ */
+ public void setNewTypeStructureEntry(TypeStructureEntry newEntry) {
+ fNewTSEntry = newEntry;
+ }
+
+ /**
+ * For debugging only
+ */
+ public String toString() {
+ StringBuffer buf = new StringBuffer("ModifiedBuilderType(");
+ return buf.append(fOldTSEntry.getType().getName()).append(")").toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/NamespaceNode.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/NamespaceNode.java
new file mode 100644
index 0000000000..c6d30b30d4
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/NamespaceNode.java
@@ -0,0 +1,72 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.Assert;
+import org.eclipse.jdt.internal.core.builder.IPackage;
+
+/**
+ *
+ */
+public class NamespaceNode extends AbstractNode {
+ protected IPackage fPackage;
+ /**
+ * Creates a new namespace node for the given package
+ */
+ public NamespaceNode(IPackage pkg) {
+ fPackage = pkg;
+ }
+
+ /**
+ * Adds a node that this node depends on. Backwards link is added automatically
+ */
+ public void addDependency(INode nodeThatIDependOn) {
+ Assert.isTrue(false, "namespaces cannot have dependencies");
+ }
+
+ /**
+ * Returns a copy of this node, without copying dependencies. Used
+ * by DependencyGraph.copy().
+ */
+ public AbstractNode copy() {
+ return new NamespaceNode(fPackage);
+ }
+
+ /**
+ * Returns the element which this node represents.
+ */
+ public Object getElement() {
+ return fPackage;
+ }
+
+ /**
+ * Returns the number of bytes that this node uses.
+ * For debugging and profiling purposes only.
+ */
+ int getFootprint() {
+ /* one slot for package */
+ return super.getFootprint() + 4;
+ }
+
+ /**
+ * Returns what kind of node this is.
+ */
+ public int getKind() {
+ return NAMESPACE_NODE;
+ }
+
+ public IPackage getPackage() {
+ return fPackage;
+ }
+
+ /**
+ * Prints a string representation of the node. This method is for debugging
+ * purposes only.
+ */
+ public String toString() {
+ return "NamespaceNode(" + fPackage.getName() + ")";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/NewBuilderType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/NewBuilderType.java
new file mode 100644
index 0000000000..f067b3361d
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/NewBuilderType.java
@@ -0,0 +1,53 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+public class NewBuilderType extends BuilderType {
+ /**
+ * The tsEntry in the new state
+ */
+ protected TypeStructureEntry fNewTSEntry;
+ /**
+ * NewBuilderType constructor comment.
+ */
+ public NewBuilderType(
+ IncrementalImageBuilder builder,
+ TypeStructureEntry newEntry) {
+ /* this is a new type, which is a hierarchy change */
+ super(builder, true, true);
+ fNewTSEntry = newEntry;
+ }
+
+ /**
+ * No indictments for a new type.
+ */
+ public void computeIndictments(IndictmentSet indictments) {
+ }
+
+ /**
+ * Returns the new tsEntry
+ */
+ public TypeStructureEntry getNewTypeStructureEntry() {
+ return fNewTSEntry;
+ }
+
+ /**
+ * Added types do not have an entry in the old state.
+ */
+ public TypeStructureEntry getOldTypeStructureEntry() {
+ return null;
+ }
+
+ /**
+ * Sets the tsEntry in the new state
+ */
+ public void setNewTypeStructureEntry(TypeStructureEntry newEntry) {
+ fNewTSEntry = newEntry;
+ }
+
+ /**
+ * For debugging only
+ */
+ public String toString() {
+ return "NewBuilderType(" + fNewTSEntry.getType().getName() + ")";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/NonStateSpecificHandleImpl.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/NonStateSpecificHandleImpl.java
new file mode 100644
index 0000000000..bfc2517266
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/NonStateSpecificHandleImpl.java
@@ -0,0 +1,133 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.Assert;
+import org.eclipse.jdt.internal.core.builder.*;
+
+public abstract class NonStateSpecificHandleImpl implements IHandle {
+ public boolean equals(Object obj) {
+ Assert.isTrue(false, "TBD");
+ return false;
+ }
+
+ public IDevelopmentContext getDevelopmentContext() {
+ return getInternalDC();
+ }
+
+ abstract JavaDevelopmentContextImpl getInternalDC();
+ public IState getState() {
+ throw new org.eclipse.jdt.internal.core.builder.StateSpecificException();
+ }
+
+ /**
+ * Returns a consistent hash code for this object
+ */
+ public abstract int hashCode();
+ /**
+ * Returns a state-specific version of this handle in the current state
+ */
+ protected IHandle inCurrentState() {
+ return inState(getDevelopmentContext().getCurrentState());
+ }
+
+ /**
+ * Returns a state-specific version of this handle in the given state
+ */
+ public abstract IHandle inState(IState s)
+ throws org.eclipse.jdt.internal.core.builder.StateSpecificException;
+ public boolean isFictional() {
+ return inCurrentState().isFictional();
+ }
+
+ public boolean isPresent() {
+ return inCurrentState().isPresent();
+ }
+
+ public boolean isStateSpecific() {
+ return false;
+ }
+
+ public abstract int kind();
+ public IHandle nonStateSpecific() {
+ throw new org.eclipse.jdt.internal.core.builder.StateSpecificException();
+ }
+
+ /**
+ * Converts an array of state-specific constructors to non-state-specific constructors.
+ */
+ static IConstructor[] nonStateSpecific(IConstructor[] stateSpecific) {
+ int len = stateSpecific.length;
+ if (len == 0)
+ return stateSpecific;
+ IConstructor[] result = new IConstructor[len];
+ for (int i = 0; i < len; ++i) {
+ result[i] = (IConstructor) stateSpecific[i].nonStateSpecific();
+ }
+ return result;
+ }
+
+ /**
+ * Converts an array of state-specific fields to non-state-specific fields.
+ */
+ static IField[] nonStateSpecific(IField[] stateSpecific) {
+ int len = stateSpecific.length;
+ if (len == 0)
+ return stateSpecific;
+ IField[] result = new IField[len];
+ for (int i = 0; i < len; ++i) {
+ result[i] = (IField) stateSpecific[i].nonStateSpecific();
+ }
+ return result;
+ }
+
+ /**
+ * Converts an array of state-specific methods to non-state-specific methods.
+ */
+ static IMethod[] nonStateSpecific(IMethod[] stateSpecific) {
+ int len = stateSpecific.length;
+ if (len == 0)
+ return stateSpecific;
+ IMethod[] result = new IMethod[len];
+ for (int i = 0; i < len; ++i) {
+ result[i] = (IMethod) stateSpecific[i].nonStateSpecific();
+ }
+ return result;
+ }
+
+ /**
+ * Converts an array of state-specific packages to non-state-specific packages.
+ */
+ static IPackage[] nonStateSpecific(IPackage[] stateSpecific) {
+ int len = stateSpecific.length;
+ if (len == 0)
+ return stateSpecific;
+ IPackage[] result = new IPackage[len];
+ for (int i = 0; i < len; ++i) {
+ result[i] = (IPackage) stateSpecific[i].nonStateSpecific();
+ }
+ return result;
+ }
+
+ /**
+ * Converts an array of state-specific types to non-state-specific types.
+ */
+ static IType[] nonStateSpecific(IType[] stateSpecific) {
+ int len = stateSpecific.length;
+ if (len == 0)
+ return stateSpecific;
+ IType[] result = new IType[len];
+ for (int i = 0; i < len; ++i) {
+ result[i] = (IType) stateSpecific[i].nonStateSpecific();
+ }
+ return result;
+ }
+
+ public String toString() {
+ Assert.isTrue(false, "TBD");
+ return null;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/OldBuilderType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/OldBuilderType.java
new file mode 100644
index 0000000000..d7abdfc1d5
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/OldBuilderType.java
@@ -0,0 +1,67 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.Assert;
+import org.eclipse.jdt.internal.core.builder.IType;
+
+/**
+ * A type that existed in the old state. Unless
+ * subclassed, this type does not exist in the new state.
+ */
+public class OldBuilderType extends BuilderType {
+ /**
+ * The tsEntry for this type in the old state
+ */
+ protected TypeStructureEntry fOldTSEntry;
+
+ /**
+ * Creates a new OldBuilderType
+ */
+ public OldBuilderType(
+ IncrementalImageBuilder builder,
+ TypeStructureEntry oldEntry) {
+ /* this is a deleted type, which is a hierarchy change */
+ super(builder, true, true);
+ fOldTSEntry = oldEntry;
+ }
+
+ /**
+ * Adds the indictments for the descriptor's type, methods,
+ * and fields. Usually used when a type has been added or removed.
+ */
+ public void computeIndictments(IndictmentSet set) {
+ /* dependents should already have been compiled */
+ }
+
+ /**
+ * Old builder types don't necessarily exist in the new state.
+ */
+ public TypeStructureEntry getNewTypeStructureEntry() {
+ return null;
+ }
+
+ /**
+ * Returns the old tsEntry
+ */
+ public TypeStructureEntry getOldTypeStructureEntry() {
+ return fOldTSEntry;
+ }
+
+ /**
+ * Sets the tsEntry in the new state
+ */
+ public void setNewTypeStructureEntry(TypeStructureEntry newEntry) {
+ Assert.isTrue(false);
+ }
+
+ /**
+ * For debugging only
+ */
+ public String toString() {
+ return "OldBuilderType(" + fOldTSEntry.getType().getName() + ")";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/OrderedSet.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/OrderedSet.java
new file mode 100644
index 0000000000..2e9f369833
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/OrderedSet.java
@@ -0,0 +1,241 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+public class OrderedSet {
+ protected int elementCount;
+ protected Object[] elementKeys;
+ protected int[] elementIndexes;
+ protected Object[] orderedList;
+
+ protected float loadFactor;
+
+ private static final int DEFAULT_SIZE = 101;
+
+ /**
+ * Constructs a new OrderedSet using the default capacity
+ * and load factor.
+ */
+ public OrderedSet() {
+ this(DEFAULT_SIZE);
+ }
+
+ /**
+ * Constructs a new OrderedSet using the specified capacity
+ * and the default load factor.
+ *
+ * @param capacity the initial capacity
+ */
+ public OrderedSet(int capacity) {
+ this(capacity, 0.75f);
+ }
+
+ /**
+ * Constructs a new OrderedSet using the specified capacity
+ * and load factor.
+ *
+ * @param loadFactor the initial load factor
+ */
+ public OrderedSet(int capacity, float loadFactor) {
+ if (capacity <= 0)
+ throw new IllegalArgumentException();
+ elementCount = 0;
+ elementKeys = new Object[capacity];
+ int[] indexes = new int[capacity];
+ for (int i = capacity; --i >= 0;) {
+ indexes[i] = -1;
+ }
+ elementIndexes = indexes;
+ orderedList = new Object[capacity];
+ this.loadFactor = loadFactor;
+ }
+
+ private int findIndex(Object object, Object[] array) {
+ Object key;
+ int length = array.length;
+ int index = (object.hashCode() & 0x7FFFFFFF) % length;
+ for (int i = index; i < length; i++) {
+ if (((key = array[i]) == null) || (key == object))
+ return i;
+ if (key.equals(object))
+ return i;
+ }
+ for (int i = 0; i < index; i++) {
+ if (((key = array[i]) == null) || (key == object))
+ return i;
+ if (key.equals(object))
+ return i;
+ }
+ return -1; // unreacheable
+ }
+
+ /**
+ * Answers the object associated with the specified index in
+ * this OrderedSet.
+ *
+ * @param index the index to use
+ * @return the object associated with the specified index
+ * @throws ArrayIndexOutOfBoundsException if the index is out of range
+ *
+ * @see #put
+ */
+ public Object get(int index) {
+ if (index >= elementCount) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ return orderedList[index];
+ }
+
+ /**
+ * Answers whether the specified object is in
+ * this OrderedSet.
+ *
+ * @param obj the object, which must not be null
+ * @return true if the object is in the set, false otherwise
+ *
+ * @see #put
+ */
+ public boolean includes(Object obj) {
+ if (obj == null) {
+ throw new NullPointerException();
+ }
+ int index = elementIndexes[findIndex(obj, elementKeys)];
+ return index != -1;
+ }
+
+ /**
+ * Answers the index associated with the specified object in
+ * this OrderedSet.
+ *
+ * @param obj the object, which must not be null
+ * @return the index associated with the object
+ * @throws IllegalArgumentException if the key is not in the pool
+ *
+ * @see #put
+ */
+ public int index(Object obj) {
+ if (obj == null) {
+ throw new NullPointerException();
+ }
+ int findIndex = findIndex(obj, elementKeys);
+ int index = elementIndexes[findIndex];
+ if (index == -1) {
+ throw new IllegalArgumentException();
+ }
+ return index;
+ }
+
+ /**
+ * Associate the given object with the given index in this OrderedSet.
+ * The object's index is not retrievable using index(Object).
+ * But the object is retrievable using get(int index).
+ * The index must not yet have been assigned.
+ *
+ * @param index the index of the object
+ * @param obj the object to add
+ *
+ * @see #get
+ * @see java.lang.Object#equals
+ */
+ public void put(int index, Object obj) {
+ if (obj == null)
+ throw new NullPointerException();
+ if (orderedList.length <= index) {
+ int[] newOrderedList = new int[orderedList.length * 2];
+ System.arraycopy(orderedList, 0, newOrderedList, 0, elementCount);
+ }
+ if (orderedList[index] != null) {
+ throw new IllegalArgumentException();
+ }
+ orderedList[index] = obj;
+ if (index >= elementCount) {
+ elementCount = index + 1;
+ }
+ }
+
+ /**
+ * Associate the given object with the next index in this OrderedSet.
+ * If the object is already present, its index is unchanged. The object cannot be null.
+ *
+ * @param obj the object to add
+ * @return the index associated with the specified obj
+ *
+ * @see #index
+ * @see java.lang.Object#equals
+ */
+ public int put(Object obj) {
+ if (obj == null)
+ throw new NullPointerException();
+ int index = findIndex(obj, elementKeys);
+ int resultIndex = elementIndexes[index];
+ if (resultIndex == -1) {
+ int size = (int) (elementKeys.length * loadFactor + 1);
+ if ((elementCount + 1) >= size) {
+ rehash();
+ index = findIndex(obj, elementKeys);
+ }
+ orderedList[elementCount] = elementKeys[index] = obj;
+ return elementIndexes[index] = elementCount++;
+ } else {
+ return resultIndex;
+ }
+ }
+
+ /**
+ * Increases the capacity of this OrderedSet. This method is sent when
+ * the size of this OrderedSet exceeds the load factor.
+ */
+ protected void rehash() {
+ Object key;
+ int index, length = elementKeys.length << 1;
+ Object[] newKeys = new Object[length];
+ int[] newIndexes = new int[length];
+ for (int i = length; --i >= 0;) {
+ newIndexes[i] = -1;
+ }
+ for (int i = 0; i < elementKeys.length; i++) {
+ if ((key = elementKeys[i]) != null) {
+ index = findIndex(key, newKeys);
+ newKeys[index] = key;
+ newIndexes[index] = elementIndexes[i];
+ }
+ }
+ Object[] newOrdered = new Object[length];
+ System.arraycopy(orderedList, 0, newOrdered, 0, elementCount);
+ elementKeys = newKeys;
+ elementIndexes = newIndexes;
+ orderedList = newOrdered;
+ }
+
+ /**
+ * Answers the number of objects in this OrderedSet.
+ *
+ * @return the number of objects in this OrderedSet
+ */
+ public int size() {
+ return elementCount;
+ }
+
+ /**
+ * Answers the string representation of this OrderedSet.
+ *
+ * @return the string representation of this OrderedSet
+ */
+ public String toString() {
+ Object key;
+ StringBuffer buffer = new StringBuffer();
+ buffer.append('{');
+ for (int i = 0; i < elementCount; i++) {
+ if (i != 0)
+ buffer.append(',');
+ if (buffer.length() > 1000) {
+ buffer.append("...");
+ break;
+ }
+ buffer.append(orderedList[i]);
+ buffer.append('=');
+ buffer.append(i);
+ }
+ buffer.append('}');
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PackageElement.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PackageElement.java
new file mode 100644
index 0000000000..ad33830657
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PackageElement.java
@@ -0,0 +1,80 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.builder.*;
+
+/**
+ * This identifies an element of a package in the workspace,
+ * before building but after fragment assembly.
+ * It consists of two parts: a package handle and a file name (represented as a source entry).
+ */
+public class PackageElement {
+ IPackage fPackage;
+ String fFileName;
+ boolean fIsSource;
+ PackageElement(IPackage pkg, String fileName, boolean isSource) {
+ fPackage = pkg;
+ fFileName = fileName;
+ fIsSource = isSource;
+ }
+
+ PackageElement(IPackage pkg, SourceEntry entry) {
+ fPackage = pkg;
+ fFileName = entry.getFileName();
+ fIsSource = entry.isSource();
+ }
+
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof PackageElement))
+ return false;
+ PackageElement e = (PackageElement) o;
+
+ /* If filenames are equal, so is isSource flag.
+ */
+ return this.fFileName.equals(e.fFileName) && fPackage.equals(e.fPackage);
+ }
+
+ /**
+ * Returns the 'file name'.
+ */
+ public String getFileName() {
+ return fFileName;
+ }
+
+ /**
+ * Returns the package containing the package element.
+ */
+ public IPackage getPackage() {
+ return fPackage;
+ }
+
+ public int hashCode() {
+ return fPackage.hashCode() * 17 + fFileName.hashCode();
+ }
+
+ /**
+ * Returns true if the source entry comes from a class file, otherwise
+ * returns false.
+ */
+ public boolean isBinary() {
+ return !fIsSource;
+ }
+
+ /**
+ * Returns true if the source entry comes from a compilation unit, otherwise
+ * returns false.
+ */
+ public boolean isSource() {
+ return fIsSource;
+ }
+
+ public String toString() {
+ return fPackage.isUnnamed() ? fFileName : fPackage.getName() + '/' + fFileName;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PackageImpl.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PackageImpl.java
new file mode 100644
index 0000000000..eac92556fe
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PackageImpl.java
@@ -0,0 +1,237 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.builder.*;
+
+public class PackageImpl
+ extends NonStateSpecificHandleImpl
+ implements IPackage {
+ JavaDevelopmentContextImpl fDevelopmentContext;
+ String fName;
+ boolean fIsUnnamed;
+
+ public static final String DEFAULT_PACKAGE_PREFIX = "Default-";
+ /**
+ * Creates a new package
+ * @param name of package
+ * @param isUnnamed whether the package is unnamed
+ */
+ PackageImpl(JavaDevelopmentContextImpl ctx, String name, boolean isUnnamed) {
+ fName = name;
+ fIsUnnamed = isUnnamed;
+ fDevelopmentContext = ctx;
+ }
+
+ /**
+ * Appends the signature for this package to the given StringBuffer.
+ * If includeUnnamed is true, then the identifiers for unnamed packages
+ * are included, preceded by '$'. Otherwise, they are excluded.
+ * Returns true if a signature was written, false otherwise.
+ */
+ boolean appendSignature(StringBuffer sb, boolean includeUnnamed) {
+ if (includeUnnamed || !fIsUnnamed) {
+ sb.append(fName);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Compares this object against the specified object.
+ * Returns true if the objects are the same.
+ */
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof PackageImpl))
+ return false;
+
+ PackageImpl pkg = (PackageImpl) o;
+ return fName.equals(pkg.fName)
+ && fIsUnnamed == pkg.fIsUnnamed
+ && fDevelopmentContext.equals(pkg.fDevelopmentContext);
+ }
+
+ /**
+ * Returns an array containing Type objects representing all
+ * classes and interfaces in the package represented by this object.
+ * This includes public and default (package) access top-level
+ * classes, inner classes, and local inner classes.
+ * Returns an array of length 0 if this package has no
+ * classes or interfaces.
+ * The Types are in no particular order.
+ */
+ public IType[] getAllClasses() throws NotPresentException {
+ return nonStateSpecific(inCurrentState0().getAllClasses());
+ }
+
+ /**
+ * Returns a handle representing the class or interface
+ * with the given name. The name is the VM class name,
+ * not including the package name.
+ * For inner classes, the name is as described in the
+ * <em>Inner Classes Specification</em>.
+ * This is a handle-only method; the specified class
+ * may or may not actually be present in the image.
+ */
+ public IType getClassHandle(String name) {
+ return new ClassOrInterfaceHandleImpl(name, this);
+ }
+
+ /**
+ * Returns an array of Type objects representing all the classes
+ * and interfaces declared as members of the package represented by
+ * this object. This includes public and default (package) access
+ * classes and interfaces declared as members of the package.
+ * This does not include inner classes and interfaces.
+ * Returns an array of length 0 if this package declares no classes
+ * or interfaces as members.
+ * The Types are in no particular order.
+ */
+ public IType[] getDeclaredClasses() throws NotPresentException {
+ return nonStateSpecific(inCurrentState0().getDeclaredClasses());
+ }
+
+ /**
+ * Return the internal representation of the development context that owns this object
+ */
+ JavaDevelopmentContextImpl getInternalDC() {
+ return fDevelopmentContext;
+ }
+
+ /**
+ * Returns the fully-qualified name of the package represented
+ * by this object, as a String.
+ * If the package is unnamed, returns the internal identifier
+ * string of this unnamed packaged.
+ * This is a handle-only method.
+ */
+ public String getName() {
+ return fName;
+ }
+
+ /**
+ * Returns an array of Package objects representing all other
+ * packages which this package directly references.
+ * This is the union of all packages directly referenced by all
+ * classes and interfaces in this package, including packages
+ * mentioned in import declarations.
+ * <p>
+ * A direct reference in source code is a use of a package's
+ * name other than as a prefix of another package name.
+ * For example, 'java.lang.Object' contains a direct reference
+ * to the package 'java.lang', but not to the package 'java'.
+ * Also note that every package that declares at least one type
+ * contains a direct reference to java.lang in virtue of the
+ * automatic import of java.lang.*.
+ * The result does not include this package (so contrary to the note
+ * above, the result for package java.lang does not include java.lang).
+ * In other words, the result is non-reflexive and typically
+ * non-transitive.
+ * <p>
+ * The resulting packages may or may not be present in the image,
+ * since the classes and interfaces in this package may refer to missing
+ * packages.
+ * The resulting packages are in no particular order.
+ */
+ public IPackage[] getReferencedPackages() throws NotPresentException {
+ return nonStateSpecific(inCurrentState0().getReferencedPackages());
+ }
+
+ /**
+ * Returns an array of Package objects representing all packages
+ * in the given image context which directly reference this package.
+ * The result does not include this package.
+ * In other words, the result is non-transitive and non-reflexive.
+ * <p>
+ * The intersection of all packages in the image and those in the
+ * image context are considered, so the resulting packages are
+ * guaranteed to be present in the image.
+ * The resulting packages are in no particular order.
+ */
+ public IPackage[] getReferencingPackages(IImageContext context)
+ throws NotPresentException {
+ return nonStateSpecific(inCurrentState0().getReferencingPackages(context));
+ }
+
+ /**
+ * Returns an array of SourceFragments describing the source package
+ * fragments from which this built package is derived.
+ * Returns an empty array if this package is not derived directly from source
+ * (e.g. package com.oti.requiem.fictional).
+ * The source coordinates in the results are set to #(1 0).
+ */
+ public ISourceFragment[] getSourceFragments() throws NotPresentException {
+ return inCurrentState0().getSourceFragments();
+ }
+
+ /**
+ * Returns a consistent hash code for this object
+ */
+ public int hashCode() {
+ return fName.hashCode();
+ }
+
+ /**
+ * Returns a state-specific version of this handle in the current state
+ */
+ private PackageImplSWH inCurrentState0() {
+ return new PackageImplSWH(fDevelopmentContext.fCurrentState, this);
+ }
+
+ /**
+ * Returns a state specific version of this handle in the given state.
+ */
+ public IHandle inState(IState s)
+ throws org.eclipse.jdt.internal.core.builder.StateSpecificException {
+ return new PackageImplSWH((StateImpl) s, this);
+ }
+
+ /**
+ * Returns true if this package is an unnamed package, false
+ * otherwise. See <em>The Java Language Specification</em>,
+ * sections 7.4.1 and 7.4.2, for details.
+ * This is a handle-only method.
+ */
+ public boolean isUnnamed() {
+ return fIsUnnamed;
+ }
+
+ /**
+ * Returns a constant indicating what kind of handle this is.
+ */
+ public int kind() {
+ return K_JAVA_PACKAGE;
+ }
+
+ /**
+ * Returns the readable name for the given package,
+ * suitable for use in progress messages.
+ */
+ public static String readableName(IPackage pkg) {
+ String name = pkg.getName();
+ if (pkg.isUnnamed()) {
+ return "default package for " + name.substring(DEFAULT_PACKAGE_PREFIX.length());
+ } else {
+ return "package " + name;
+ }
+ }
+
+ /**
+ * Returns a string representation of the package. For debugging purposes
+ * only (NON-NLS).
+ */
+ public String toString() {
+ String result = "package ";
+ if (isUnnamed())
+ result += "{unnamed, id=" + getName() + "}";
+ else
+ result += getName();
+ return result;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PackageImplSWH.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PackageImplSWH.java
new file mode 100644
index 0000000000..730634e451
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PackageImplSWH.java
@@ -0,0 +1,214 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IPath;
+
+import org.eclipse.jdt.internal.core.builder.*;
+
+import java.util.*;
+
+public class PackageImplSWH
+ extends StateSpecificHandleImpl
+ implements IPackage {
+ PackageImpl fHandle;
+ /**
+ * Internal - Create a new Package
+ */
+ PackageImplSWH(StateImpl state, PackageImpl handle)
+ throws NotPresentException {
+ if (state == null)
+ throw new NotPresentException();
+ fState = state;
+ fHandle = handle;
+ }
+
+ /**
+ * Returns an array containing Type objects representing all
+ * classes and interfaces in the package represented by this object.
+ * This includes public and default (package) access top-level
+ * classes, inner classes, and local inner classes.
+ * Returns an array of length 0 if this package has no
+ * classes or interfaces.
+ * The Types are in no particular order.
+ * This is a slow method. getDeclaredClasses() should be used for most cases.
+ */
+ public IType[] getAllClasses() throws NotPresentException {
+
+ TypeStructureEntry[] entries = fState.getAllTypesForPackage(fHandle);
+ if (entries == null) {
+ throw new NotPresentException();
+ }
+ IType[] results = new IType[entries.length];
+ for (int i = 0, num = entries.length; i < num; ++i) {
+ results[i] = (IType) entries[i].getType().inState(fState);
+ }
+ return results;
+ }
+
+ /**
+ * getClassHandle method comment.
+ * Returns a handle representing the class or interface
+ * with the given name. The name is the VM class name,
+ * not including the package name.
+ * For inner classes, the name is as described in the
+ * <em>Inner Classes Specification</em>.
+ * This is a handle-only method; the specified class
+ * may or may not actually be present in the image.
+ */
+ public IType getClassHandle(String name) {
+ return (IType) fHandle.getClassHandle(name).inState(fState);
+ }
+
+ /**
+ * Returns an array of Type objects representing all the classes
+ * and interfaces declared as members of the package represented by
+ * this object. This includes public and default (package) access
+ * classes and interfaces declared as members of the package.
+ * This does not include inner classes and interfaces.
+ * Returns an array of length 0 if this package declares no classes
+ * or interfaces as members.
+ * The Types are in no particular order.
+ */
+ public IType[] getDeclaredClasses() throws NotPresentException {
+ TypeStructureEntry[] entries = fState.getAllTypesForPackage(fHandle);
+ if (entries == null) {
+ throw new NotPresentException();
+ }
+ int num = entries.length;
+ IType[] results = new IType[num];
+ int count = 0;
+ for (int i = 0; i < num; ++i) {
+ if (BinaryStructure.isPackageMember(fState.getBinaryType(entries[i]))) {
+ results[count++] = (IType) entries[i].getType().inState(fState);
+ }
+ }
+ if (count < num) {
+ System.arraycopy(results, 0, results = new IType[count], 0, count);
+ }
+ return results;
+ }
+
+ /**
+ * Returns the fully-qualified name of the package represented
+ * by this object, as a String.
+ * If the package is unnamed, returns the internal identifier
+ * string of this unnamed packaged.
+ * This is a handle-only method.
+ */
+ public String getName() {
+ return fHandle.getName();
+ }
+
+ /**
+ * Returns an array of Package objects representing all other
+ * packages which this package directly references.
+ * This is the union of all packages directly referenced by all
+ * classes and interfaces in this package, including packages
+ * mentioned in import declarations.
+ * <p>
+ * A direct reference in source code is a use of a package's
+ * name other than as a prefix of another package name.
+ * For example, 'java.lang.Object' contains a direct reference
+ * to the package 'java.lang', but not to the package 'java'.
+ * Also note that every package that declares at least one type
+ * contains a direct reference to java.lang in virtue of the
+ * automatic import of java.lang.*.
+ * The result does not include this package (so contrary to the note
+ * above, the result for package java.lang does not include java.lang).
+ * In other words, the result is non-reflexive and typically
+ * non-transitive.
+ * <p>
+ * The resulting packages may or may not be present in the image,
+ * since the classes and interfaces in this package may refer to missing
+ * packages.
+ * The resulting packages are in no particular order.
+ */
+ public IPackage[] getReferencedPackages() throws NotPresentException {
+ if (!isPresent())
+ throw new NotPresentException();
+ IPackage[] pkgs = fState.getReferencedPackages((IPackage) nonStateSpecific());
+
+ /* wrapped returned packages in state handles */
+ for (int i = 0; i < pkgs.length; i++) {
+ pkgs[i] = (IPackage) pkgs[i].inState(fState);
+ }
+ return pkgs;
+
+ }
+
+ /**
+ * Returns an array of Package objects representing all packages
+ * in the given image context which directly reference this package.
+ * The result does not include this package.
+ * In other words, the result is non-transitive and non-reflexive.
+ * <p>
+ * The intersection of all packages in the image and those in the
+ * image context are considered, so the resulting packages are
+ * guaranteed to be present in the image.
+ * The resulting packages are in no particular order.
+ */
+ public IPackage[] getReferencingPackages(IImageContext context)
+ throws NotPresentException {
+ if (!isPresent())
+ throw new NotPresentException("Not present");
+
+ IPackage[] pkgs = fState.getReferencingPackages(fHandle, context);
+
+ /* wrap packages in state */
+ for (int i = 0; i < pkgs.length; i++) {
+ pkgs[i] = (IPackage) pkgs[i].inState(fState);
+ }
+ return pkgs;
+ }
+
+ /**
+ * Returns an array of SourceFragments describing the source package
+ * fragments from which this built package is derived.
+ * Returns an empty array if this package is not derived directly from source
+ * The source coordinates in the results are set to #(-1, -1).
+ *
+ * If this is a default package, we must resolve the project name from the
+ * internal identifier
+ */
+ public ISourceFragment[] getSourceFragments() throws NotPresentException {
+
+ IPath[] paths = fState.getPackageMap().getFragments(fHandle);
+ if (paths == null) {
+ throw new NotPresentException();
+ }
+ int max = paths.length;
+ ISourceFragment[] frags = new ISourceFragment[max];
+ for (int i = 0; i < max; i++) {
+ frags[i] = new SourceFragmentImpl(-1, -1, paths[i]);
+ }
+ return frags;
+ }
+
+ /**
+ * isPresent method comment.
+ */
+ public boolean isPresent() {
+ return fState.getPackageMap().containsPackage(fHandle);
+ }
+
+ /**
+ * Returns true if this package is an unnamed package, false
+ * otherwise. See <em>The Java Language Specification</em>,
+ * sections 7.4.1 and 7.4.2, for details.
+ * This is a handle-only method.
+ */
+ public boolean isUnnamed() {
+ return fHandle.isUnnamed();
+ }
+
+ /**
+ * Returns the non state specific handle
+ */
+ public IHandle nonStateSpecific() {
+ return fHandle;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PackageMap.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PackageMap.java
new file mode 100644
index 0000000000..c7623428d8
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PackageMap.java
@@ -0,0 +1,138 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.jdt.internal.core.builder.IPackage;
+import java.util.*;
+
+/**
+ * The state's package map.
+ */
+public class PackageMap extends StateTables {
+ Hashtable fTable;
+ /**
+ * Creates a new package map
+ */
+ PackageMap() {
+ fTable = new Hashtable(23);
+ }
+
+ /**
+ * Returns true if the package exists in the state, otherwise
+ * returns false
+ */
+ boolean containsPackage(IPackage pkg) {
+ return fTable.containsKey(pkg);
+ }
+
+ /**
+ * Creates a copy of the package map.
+ */
+ PackageMap copy() {
+ try {
+ PackageMap copy = (PackageMap) super.clone();
+ copy.fTable = (Hashtable) fTable.clone();
+ return copy;
+ } catch (CloneNotSupportedException e) {
+ // Should not happen.
+ throw new Error();
+ }
+ }
+
+ /**
+ * Returns an enumeration of all packages in the state. The enumeration
+ * is of non state-specific package handles.
+ */
+ public Enumeration getAllPackages() {
+ return fTable.keys();
+ }
+
+ /**
+ * Returns all packages in the state. The result is an array
+ * of non state-specific package handles.
+ */
+ public IPackage[] getAllPackagesAsArray() {
+ IPackage[] pkgs = new IPackage[fTable.size()];
+ int i = 0;
+ for (Enumeration e = fTable.keys(); e.hasMoreElements();) {
+ pkgs[i++] = (IPackage) e.nextElement();
+ }
+ return pkgs;
+ }
+
+ /**
+ * Returns the package map entry for a given package.
+ * Returns null if the package is not present.
+ */
+ PackageMapEntry getEntry(IPackage pkg) {
+ return (PackageMapEntry) fTable.get(pkg);
+ }
+
+ /**
+ * Returns the package fragments for a given package. The returned
+ * fragments are sorted according to the class path.
+ * Returns null if the package is not present.
+ */
+ IPath[] getFragments(IPackage pkg) {
+ PackageMapEntry entry = (PackageMapEntry) fTable.get(pkg);
+ return entry == null ? null : entry.getFragments();
+ }
+
+ /**
+ * Adds a fragment entry for the given package.
+ * Mutable operation, should only be used when recreating package map.
+ */
+ void putFragment(IPackage pkg, IPath frag) {
+ PackageMapEntry entry = (PackageMapEntry) fTable.get(pkg);
+ if (entry == null) {
+ entry = new PackageMapEntry(pkg);
+ fTable.put(pkg, entry);
+ }
+ entry.addFragment(frag);
+ }
+
+ /**
+ * Adds an array of fragments for the given package. Assumes that the
+ * given array of fragments are in classpath order.
+ */
+ void putFragments(IPackage pkg, IPath[] frags) {
+ PackageMapEntry entry = (PackageMapEntry) fTable.get(pkg);
+ if (entry == null) {
+ entry = new PackageMapEntry(pkg);
+ fTable.put(pkg, entry);
+ }
+ entry.addFragments(frags);
+ }
+
+ /**
+ * Returns the number of packages in the state.
+ */
+ int size() {
+ return fTable.size();
+ }
+
+ /**
+ * For debugging only.
+ */
+ public String toString() {
+ IPackage[] pkgs = getAllPackagesAsArray();
+ Arrays.sort(pkgs, StateImpl.getPackageComparator());
+ StringBuffer sb = new StringBuffer();
+ sb.append(super.toString() + ":\n");
+ for (int i = 0; i < pkgs.length; ++i) {
+ sb.append(" " + pkgs[i].getName() + ": ");
+ IPath[] fragments = getFragments(pkgs[i]);
+ for (int j = 0; j < fragments.length; ++j) {
+ if (j != 0)
+ sb.append(", ");
+ sb.append(fragments[j]);
+ }
+ sb.append("\n");
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PackageMapEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PackageMapEntry.java
new file mode 100644
index 0000000000..231d5177e0
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PackageMapEntry.java
@@ -0,0 +1,94 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IPath;
+
+import org.eclipse.jdt.internal.core.builder.IPackage;
+
+import java.util.Hashtable;
+
+/**
+ * These objects are used as entries in the State's package map table.
+ */
+class PackageMapEntry extends StateTables {
+ IPackage fPkg;
+ IPath[] fFragments;
+ /**
+ * Creates a new package map entry.
+ */
+ PackageMapEntry(IPackage pkg) {
+ fPkg = pkg;
+ fFragments = null;
+ }
+
+ /**
+ * Adds a new package fragment to the entry.
+ */
+ void addFragment(IPath fragment) {
+ if (fFragments == null) {
+ fFragments = new IPath[] { fragment };
+ } else {
+ for (int i = 0; i < fFragments.length; ++i) {
+ if (fFragments[i].equals(fragment)) {
+ System.out.println(
+ "Warning: internal error: attempt to add duplicate package fragment in image builder: "
+ + fragment);
+ return;
+ }
+ }
+ IPath[] newFragments = new IPath[fFragments.length + 1];
+ System.arraycopy(fFragments, 0, newFragments, 0, fFragments.length);
+ newFragments[fFragments.length] = fragment;
+ fFragments = newFragments;
+ }
+ }
+
+ /**
+ * Adds a new package fragment to the entry.
+ */
+ void addFragments(IPath[] fragments) {
+ if (fFragments == null) {
+ fFragments = new IPath[fragments.length];
+ System.arraycopy(fragments, 0, fFragments, 0, fragments.length);
+ } else {
+ IPath[] newFragments = new IPath[fFragments.length + fragments.length];
+ System.arraycopy(fFragments, 0, newFragments, 0, fFragments.length);
+ System.arraycopy(
+ fragments,
+ 0,
+ newFragments,
+ fFragments.length,
+ fragments.length);
+ fFragments = newFragments;
+ }
+ }
+
+ /**
+ * Returns an the fragments in the package
+ */
+ IPath[] getFragments() {
+ return fFragments;
+ }
+
+ /**
+ * Returns the package for which this is the entry.
+ */
+ IPackage getPackage() {
+ return fPkg;
+ }
+
+ /**
+ * Returns a String that represents the value of this object.
+ * This method is for debugging purposes only.
+ */
+ public String toString() {
+ StringBuffer buf = new StringBuffer("PackageMapEntry(");
+ buf.append(fPkg);
+ buf.append(")");
+ return buf.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PathMap.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PathMap.java
new file mode 100644
index 0000000000..d309b57536
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PathMap.java
@@ -0,0 +1,142 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.jdt.internal.core.builder.IPackage;
+import java.util.*;
+import org.eclipse.jdt.internal.core.util.LookupTable;
+
+/**
+ * A PathMap is essentially a reverse-indexed package map. It maps
+ * from IPaths to a IPackage[], the packages contributed by that path.
+ * In most cases a path contributes only one package, but if the path
+ * happens to be a zip, it can contribute many package fragments.
+ */
+class PathMap extends StateTables {
+ /**
+ * Make it a dictionary so the implementation can be either
+ * a LookupTable or a Hashtable.
+ */
+ Dictionary fTable;
+
+ /**
+ * Creates a new path map given a package map. The package map is
+ * from IPackage -> IPath[]. This creates a path map that maps
+ * from IPath -> IPackage[]
+ */
+ PathMap(PackageMap pkgMap) {
+ fTable = packageMapToPathMap(pkgMap);
+ }
+
+ /**
+ * Returns the paths which are the keys in the path map.
+ */
+ IPath[] getPaths() {
+ IPath[] paths = new IPath[fTable.size()];
+ int count = 0;
+ for (Enumeration e = fTable.keys(); e.hasMoreElements();) {
+ paths[count++] = (IPath) e.nextElement();
+ }
+ return paths;
+ }
+
+ /**
+ * Returns whether the path map contains the given path as a key.
+ */
+ boolean hasPath(IPath path) {
+ return fTable.get(path) != null;
+ }
+
+ /**
+ * Returns the package handle for the given package resource.
+ * Throws an internal error if the path was inappropriate.
+ */
+ IPackage packageHandleFromPath(IPath path) {
+ IPackage[] pkgs = (IPackage[]) fTable.get(path);
+ if (pkgs == null) {
+ throw new Error("Attempt to access packages for non-existent path:" + path);
+ }
+ if (pkgs.length != 1) {
+ throw new Error("Didn't get exactly one package for " + path);
+ }
+ return pkgs[0];
+ }
+
+ /**
+ * Returns the package handles for the given package resource.
+ */
+ IPackage[] packageHandlesFromPath(IPath path) {
+ IPackage[] pkgs = (IPackage[]) fTable.get(path);
+ return pkgs != null ? pkgs : new IPackage[0];
+ }
+
+ /**
+ * Creates and returns new path map given a package map. The package map is
+ * from IPackage -> IPath[]. The new path map is from IPath -> IPackage[]
+ */
+ protected Dictionary packageMapToPathMap(PackageMap pkgMap) {
+ LookupTable table = new LookupTable();
+
+ /* first generate a path map using vectors */
+ for (Enumeration e = pkgMap.getAllPackages(); e.hasMoreElements();) {
+ IPackage pkg = (IPackage) e.nextElement();
+ IPath[] paths = pkgMap.getFragments(pkg);
+
+ /* add entries in the path map for each fragment */
+ for (int i = 0; i < paths.length; i++) {
+ Vector v = (Vector) table.get(paths[i]);
+ if (v == null) {
+ /* most common case is one path per package */
+ v = new Vector(1);
+ table.put(paths[i], v);
+ }
+ v.addElement(pkg);
+ }
+ }
+
+ /* convert vectors to arrays */
+ for (Enumeration e = table.keys(); e.hasMoreElements();) {
+ IPath path = (IPath) e.nextElement();
+ Vector v = (Vector) table.get(path);
+ IPackage[] pkgs = new IPackage[v.size()];
+ v.copyInto(pkgs);
+ table.put(path, pkgs);
+ }
+ return table;
+ }
+
+ /**
+ * For debugging only.
+ */
+ public String toString() {
+ ArrayList list = new ArrayList();
+ for (Enumeration e = fTable.keys(); e.hasMoreElements();) {
+ IPath path = (IPath) e.nextElement();
+ list.add(path);
+ }
+ Collections.sort(list, StateImpl.getPathComparator());
+ StringBuffer sb = new StringBuffer();
+ sb.append(super.toString() + ":\n");
+ for (int i = 0; i < list.size(); ++i) {
+ IPath path = (IPath) list.get(i);
+ sb.append(" " + path + ": ");
+ IPackage[] pkgs = packageHandlesFromPath(path);
+ if (pkgs.length == 1) {
+ sb.append(pkgs[0].getName());
+ } else {
+ Arrays.sort(pkgs, StateImpl.getPackageComparator());
+ sb.append("(" + pkgs.length + " packages)");
+ for (int j = 0; j < pkgs.length; ++j) {
+ sb.append("\n ");
+ sb.append(pkgs[j].getName());
+ }
+ }
+ sb.append("\n");
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PrimitiveTypeHandleImpl.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PrimitiveTypeHandleImpl.java
new file mode 100644
index 0000000000..aedc255e67
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PrimitiveTypeHandleImpl.java
@@ -0,0 +1,262 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.Assert;
+import org.eclipse.jdt.internal.core.builder.*;
+
+import java.util.Hashtable;
+
+public class PrimitiveTypeHandleImpl extends TypeImpl implements IType {
+ JavaDevelopmentContextImpl fDevelopmentContext;
+ int fTypeCode;
+
+ /*
+ * Type codes
+ */
+ static final int TC_BOOLEAN = 0;
+ static final int TC_BYTE = 1;
+ static final int TC_CHAR = 2;
+ static final int TC_SHORT = 3;
+ static final int TC_INT = 4;
+ static final int TC_LONG = 5;
+ static final int TC_FLOAT = 6;
+ static final int TC_DOUBLE = 7;
+ static final int TC_ARRAY = 9;
+ static final int TC_CLASS = 10;
+ static final int TC_VOID = 11;
+ /**
+ * Creates a new primitive type with the given type code
+ */
+ PrimitiveTypeHandleImpl(JavaDevelopmentContextImpl dc, char typeCode) {
+ fDevelopmentContext = dc;
+ switch (typeCode) {
+ case 'I' :
+ fTypeCode = TC_INT;
+ break;
+ case 'F' :
+ fTypeCode = TC_FLOAT;
+ break;
+ case 'V' :
+ fTypeCode = TC_VOID;
+ break;
+ case 'Z' :
+ fTypeCode = TC_BOOLEAN;
+ break;
+ case 'B' :
+ fTypeCode = TC_BYTE;
+ break;
+ case 'S' :
+ fTypeCode = TC_SHORT;
+ break;
+ case 'C' :
+ fTypeCode = TC_CHAR;
+ break;
+ case 'J' :
+ fTypeCode = TC_LONG;
+ break;
+ case 'D' :
+ fTypeCode = TC_DOUBLE;
+ break;
+ }
+ }
+
+ /**
+ * Appends the signature for this type to the StringBuffer
+ * If includeUnnamed is true, then the identifiers for unnamed packages
+ * are included, preceded by '$'. Otherwise, they are excluded.
+ */
+ void appendSignature(StringBuffer sb, boolean includeUnnamed) {
+ char sig;
+ switch (fTypeCode) {
+ case TC_BOOLEAN :
+ sig = 'Z';
+ break;
+ case TC_BYTE :
+ sig = 'B';
+ break;
+ case TC_CHAR :
+ sig = 'C';
+ break;
+ case TC_DOUBLE :
+ sig = 'D';
+ break;
+ case TC_FLOAT :
+ sig = 'F';
+ break;
+ case TC_INT :
+ sig = 'I';
+ break;
+ case TC_LONG :
+ sig = 'J';
+ break;
+ case TC_SHORT :
+ sig = 'S';
+ break;
+ case TC_VOID :
+ sig = 'V';
+ break;
+ default :
+ Assert.isTrue(false, "invalid type code");
+ sig = ' ';
+ }
+ sb.append(sig);
+ }
+
+ /**
+ * Appends the VM signature of the type to the StringBuffer.
+ */
+ void appendVMSignature(StringBuffer sb) {
+ sb.append(typeSignature(fTypeCode));
+ }
+
+ /**
+ * Compares this object against the specified object.
+ * Returns true if the objects are the same.
+ */
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof PrimitiveTypeHandleImpl))
+ return false;
+
+ PrimitiveTypeHandleImpl prim = (PrimitiveTypeHandleImpl) o;
+ return fTypeCode == prim.fTypeCode
+ && fDevelopmentContext.equals(prim.fDevelopmentContext);
+ }
+
+ public JavaDevelopmentContextImpl getInternalDC() {
+ return fDevelopmentContext;
+ }
+
+ /**
+ * Returns the fully-qualified name of the type (class, interface,
+ * array, or primitive) represented by this object, as a String.
+ * For classes and interfaces, the name is the VM class name,
+ * including the package name.
+ * For inner classes, the name is as described in the
+ * <em>Inner Classes Specification</em>.
+ * For array types, the name is the name of the component type, followed by '[]'.
+ * For primitive types, the name is the keyword for the primitive type.
+ * This is a handle-only method.
+ */
+ public String getName() {
+ return getSimpleName();
+ }
+
+ /**
+ * Returns the simple name of the type (class, interface, array,
+ * or primitive) represented by this object, as a String.
+ * For classes and interfaces, this is the VM class name,
+ * excluding the package name.
+ * For array types, this is the simple name of the component type, followed by '[]'.
+ * For primitive types, this is the keyword for the primitive type.
+ * This is a handle-only method.
+ */
+ public String getSimpleName() {
+ switch (fTypeCode) {
+ case TC_BOOLEAN :
+ return "boolean";
+ case TC_BYTE :
+ return "byte";
+ case TC_CHAR :
+ return "char";
+ case TC_DOUBLE :
+ return "double";
+ case TC_FLOAT :
+ return "float";
+ case TC_INT :
+ return "int";
+ case TC_LONG :
+ return "long";
+ case TC_SHORT :
+ return "short";
+ case TC_VOID :
+ return "void";
+ default :
+ Assert.isTrue(false, "invalid type code");
+ }
+ return null;
+ }
+
+ int getTypeCode() {
+ return fTypeCode;
+ }
+
+ /**
+ * Returns the VM signature of the type.
+ */
+ String getVMSignature() {
+ return typeSignature(fTypeCode);
+ }
+
+ /**
+ * Returns a consistent hash code for this object
+ */
+ public int hashCode() {
+ return fTypeCode;
+ }
+
+ /**
+ * Returns a state specific version of this handle in the given state.
+ */
+ public IHandle inState(IState s)
+ throws org.eclipse.jdt.internal.core.builder.StateSpecificException {
+
+ return new PrimitiveTypeHandleImplSWH((StateImpl) s, this);
+ }
+
+ /**
+ * Determines if the specified Type object represents a primitive Java
+ * type.
+ * This is a handle-only method.
+ *
+ * <p>There are nine predefined Type objects to represent the eight
+ * primitive Java types and void. These are created by the Java
+ * Virtual Machine, and have the same names as the primitive types
+ * that they represent, namely boolean, byte, char, short, int,
+ * long, float, and double, and void.
+ */
+ public boolean isPrimitive() {
+ return true;
+ }
+
+ /**
+ * Returns a string representation of the package. For debugging purposes
+ * only (NON-NLS).
+ */
+ public String toString() {
+ return getName();
+ }
+
+ /**
+ * Convert a base type code to the VM naming format
+ */
+ protected static String typeSignature(int typeCode) {
+ switch (typeCode) {
+ case TC_VOID :
+ return "V";
+ case TC_BOOLEAN :
+ return "Z";
+ case TC_BYTE :
+ return "B";
+ case TC_CHAR :
+ return "C";
+ case TC_SHORT :
+ return "S";
+ case TC_INT :
+ return "I";
+ case TC_LONG :
+ return "J";
+ case TC_FLOAT :
+ return "F";
+ case TC_DOUBLE :
+ return "D";
+ default :
+ return "unknown";
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PrimitiveTypeHandleImplSWH.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PrimitiveTypeHandleImplSWH.java
new file mode 100644
index 0000000000..e745c9a053
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/PrimitiveTypeHandleImplSWH.java
@@ -0,0 +1,52 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.builder.*;
+
+public class PrimitiveTypeHandleImplSWH extends TypeImplSWH {
+ PrimitiveTypeHandleImpl fHandle;
+ /**
+ * Creates a new method handle in the given state
+ */
+ PrimitiveTypeHandleImplSWH(StateImpl state, IType handle) {
+ fState = state;
+ try {
+ fHandle = (PrimitiveTypeHandleImpl) handle;
+ } catch (ClassCastException e) {
+ throw new StateSpecificException();
+ }
+ }
+
+ /**
+ * Returns the non state specific handle
+ */
+ protected TypeImpl getHandle() {
+ return fHandle;
+ }
+
+ /**
+ * Primitive types are always present.
+ */
+ public boolean isPresent() {
+ return true;
+ }
+
+ /**
+ * Determines if the specified Type object represents a primitive Java
+ * type.
+ * This is a handle-only method.
+ *
+ * <p>There are nine predefined Type objects to represent the eight
+ * primitive Java types and void. These are created by the Java
+ * Virtual Machine, and have the same names as the primitive types
+ * that they represent, namely boolean, byte, char, short, int,
+ * long, float, and double, and void.
+ */
+ public boolean isPrimitive() {
+ return true;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ProblemDetailImpl.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ProblemDetailImpl.java
new file mode 100644
index 0000000000..56698e2eb5
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ProblemDetailImpl.java
@@ -0,0 +1,237 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IPath;
+
+import org.eclipse.jdt.internal.compiler.IProblem;
+import org.eclipse.jdt.internal.core.builder.*;
+import org.eclipse.jdt.internal.core.Util;
+
+/**
+ * @see IProblemDetail
+ */
+public class ProblemDetailImpl implements IProblemDetail, IProblem {
+ protected SourceEntry fSourceEntry;
+ protected String fMessage;
+ protected int fStartPos, fEndPos, fLineNumber;
+ protected int fSeverity;
+
+ /**
+ * The ID of the problem returned by the compiler.
+ * @see com.ibm.compiler.java.problem.ProblemIrritants
+ */
+ protected int fID;
+
+ /**
+ * Severity flag indicating a syntax error (also covers namespace errors such as duplicates).
+ */
+ protected static final int S_SYNTAX_ERROR = 2;
+ /**
+ * Creates a problem detail.
+ */
+ public ProblemDetailImpl(
+ String msg,
+ int id,
+ int severity,
+ SourceEntry sourceEntry,
+ int startPos,
+ int endPos,
+ int lineNumber) {
+ fMessage = msg;
+ fID = id;
+ fSeverity = severity;
+ fSourceEntry = sourceEntry;
+ fStartPos = startPos;
+ fEndPos = endPos;
+ fLineNumber = lineNumber;
+ }
+
+ /**
+ * Creates a problem detail.
+ */
+ public ProblemDetailImpl(String msg, SourceEntry sourceEntry) {
+ this(msg, 0, S_ERROR, sourceEntry, -1, -1, -1);
+ }
+
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(this instanceof ProblemDetailImpl))
+ return false;
+ return equals((ProblemDetailImpl) o, false);
+ }
+
+ public boolean equals(ProblemDetailImpl pb, boolean ignorePositions) {
+ return fMessage.equals(pb.fMessage)
+ && Util.equalOrNull(fSourceEntry, pb.fSourceEntry)
+ && fSeverity == pb.fSeverity
+ && (ignorePositions || (fStartPos == pb.fStartPos && fEndPos == pb.fEndPos));
+ }
+
+ /**
+ * @see IProblem
+ */
+ public String[] getArguments() {
+ return null; // not kept
+ }
+
+ /**
+ * Returns the end pos.
+ */
+ public int getEndPos() {
+ return fEndPos;
+ }
+
+ /**
+ * @see IProblemDetail
+ */
+ public int getID() {
+ return fID;
+ }
+
+ /**
+ * @see IProblemDetail
+ */
+ public int getKind() {
+ return IProblemDetail.K_COMPILATION_PROBLEM;
+ }
+
+ /**
+ * @see IProblemDetail
+ */
+ public int getLineNumber() {
+ return fLineNumber;
+ }
+
+ /**
+ * @see IProblemDetail
+ */
+ public String getMessage() {
+ return fMessage;
+ }
+
+ /**
+ * getOriginatingFileName method comment.
+ */
+ public char[] getOriginatingFileName() {
+ return fSourceEntry.getPathWithZipEntryName().toCharArray();
+ }
+
+ /**
+ * Returns the path of the source entry.
+ */
+ IPath getPath() {
+ return fSourceEntry == null ? null : fSourceEntry.getPath();
+ }
+
+ /**
+ * @see IProblemDetail
+ */
+ public int getSeverity() {
+ return fSeverity;
+ }
+
+ /**
+ * @see IProblem
+ */
+ public int getSourceEnd() {
+ return fEndPos;
+ }
+
+ /**
+ * Returns the source entry
+ */
+ SourceEntry getSourceEntry() {
+ return fSourceEntry;
+ }
+
+ /**
+ * @see ICompilationProblem
+ */
+ public ISourceFragment getSourceFragment() {
+ if (fSourceEntry == null) {
+ return null;
+ }
+ return new SourceFragmentImpl(fStartPos, fEndPos, fSourceEntry);
+ }
+
+ /**
+ * @see IProblem
+ */
+ public int getSourceLineNumber() {
+ return fLineNumber;
+ }
+
+ /**
+ * @see IProblem
+ */
+ public int getSourceStart() {
+ return fStartPos;
+ }
+
+ /**
+ * Returns the start pos.
+ */
+ public int getStartPos() {
+ return fStartPos;
+ }
+
+ public int hashCode() {
+ return fMessage.hashCode() * 17
+ + (fSourceEntry == null ? 0 : fSourceEntry.hashCode());
+ }
+
+ /**
+ * @see IProblem
+ */
+ public boolean isError() {
+ return (fSeverity & S_ERROR) != 0;
+ }
+
+ /**
+ * @see IProblem
+ */
+ public boolean isWarning() {
+ return (fSeverity & S_ERROR) == 0;
+ }
+
+ /**
+ * @see IProblem
+ */
+ public void setSourceEnd(int sourceEnd) {
+ fEndPos = sourceEnd;
+ }
+
+ /**
+ * Internal - Set the source entry.
+ */
+ public void setSourceEntry(SourceEntry sourceEntry) {
+ fSourceEntry = sourceEntry;
+ }
+
+ /**
+ * @see IProblem
+ */
+ public void setSourceLineNumber(int lineNumber) {
+ fLineNumber = lineNumber;
+ }
+
+ /**
+ * @see IProblem
+ */
+ public void setSourceStart(int sourceStart) {
+ fStartPos = sourceStart;
+ }
+
+ /**
+ * Returns a readable representation of the class. This method is for debugging
+ * purposes only. Non-NLS.
+ */
+ public String toString() {
+ return "ProblemDetail(" + getMessage() + ")";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ProblemFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ProblemFactory.java
new file mode 100644
index 0000000000..d9971f5282
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ProblemFactory.java
@@ -0,0 +1,137 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.IProblem;
+import org.eclipse.jdt.internal.compiler.IProblemFactory;
+import org.eclipse.jdt.internal.core.builder.IProblemDetail;
+import org.eclipse.jdt.internal.compiler.problem.ProblemIrritants;
+
+import java.util.*;
+
+/**
+ * @see IProblemFactory
+ */
+public class ProblemFactory implements IProblemFactory {
+ protected Locale fLocale;
+ protected ResourceBundle fCompilerResources;
+ protected String[] fMessageTemplates;
+
+ protected static Hashtable fgFactories = new Hashtable(5);
+ /**
+ * Creates a problem factory for the given locale.
+ */
+ private ProblemFactory(Locale locale) {
+ fLocale = locale;
+ fCompilerResources =
+ ResourceBundle.getBundle(
+ "org.eclipse.jdt.internal.compiler.problem.Messages",
+ locale);
+ //$NON-NLS-1$
+ initializeMessageTemplates();
+ }
+
+ /**
+ * @see IProblemFactory
+ */
+ public IProblem createProblem(
+ char[] originatingFileName,
+ int problemId,
+ String[] arguments,
+ int severity,
+ int startPosition,
+ int endPosition,
+ int lineNumber) {
+ String message = getLocalizedMessage(problemId, arguments);
+ int sev = (severity & IProblem.Error) != 0 ? IProblemDetail.S_ERROR : 0;
+ // SourceEntry is filled in later when problem is actually recorded.
+ SourceEntry sEntry = null;
+ if (lineNumber == 0)
+ lineNumber = -1;
+ return new ProblemDetailImpl(
+ message,
+ problemId,
+ sev,
+ sEntry,
+ startPosition,
+ endPosition,
+ lineNumber);
+ }
+
+ /**
+ * @see IProblemFactory
+ */
+ public Locale getLocale() {
+ return fLocale;
+ }
+
+ /**
+ * @see IProblemFactory
+ */
+ public String getLocalizedMessage(int id, String[] problemArguments) {
+ StringBuffer output = new StringBuffer(80);
+ String message =
+ fMessageTemplates[(id & ProblemIrritants.IgnoreCategoriesMask)];
+ if (message == null) {
+ return "Unable to retrieve the error message for problem id: "
+ + id
+ + ". Check compiler resources.";
+ }
+ int length = message.length();
+ int start = -1, end = length;
+ while (true) {
+ if ((end = message.indexOf('{', start)) > -1) {
+ output.append(message.substring(start + 1, end));
+ if ((start = message.indexOf('}', end)) > -1) {
+ try {
+ output.append(
+ problemArguments[Integer.parseInt(message.substring(end + 1, start))]);
+ } catch (NumberFormatException nfe) {
+ output.append(message.substring(end + 1, start + 1));
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return "Corrupted compiler resources for problem id: "
+ + (id & ProblemIrritants.IgnoreCategoriesMask)
+ + ". Check compiler resources.";
+ }
+ } else {
+ output.append(message.substring(end, length));
+ break;
+ }
+ } else {
+ output.append(message.substring(start + 1, length));
+ break;
+ }
+ }
+ return output.toString();
+ }
+
+ /**
+ * Returns the problem factory for the given locale.
+ */
+ public static ProblemFactory getProblemFactory(Locale locale) {
+ ProblemFactory factory = (ProblemFactory) fgFactories.get(locale);
+ if (factory == null) {
+ factory = new ProblemFactory(locale);
+ fgFactories.put(locale, factory);
+ }
+ return factory;
+ }
+
+ /**
+ * This method initializes the messageTemplates variable according
+ * to the current Locale.
+ */
+ protected void initializeMessageTemplates() {
+ fMessageTemplates = new String[500];
+ for (int i = 0; i < fMessageTemplates.length; i++) {
+ try {
+ fMessageTemplates[i] = fCompilerResources.getString(String.valueOf(i));
+ //$NON-NLS-1$
+ } catch (MissingResourceException e) {
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ProblemTable.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ProblemTable.java
new file mode 100644
index 0000000000..a1d2cff1d8
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ProblemTable.java
@@ -0,0 +1,201 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.IProject;
+
+import org.eclipse.jdt.internal.core.builder.IProblemDetail;
+import org.eclipse.jdt.internal.core.builder.IProblemReporter;
+
+import java.util.*;
+import org.eclipse.jdt.internal.core.builder.IDevelopmentContext;
+
+/**
+ * A table of all the problems in the state, keyed by SourceEntry, and
+ * a vector of IProblemDetails as the values.
+ */
+public class ProblemTable extends StateTables implements IProblemReporter {
+ Hashtable fTable = new Hashtable(20);
+ Vector fImageProblems = new Vector(11);
+ /**
+ * Creates a copy of the table.
+ */
+ public IProblemReporter copy() {
+ try {
+ ProblemTable copy = (ProblemTable) super.clone();
+ copy.fTable = new Hashtable(fTable.size() * 2 + 1);
+ for (Enumeration e = fTable.keys(); e.hasMoreElements();) {
+ SourceEntry sEntry = (SourceEntry) e.nextElement();
+ Vector v = (Vector) fTable.get(sEntry);
+ copy.fTable.put(sEntry, v.clone());
+ }
+ return copy;
+ } catch (CloneNotSupportedException e) {
+ // Should not happen.
+ throw new Error();
+ }
+ }
+
+ /**
+ * Returns an enumeration of all problems with elements of the image,
+ * but not with the image itself.
+ */
+ public Enumeration getAllProblems() {
+
+ /* this is a very slow way of doing it.. is there a faster way? */
+ Vector allProblems = new Vector();
+ for (Enumeration e = fTable.elements(); e.hasMoreElements();) {
+ Vector problemVector = (Vector) e.nextElement();
+ for (Enumeration ee = problemVector.elements(); ee.hasMoreElements();) {
+ allProblems.addElement(ee.nextElement());
+ }
+ }
+ return allProblems.elements();
+ }
+
+ /**
+ * Returns the problems with the image itself. Returns null if no
+ * problems exist for the image. An example of such a problem is
+ * duplicate types in a package.
+ */
+ public Enumeration getImageProblems() {
+ return fImageProblems.elements();
+ }
+
+ /**
+ * Returns an enumeration of problem table keys (SourceEntry objects)
+ */
+ public Enumeration getProblemKeys() {
+ return fTable.keys();
+ }
+
+ /**
+ * Returns an enumeration of problems for a given source entry.
+ */
+ public Enumeration getProblems(Object entry) {
+ Vector vProblems = (Vector) fTable.get(entry);
+ if (vProblems == null) {
+ return new Vector().elements();
+ }
+ return vProblems.elements();
+ }
+
+ /**
+ * Returns a vector of problems for a given source entry,
+ * or null if no problems.
+ */
+ public Vector getProblemVector(Object entry) {
+ return (Vector) fTable.get(entry);
+ }
+
+ /**
+ * Returns whether the given entry has any problems.
+ */
+ public boolean hasProblems(Object entry) {
+ return fTable.get(entry) != null;
+ }
+
+ /**
+ * Adds a problem to the problem table. If the problem is a duplicate, it is
+ * not added and an error message is generated.
+ */
+ public void putProblem(Object entry, IProblemDetail problem) {
+ Vector problems = (Vector) fTable.get(entry);
+ if (problems == null) {
+ problems = new Vector();
+ fTable.put(entry, problems);
+ }
+ /* for (int i = 0; i < problems.size(); ++i) {
+ if (problem.equals(problems.elementAt(i))) {
+ System.err.println("DBG: Same error reported twice for " + entry + ": " + problem);
+ return;
+ }
+ }
+ */
+ problems.addElement(problem);
+ }
+
+ /**
+ * Removes all problems except syntax errors for the given source entry.
+ */
+ public void removeNonSyntaxErrors(Object entry) {
+ Vector problems = (Vector) fTable.get(entry);
+ if (problems != null) {
+ int i = 0;
+ while (i < problems.size()) {
+ IProblemDetail problem = (IProblemDetail) problems.elementAt(i);
+ if ((problem.getSeverity() & ProblemDetailImpl.S_SYNTAX_ERROR) == 0) {
+ problems.removeElementAt(i);
+ } else {
+ i++;
+ }
+ }
+ if (problems.isEmpty()) {
+ fTable.remove(entry);
+ }
+ }
+ }
+
+ /**
+ * Removes all problems for the given source entry
+ */
+ public void removeProblems(Object entry) {
+ fTable.remove(entry);
+ }
+
+ /**
+ * Removes all syntax errors for the given source entry.
+ */
+ public void removeSyntaxErrors(Object entry) {
+ Vector problems = (Vector) fTable.get(entry);
+ if (problems != null) {
+ int i = 0;
+ while (i < problems.size()) {
+ IProblemDetail problem = (IProblemDetail) problems.elementAt(i);
+ if ((problem.getSeverity() & ProblemDetailImpl.S_SYNTAX_ERROR) != 0) {
+ problems.removeElementAt(i);
+ } else {
+ i++;
+ }
+ }
+ if (problems.isEmpty()) {
+ fTable.remove(entry);
+ }
+ }
+ }
+
+ /**
+ * Returns the total number of problems in the table.
+ */
+ int size() {
+ int size = fImageProblems.size();
+ for (Enumeration e = fTable.elements(); e.hasMoreElements();) {
+ Vector v = (Vector) e.nextElement();
+ size += v.size();
+ }
+ return size;
+ }
+
+ /**
+ * Returns a String that represents the value of this object.
+ * @return a string representation of the receiver
+ */
+ public String toString() {
+ StringBuffer buf = new StringBuffer("ProblemTable(\n\t");
+ buf.append("type problems: ");
+ buf.append(fTable);
+ buf.append("\n\timage problems: ");
+ buf.append(fImageProblems);
+ buf.append(")");
+ return buf.toString();
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.core.builder.IProblemReporter
+ */
+ public void initialize(IProject project, IDevelopmentContext dc) {
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ProjectBinaryOutput.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ProjectBinaryOutput.java
new file mode 100644
index 0000000000..1fd2228263
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ProjectBinaryOutput.java
@@ -0,0 +1,254 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Path;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.core.Assert;
+import org.eclipse.jdt.internal.core.builder.IState;
+import org.eclipse.jdt.internal.core.builder.IType;
+import org.eclipse.jdt.internal.core.Util;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.*;
+
+/**
+ * A <ProjectBinaryOutput> is a <BinaryOutput> that stores the
+ * binaries in a folder of an <IProject>.
+ */
+public class ProjectBinaryOutput extends BinaryOutput {
+ private IProject project;
+ private IPath outputPath;
+ private JavaDevelopmentContextImpl dc;
+
+ public final static String ADDED = "ADDED";
+ public final static String MODIFIED = "MODIFIED";
+ public final static String DELETED = "DELETED";
+
+ /**
+ * Creates a new ProjectBinaryOutput for the given project and output path
+ * in this project.
+ */
+ public ProjectBinaryOutput(
+ IProject project,
+ IPath outputPath,
+ JavaDevelopmentContextImpl dc) {
+ this.project = project;
+ this.outputPath = outputPath;
+ this.dc = dc;
+
+ /* create the output folder is it doesn't exist */
+ if (!project.getFullPath().equals(outputPath)) {
+ this.makeContainersIfNecessary(outputPath);
+ }
+ }
+
+ /**
+ * @see BinaryOutput
+ */
+ protected void basicPutBinary(
+ TypeStructureEntry tsEntry,
+ byte[] binary,
+ int crc) {
+
+ IType type;
+ IPath path = getPathForBinary(type = tsEntry.getType());
+ deleteBinary(type);
+
+ IContainer container = makeContainersIfNecessary(path.removeLastSegments(1));
+
+ PackageElement element =
+ new PackageElement(type.getPackage(), new SourceEntry(path, null, null));
+ IFile file = container.getFile(new Path(path.lastSegment()));
+
+ try {
+ ByteArrayInputStream stream = new ByteArrayInputStream(binary);
+ file.create(stream, true, null);
+ } catch (CoreException e) {
+ throw this.dc.internalException(e);
+ }
+ }
+
+ /**
+ * Deletes everything in the given container.
+ */
+ private void deleteAllInContainer(IContainer container) {
+ try {
+ if (!container.exists())
+ return;
+ IResource[] members = container.members();
+ for (int i = 0, max = members.length; i < max; i++) {
+ IResource resource = (IResource) members[i];
+ resource.delete(true, null);
+ }
+ } catch (CoreException e) {
+ throw this.dc.internalException(e);
+ }
+ }
+
+ /**
+ * @see BinaryOutput
+ */
+ public void deleteBinary(IType type) {
+ IPath path = getPathForBinary(type);
+ IFile file = getFile(path);
+ try {
+ file.delete(true, null);
+ } catch (CoreException e) {
+ throw this.dc.internalException(e);
+ }
+ }
+
+ /**
+ * Deletes the classes in the given container, recursively.
+ * Delete any folders which become empty.
+ */
+ private void deleteClassesInContainer(IContainer container) {
+ try {
+ if (!container.exists())
+ return;
+ IResource[] members = container.members();
+ for (int i = 0, max = members.length; i < max; i++) {
+ IResource resource = (IResource) members[i];
+ switch (resource.getType()) {
+ case IResource.FILE :
+ if (resource.getName().toLowerCase().endsWith(".class")) {
+ resource.delete(true, null);
+ }
+ break;
+ case IResource.PROJECT :
+ case IResource.FOLDER :
+ deleteClassesInContainer((IContainer) resource);
+ break;
+ }
+ }
+ //
+ // Don't delete empty folders, since the output may overlap with the source, and
+ // we don't want to delete empty folders which the user may have created.
+ //
+ // if (container.getType() == IResource.FOLDER && !container.members().hasMoreElements()) {
+ // container.delete(true, null);
+ // }
+ } catch (CoreException e) {
+ throw this.dc.internalException(e);
+ }
+ }
+
+ /**
+ * @see BinaryOutput
+ */
+ public void garbageCollect(IState[] statesInUse) {
+ // Nothing to do for a Project binary output
+ }
+
+ /**
+ * @see BinaryOutput
+ */
+ public byte[] getBinary(TypeStructureEntry tsEntry, IType type) {
+ IPath path = getPathForBinary(type);
+ IFile file = getFile(path);
+ try {
+ InputStream input = file.getContents(true);
+ return Util.readContentsAsBytes(input);
+ } catch (IOException e) {
+ throw this.dc.internalException(e);
+ } catch (CoreException e) {
+ return this.dc.getBinaryFromFileSystem(file);
+ }
+ }
+
+ /**
+ * Returns the container for a path.
+ */
+ private IContainer getContainer(IPath path) {
+ if (path.isAbsolute()) {
+ if (this.project.getFullPath().equals(path)) {
+ return this.project;
+ } else {
+ return this.project.getWorkspace().getRoot().getFolder(path);
+ }
+ }
+ return this.project.getFolder(path);
+ }
+
+ /**
+ * Returns the file for a path.
+ */
+ private IFile getFile(IPath path) {
+ if (path.isAbsolute()) {
+ return this.project.getWorkspace().getRoot().getFile(path);
+ }
+ return this.project.getFile(path);
+ }
+
+ /**
+ * Returns the path for the output package fragment root.
+ */
+ IPath getOutputPath() {
+ return this.outputPath;
+ }
+
+ /**
+ * Returns the path in the output folder for the given type.
+ */
+ private IPath getPathForBinary(IType type) {
+ return getOutputPath().append(type.getName().replace('.', '/') + ".class");
+ }
+
+ /**
+ * Returns the container at the given path, creating it and any parent folders if necessary.
+ */
+ IContainer makeContainersIfNecessary(IPath path) {
+ try {
+ IContainer container = getContainer(path);
+ if (container.exists())
+ return container;
+ Assert.isTrue(container instanceof IFolder);
+ makeContainersIfNecessary(path.removeLastSegments(1));
+ ((IFolder) container).create(true, true, null);
+ return container;
+ } catch (CoreException e) {
+ throw this.dc.internalException(e);
+ }
+ }
+
+ /**
+ * @see BinaryOutput
+ */
+ public void scrubOutput() {
+
+ IJavaProject projectElement = JavaCore.create(this.project);
+ IClasspathEntry[] entries;
+ try {
+ entries = projectElement.getResolvedClasspath(true);
+ } catch (JavaModelException e) {
+ throw this.dc.internalException(e);
+ }
+
+ /* detect whether the binary ouput coincidates with source folder */
+ boolean flushAllOutput = false;
+ for (int i = 0, length = entries.length; i < length; i++) {
+ IClasspathEntry entry = entries[i];
+ if ((entry.getEntryKind() == IClasspathEntry.CPE_SOURCE)) {
+ if (!this.outputPath.equals(entry.getPath())) {
+ flushAllOutput = true; // output is distinct - flush all
+ break;
+ }
+ }
+ }
+ if (flushAllOutput) {
+ deleteAllInContainer(getContainer(this.outputPath));
+ } else {
+ deleteClassesInContainer(getContainer(this.outputPath));
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ProjectResourceCopier.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ProjectResourceCopier.java
new file mode 100644
index 0000000000..0d2c48adfb
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ProjectResourceCopier.java
@@ -0,0 +1,264 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.core.*;
+
+import java.util.*;
+
+public class ProjectResourceCopier implements IResourceVisitor {
+
+ /* internal state */
+ private final IJavaProject project;
+ private final JavaDevelopmentContextImpl devContext;
+ private final IProject projectRsc;
+ private final IWorkspace workspace;
+ private final IWorkspaceRoot root;
+ private final IPath outputLocation;
+ private final BuildNotifier notifier;
+ private final float totalAvailableProgress;
+ private IResource[] sourceFolders;
+ public ProjectResourceCopier(
+ IJavaProject project,
+ JavaDevelopmentContextImpl devContext,
+ BuildNotifier notifier,
+ float totalAvailableProgress) {
+
+ this.project = project;
+ this.devContext = devContext;
+ this.projectRsc = this.project.getProject();
+ this.workspace = this.projectRsc.getWorkspace();
+ this.root = this.workspace.getRoot();
+ try {
+ this.outputLocation = this.project.getOutputLocation();
+ IClasspathEntry[] entries = this.project.getResolvedClasspath(true);
+ this.sourceFolders = new IResource[entries.length];
+ for (int i = 0, length = entries.length; i < length; i++) {
+ IClasspathEntry entry = entries[i];
+ if ((entry.getEntryKind() == IClasspathEntry.CPE_SOURCE)) {
+ this.sourceFolders[i] = this.root.findMember(entry.getPath());
+ }
+ }
+ } catch (JavaModelException e) {
+ throw new ImageBuilderInternalException(e);
+ }
+ this.notifier = notifier;
+ this.totalAvailableProgress = totalAvailableProgress;
+ }
+
+ public void copyAllResourcesOnClasspath() {
+
+ boolean hasNotified = false;
+ try {
+ for (int i = 0, length = this.sourceFolders.length; i < length; i++) {
+ if (sourceFolders[i] != null) {
+ if (this.outputLocation.equals(this.sourceFolders[i].getFullPath()))
+ continue; // do nothing if output is same as source folder
+ if (!hasNotified) {
+ hasNotified = true;
+ if (notifier != null)
+ notifier.subTask("Copying all resources on the classpath");
+ }
+ this.sourceFolders[i].accept(this);
+ }
+ if (notifier != null)
+ notifier.updateProgressDelta(totalAvailableProgress / length);
+ }
+ } catch (CoreException e) {
+ throw this.devContext.internalException(e);
+ }
+ }
+
+ /**
+ * Copy a given resource into the output folder (if non java source file)
+ */
+ private boolean copyToOutput(IResource resource) {
+
+ if (!resource.exists())
+ return false;
+ IPath sourceFolderPath = getSourceFolderPath(resource);
+ IPath resourcePath = resource.getFullPath();
+
+ switch (resource.getType()) {
+ case IResource.FILE :
+ if (sourceFolderPath == null)
+ return false; // resource is not inside the classpath
+ if (!"java".equals(resource.getFileExtension())) { // ignore source files
+
+ IFile currentFile = (IFile) resource;
+ IPath pathSuffix =
+ resourcePath.removeFirstSegments(sourceFolderPath.segmentCount());
+ IPath targetPath = this.outputLocation.append(pathSuffix);
+ try {
+ IFile previousFile = this.root.getFile(targetPath);
+ if (previousFile.exists())
+ previousFile.delete(true, false, null);
+ currentFile.copy(targetPath, true, null);
+ } catch (CoreException e) {
+ throw this.devContext.internalException(e);
+ }
+ }
+ break;
+ case IResource.PROJECT :
+ if (resourcePath.equals(this.outputLocation))
+ return false; // do not visit the binary output
+ if (resourcePath.equals(sourceFolderPath))
+ return true; // skip source folder itself
+ break;
+ case IResource.FOLDER :
+ if (resourcePath.equals(this.outputLocation))
+ return false; // do not visit the binary output
+ if (sourceFolderPath == null)
+ return true;
+ // continue inside folder (source folder might be one of its children)
+ if (resourcePath.equals(sourceFolderPath))
+ return true; // skip source folder itself
+ IContainer currentFolder = (IFolder) resource;
+
+ IPath pathSuffix =
+ resourcePath.removeFirstSegments(sourceFolderPath.segmentCount());
+ IPath targetPath = this.outputLocation.append(pathSuffix);
+ IFolder targetFolder = this.root.getFolder(targetPath);
+ if (!targetFolder.exists()) {
+ try {
+ targetFolder.create(true, true, null);
+ } catch (CoreException e) {
+ throw this.devContext.internalException(e);
+ }
+ }
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * Delete the corresponding resource from the output folder
+ */
+ private boolean deleteResourceCopyFromOutput(IResource resource) {
+
+ IPath sourceFolderPath = getSourceFolderPath(resource);
+ if (sourceFolderPath == null)
+ return false; // resource is not inside the classpath
+
+ IPath resourcePath = resource.getFullPath();
+ if (resourcePath.equals(sourceFolderPath))
+ return true; // skip source folder itself
+ if (resourcePath.equals(this.outputLocation))
+ return false; // do not visit the binary output
+ IPath pathSuffix, targetPath;
+
+ switch (resource.getType()) {
+ case IResource.FILE :
+ if (!"java".equals(resource.getFileExtension())) { // ignore source files
+
+ IFile currentFile = (IFile) resource;
+ pathSuffix = resourcePath.removeFirstSegments(sourceFolderPath.segmentCount());
+ targetPath = this.outputLocation.append(pathSuffix);
+ try {
+ IFile previousFile = this.root.getFile(targetPath);
+ if (previousFile.exists())
+ previousFile.delete(true, true, null);
+ } catch (CoreException e) {
+ throw this.devContext.internalException(e);
+ }
+ }
+ break;
+ case IResource.FOLDER :
+ IContainer currentFolder = (IFolder) resource;
+ pathSuffix = resourcePath.removeFirstSegments(sourceFolderPath.segmentCount());
+ targetPath = this.outputLocation.append(pathSuffix);
+ IFolder targetFolder = this.root.getFolder(targetPath);
+ if (targetFolder.exists()) {
+ try {
+ targetFolder.delete(true, false, null);
+ } catch (CoreException e) {
+ throw this.devContext.internalException(e);
+ }
+ }
+ break;
+ }
+ return false;
+ }
+
+ /**
+ * Answer the path of the classpath source folder entry enclosing a given resource (if the resource is on the classpath)
+ */
+ private IPath getSourceFolderPath(IResource resource) {
+
+ IPath resourcePath = resource.getFullPath();
+ for (int i = 0, length = this.sourceFolders.length; i < length; i++) {
+ if (this.sourceFolders[i] != null) {
+ IPath sourceFolderPath = this.sourceFolders[i].getFullPath();
+ if (sourceFolderPath.isPrefixOf(resourcePath)) {
+ return sourceFolderPath;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Traverse an existing delta and update the affected resources in the binary output
+ */
+ public void updateAffectedResources(IResourceDelta delta) {
+
+ // check that there is anything to do (if any source folder is not coincidating with the binary output)
+ boolean hasNotified = false;
+ for (int i = 0, length = this.sourceFolders.length; i < length; i++) {
+ if (sourceFolders[i] != null) {
+ if (this.outputLocation.equals(this.sourceFolders[i].getFullPath()))
+ continue; // do nothing if output is same as source folder
+ if (!hasNotified) {
+ hasNotified = true;
+ if (notifier != null)
+ notifier.subTask("Updating resources on the classpath");
+ }
+ }
+ }
+ if (hasNotified)
+ updateAffectedResources0(delta);
+ }
+
+ /**
+ * Traverse an existing delta and update the affected resources in the binary output
+ */
+ private void updateAffectedResources0(IResourceDelta delta) {
+
+ IResource affectedResource = delta.getResource();
+ boolean processChildren = true;
+ switch (delta.getKind()) {
+ case IResourceDelta.ADDED :
+ case IResourceDelta.CHANGED :
+ processChildren = copyToOutput(affectedResource);
+ break;
+ case IResourceDelta.REMOVED :
+ processChildren = deleteResourceCopyFromOutput(affectedResource);
+ }
+ if (processChildren) {
+ IResourceDelta[] children = delta.getAffectedChildren();
+ for (int i = 0; i < children.length; i++) {
+ updateAffectedResources0(children[i]);
+ }
+ }
+ }
+
+ /** Visits the given resource.
+ *
+ * @param resource the resource to visit
+ * @return <code>true</code> if the resource's members should
+ * be visited; <code>false</code> if they should be skipped
+ * @exception CoreException if the visit fails for some reason.
+ */
+ public boolean visit(IResource resource) throws CoreException {
+
+ return copyToOutput(resource);
+ // binary output should be empty, just copy current resources
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ReportCardImpl.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ReportCardImpl.java
new file mode 100644
index 0000000000..fb3d175c88
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ReportCardImpl.java
@@ -0,0 +1,222 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IPath;
+
+import org.eclipse.jdt.internal.core.builder.*;
+
+import java.util.*;
+
+public class ReportCardImpl implements IReportCard {
+ private StateImpl fState;
+ private ImageContextImpl fImageContext;
+ public ReportCardImpl(StateImpl state, IImageContext context) {
+ fState = state;
+ fImageContext = (ImageContextImpl) context;
+ }
+
+ public IPath[] changedPaths(IReportCard previous) {
+ Hashtable myProblemTable = problemTableFrom(getLeafProblemsFor(null));
+ Hashtable prevProblemTable =
+ problemTableFrom(previous.getLeafProblemsFor(null));
+ Hashtable changed = new Hashtable();
+
+ /* do for all problems in the new table */
+ for (Enumeration e = myProblemTable.keys(); e.hasMoreElements();) {
+ IPath path = (IPath) e.nextElement();
+ Hashtable myProblems = (Hashtable) myProblemTable.get(path);
+ Hashtable prevProblems = (Hashtable) prevProblemTable.remove(path);
+ if (prevProblems == null || !setCompare(myProblems, prevProblems)) {
+ changed.put(path, path);
+ }
+ }
+
+ /* pick up all problems that are only in the old table */
+ for (Enumeration e = prevProblemTable.keys(); e.hasMoreElements();) {
+ IPath path = (IPath) e.nextElement();
+ changed.put(path, path);
+ }
+
+ /* convert results to array */
+ IPath[] results = new IPath[changed.size()];
+ int i = 0;
+ for (Enumeration e = changed.keys(); e.hasMoreElements(); i++) {
+ results[i] = (IPath) e.nextElement();
+ }
+ return results;
+ }
+
+ /**
+ * Returns all the problems for this state
+ */
+ private void getAllProblems(Vector results) {
+ /* iterate through problems in the problem table */
+ for (Enumeration e = fState.getProblemReporter().getAllProblems();
+ e.hasMoreElements();
+ ) {
+ results.addElement(e.nextElement());
+ }
+
+ /* go through all problems attached to the image itself */
+ for (Enumeration e = fState.getProblems(); e.hasMoreElements();) {
+ results.addElement(e.nextElement());
+ }
+ }
+
+ public IImageContext getImageContext() {
+ return fImageContext;
+ }
+
+ public IProblemDetail[] getLeafProblemsFor(IPath path) {
+ Vector vResults = new Vector();
+
+ /* if we want all problems */
+ if (path == null) {
+ getAllProblems(vResults);
+ } else {
+ getProblemsForPath(path, vResults);
+ }
+ /* convert to array */
+ IProblemDetail[] results = new IProblemDetail[vResults.size()];
+ vResults.copyInto(results);
+ return results;
+ }
+
+ public IPath[] getProblemPaths(IPath path) {
+ Hashtable set = new Hashtable();
+
+ /* build set of all element IDs */
+ IProblemDetail[] problems = getLeafProblemsFor(path);
+ for (int i = 0; i < problems.length; i++) {
+ IPath problemPath =
+ ((ProblemDetailImpl) problems[i]).getSourceEntry().getPath();
+ set.put(problemPath, problemPath);
+ }
+
+ /* convert set to array */
+ IPath[] results = new IPath[set.size()];
+ int i = 0;
+ for (Enumeration e = set.keys(); e.hasMoreElements();) {
+ results[i++] = (IPath) e.nextElement();
+ }
+ return results;
+ }
+
+ private void getProblemsForPath(IPath path, Vector vResults) {
+ for (Enumeration e = fState.getProblemReporter().getProblemKeys();
+ e.hasMoreElements();
+ ) {
+ SourceEntry sEntry = (SourceEntry) e.nextElement();
+ IPath sEntryPath = sEntry.getPath();
+ if (path.isPrefixOf(sEntryPath)) {
+ String extension = sEntryPath.getFileExtension();
+ // test most frequent cases first
+ if (extension != null
+ && (extension.toLowerCase().equals("java")
+ || extension.toLowerCase().equals("class"))) {
+ getProblemsForSourceEntry(sEntry, vResults);
+ } else {
+ if (fState.isZipElement(sEntryPath)) {
+ getProblemsForZip(sEntryPath, vResults);
+ }
+ }
+ }
+ }
+ }
+
+ private void getProblemsForSourceEntry(SourceEntry sEntry, Vector results) {
+ IProblemReporter pbReporter = fState.getProblemReporter();
+ if (pbReporter.hasProblems(sEntry)) {
+ // Only check image context if there are really problems with this element
+ IPackage pkg =
+ fState.getPathMap().packageHandleFromPath(
+ sEntry.getPath().removeLastSegments(1));
+ if (fImageContext == null || fImageContext.containsPackage(pkg)) {
+ for (Enumeration e = pbReporter.getProblems(sEntry); e.hasMoreElements();) {
+ results.addElement(e.nextElement());
+ }
+ }
+ }
+ }
+
+ protected void getProblemsForZip(IPath zipPath, Vector results) {
+ // avoid iterating over all entries in the zip file
+ IProblemReporter pbReporter = fState.getProblemReporter();
+ for (Enumeration e = pbReporter.getAllProblems(); e.hasMoreElements();) {
+ ProblemDetailImpl problem = (ProblemDetailImpl) e.nextElement();
+ SourceEntry sEntry = problem.getSourceEntry();
+ if (sEntry.fZipEntryFileName != null && sEntry.getPath().equals(zipPath)) {
+ // Check image context.
+ if (fImageContext == null
+ || fImageContext.containsPackage(fState.packageFromSourceEntry(sEntry))) {
+ results.addElement(problem);
+ }
+ }
+ }
+ }
+
+ public IState getState() {
+ return fState;
+ }
+
+ public boolean hasLeafProblems(IPath path) {
+ return getLeafProblemsFor(path).length > 0;
+ }
+
+ /**
+ * Returns a dictionary of problems keyed by their path.
+ * Each entry in the dictionary is a set of problems. The set is implemented as a
+ * hashtable with identical keys and values. Problems with no path are not
+ * included in the result.
+ */
+ private Hashtable problemTableFrom(IProblemDetail[] problems) {
+ Hashtable table = new Hashtable(25);
+ for (int i = 0; i < problems.length; i++) {
+ IPath path = ((ProblemDetailImpl) problems[i]).getPath();
+ if (path != null) {
+ Hashtable entry = (Hashtable) table.get(path);
+ if (entry == null) {
+ entry = new Hashtable(10);
+ table.put(path, entry);
+ }
+ entry.put(problems[i], problems[i]);
+ }
+ }
+ return table;
+ }
+
+ /**
+ * Returns true if the two sets of problems are the same, false otherwise.
+ * Don't use ProblemDetail.equals() because it doesn't consider source
+ * positions or severity
+ */
+ private boolean setCompare(Hashtable myProblems, Hashtable prevProblems) {
+ if (myProblems.size() != prevProblems.size()) {
+ return false;
+ }
+
+ /* iterate through both tables */
+ for (Enumeration e = myProblems.keys(); e.hasMoreElements();) {
+ ProblemDetailImpl a = (ProblemDetailImpl) myProblems.get(e.nextElement());
+ ProblemDetailImpl b = (ProblemDetailImpl) prevProblems.get(a);
+ if (b == null) {
+ /* problem is not in prevProblems */
+ return false;
+ }
+ }
+ for (Enumeration e = prevProblems.keys(); e.hasMoreElements();) {
+ ProblemDetailImpl a = (ProblemDetailImpl) prevProblems.get(e.nextElement());
+ ProblemDetailImpl b = (ProblemDetailImpl) myProblems.get(a);
+ if (b == null) {
+ /* problem is not in myProblems */
+ return false;
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/SourceElementTable.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/SourceElementTable.java
new file mode 100644
index 0000000000..0f710da0c0
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/SourceElementTable.java
@@ -0,0 +1,139 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.Assert;
+import org.eclipse.jdt.internal.core.builder.*;
+import org.eclipse.jdt.internal.core.util.LookupTable;
+
+import java.util.Enumeration;
+
+/**
+ * The source element table contains all elements of the workspace that are
+ * visible to the image builder. It is implemented as nested hashtables. The
+ * first hashtable is keyed by non state-specific package handle. The second
+ * table is keyed by name of source file name (e.g., "Object.class", or "Foo.java"),
+ * and has SourceEntry objects as values.
+ */
+class SourceElementTable extends StateTables {
+ LookupTable fPackageTable = new LookupTable(11);
+ /**
+ * Returns true if the package is in the table, false otherwise.
+ */
+ boolean containsPackage(IPackage pkg) {
+ return fPackageTable.containsKey(pkg);
+ }
+
+ /**
+ * Creates a copy of the table.
+ */
+ SourceElementTable copy() {
+ try {
+ SourceElementTable copy = (SourceElementTable) super.clone();
+ copy.fPackageTable = new LookupTable(fPackageTable.size() * 2 + 1);
+ for (Enumeration e = fPackageTable.keys(); e.hasMoreElements();) {
+ IPackage pkg = (IPackage) e.nextElement();
+ LookupTable pkgTable = (LookupTable) fPackageTable.get(pkg);
+ copy.fPackageTable.put(pkg, pkgTable.clone());
+ }
+ return copy;
+ } catch (CloneNotSupportedException e) {
+ // Should not happen.
+ throw new Error();
+ }
+ }
+
+ /**
+ * Returns the table for a package. Returns null if no such table exists.
+ */
+ LookupTable getPackageTable(IPackage pkg) {
+ return (LookupTable) fPackageTable.get(pkg);
+ }
+
+ /**
+ * Returns the source entries in the given package.
+ * Returns null if no entries exist for that package.
+ */
+ SourceEntry[] getSourceEntries(IPackage pkg) {
+ LookupTable pkgTable = getPackageTable(pkg);
+ if (pkgTable == null) {
+ return null;
+ }
+ int i = 0;
+ SourceEntry[] results = new SourceEntry[pkgTable.size()];
+ for (Enumeration e = pkgTable.elements(); e.hasMoreElements();) {
+ results[i++] = (SourceEntry) e.nextElement();
+ }
+ return results;
+ }
+
+ /**
+ * Returns the source entry for a package and file name. Returns null if
+ * no entry exists.
+ */
+ SourceEntry getSourceEntry(IPackage pkg, String fileName) {
+ /* make sure package is not state specific */
+ Assert.isTrue(!pkg.isStateSpecific());
+ LookupTable pkgTable = getPackageTable(pkg);
+ if (pkgTable != null) {
+ Assert.isTrue(fileName.indexOf('.') != -1, "name must have extension");
+ return (SourceEntry) pkgTable.get(fileName);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the number of packages in the table.
+ */
+ int numPackages() {
+ return fPackageTable.size();
+ }
+
+ /**
+ * Adds the table for a package to the table.
+ */
+ void putPackageTable(IPackage pkg, LookupTable pkgTable) {
+ fPackageTable.put(pkg, pkgTable);
+ }
+
+ /**
+ * Adds one source entry in the source element table
+ */
+ public void putSourceEntry(IPackage pkg, SourceEntry sourceEntry) {
+ LookupTable pkgTable = getPackageTable(pkg);
+ if (pkgTable == null) {
+ putPackageTable(pkg, pkgTable = new LookupTable());
+ }
+ pkgTable.put(sourceEntry.getFileName(), sourceEntry);
+ }
+
+ /**
+ * Removes the source entries for a package.
+ */
+ void removePackage(IPackage pkg) {
+ fPackageTable.remove(pkg);
+ }
+
+ /**
+ * Removes the source entry for a source element. Returns the
+ * removed element or null if it didn't exist
+ */
+ SourceEntry removeSourceEntry(IPackage pkg, String fileName) {
+ LookupTable pkgTable = getPackageTable(pkg);
+ if (pkgTable != null) {
+ return (SourceEntry) pkgTable.remove(fileName);
+ }
+ return null;
+ }
+
+ /**
+ * Returns a String that represents the value of this object.
+ * @return a string representation of the receiver
+ */
+ public String toString() {
+ return "SourceElementTable(" + fPackageTable + ")";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/SourceEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/SourceEntry.java
new file mode 100644
index 0000000000..8ae8019df6
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/SourceEntry.java
@@ -0,0 +1,156 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.internal.core.Util;
+
+import java.io.File;
+
+/**
+ * This class encapsulates a reference to an element in the workspace. This
+ * element may be a java source file, a class file, or a zip entry.
+ */
+public class SourceEntry extends StateTables {
+ IPath fPath;
+ String fZipEntryPath;
+ String fZipEntryFileName;
+ /**
+ * Creates a new SourceEntry.
+ */
+ public SourceEntry(IPath path, String zipEntryPath, String zipEntryFileName) {
+ fPath = path;
+ fZipEntryPath = zipEntryPath;
+ fZipEntryFileName = zipEntryFileName;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof SourceEntry))
+ return false;
+ SourceEntry entry = (SourceEntry) o;
+ if (!this.fPath.equals(entry.fPath))
+ return false;
+ if (!Util.equalOrNull(fZipEntryPath, entry.fZipEntryPath))
+ return false;
+ if (!Util.equalOrNull(fZipEntryFileName, entry.fZipEntryFileName))
+ return false;
+ return true;
+ }
+
+ public static SourceEntry fromPathWithZipEntryName(String pathWithZipEntryName) {
+ // Convert separators back. See getPathWithZipEntryName().
+ pathWithZipEntryName = pathWithZipEntryName.replace(File.separatorChar, '/');
+ int i = pathWithZipEntryName.lastIndexOf('#');
+ if (i == -1) {
+ return new SourceEntry(new Path(pathWithZipEntryName), null, null);
+ } else {
+ Path path = new Path(pathWithZipEntryName.substring(0, i));
+ String zipEntryName = pathWithZipEntryName.substring(i + 1);
+ String zipEntryPath = null, zipEntryFileName = null;
+ if (zipEntryName != null) {
+ int pos = zipEntryName.lastIndexOf('/');
+ if (pos != -1) {
+ zipEntryPath = zipEntryName.substring(0, pos);
+ zipEntryFileName = zipEntryName.substring(pos + 1);
+ } else {
+ zipEntryPath = null;
+ zipEntryFileName = zipEntryName;
+ }
+ }
+ return new SourceEntry(path, zipEntryPath, zipEntryFileName);
+ }
+ }
+
+ /**
+ * Returns the 'file name'.
+ */
+ public String getFileName() {
+ if (fZipEntryFileName != null) {
+ return fZipEntryFileName;
+ }
+ return fPath.lastSegment();
+ }
+
+ /**
+ * Returns the 'file name' without the file extension.
+ */
+ public String getName() {
+ String name = getFileName();
+ int lastDot = name.lastIndexOf('.');
+ if (lastDot != -1)
+ name = name.substring(0, lastDot);
+ return name;
+ }
+
+ public IPath getPath() {
+ return fPath;
+ }
+
+ public String getPathWithZipEntryName() {
+ String s =
+ fZipEntryFileName == null
+ ? fPath.toString()
+ : fPath.toString() + '#' + this.getZipEntryName();
+ // Convert separators.
+ // See 1FVQGE2: ITPJCORE:ALL - Class file has workbench relative source file attribute
+ // and 1FW1LHM: LFCOM:ALL - Source file names and dependency info
+ return s.replace('/', File.separatorChar);
+ }
+
+ public String getZipEntryName() {
+ return fZipEntryPath == null
+ ? fZipEntryFileName
+ : fZipEntryPath + "/" + fZipEntryFileName;
+ }
+
+ public int hashCode() {
+ int code = fPath.hashCode();
+ if (fZipEntryPath != null) {
+ code = code * 17 + fZipEntryPath.hashCode();
+ }
+ if (fZipEntryFileName != null) {
+ code = code * 17 + fZipEntryFileName.hashCode();
+ }
+ return code;
+ }
+
+ /**
+ * Returns true if the source entry comes from a binary file, otherwise
+ * returns false.
+ */
+ public boolean isBinary() {
+ if (fZipEntryFileName != null) {
+ return fZipEntryFileName.endsWith(".class");
+ }
+ String extension = fPath.getFileExtension();
+ return extension != null && extension.equalsIgnoreCase("class");
+ }
+
+ /**
+ * Returns true if the source entry comes from a compilation unit, otherwise
+ * returns false.
+ */
+ public boolean isSource() {
+ if (fZipEntryFileName != null) {
+ return fZipEntryFileName.endsWith(".java");
+ }
+ String extension = fPath.getFileExtension();
+ return extension != null && extension.equalsIgnoreCase("java");
+ }
+
+ /**
+ * Returns a String that represents the value of this object.
+ * @return a string representation of the receiver
+ */
+ public String toString() {
+ return fZipEntryFileName == null
+ ? fPath.toString()
+ : fPath.toString() + ", entry: " + this.getZipEntryName();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/SourceFragmentImpl.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/SourceFragmentImpl.java
new file mode 100644
index 0000000000..6fb1d29cf4
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/SourceFragmentImpl.java
@@ -0,0 +1,79 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IPath;
+
+import org.eclipse.jdt.internal.core.builder.ISourceFragment;
+import org.eclipse.jdt.internal.core.Util;
+
+public class SourceFragmentImpl implements ISourceFragment {
+ private int fStartPos, fEndPos;
+ private IPath fPath;
+ private String fZipEntryName;
+ public SourceFragmentImpl(int start, int end, IPath path) {
+ fStartPos = start;
+ fEndPos = end;
+ fPath = path;
+ }
+
+ public SourceFragmentImpl(int start, int end, SourceEntry sourceEntry) {
+ fStartPos = start;
+ fEndPos = end;
+ fPath = sourceEntry.getPath();
+ fZipEntryName = sourceEntry.getZipEntryName();
+ }
+
+ public SourceFragmentImpl(SourceEntry sourceEntry) {
+ this(-1, -1, sourceEntry);
+ }
+
+ /**
+ * Compares this object against the specified object.
+ * Returns true if the objects are the same.
+ */
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof SourceFragmentImpl))
+ return false;
+
+ SourceFragmentImpl frag = (SourceFragmentImpl) o;
+ if (this.fStartPos != frag.fStartPos || this.fEndPos != frag.fEndPos)
+ return false;
+ if (!Util.equalOrNull(this.fPath, frag.fPath))
+ return false;
+ return Util.equalOrNull(this.fZipEntryName, frag.fZipEntryName);
+ }
+
+ public IPath getPath() {
+ return fPath;
+ }
+
+ /**
+ * getZipEntryName method comment.
+ */
+ public String getZipEntryName() {
+ return fZipEntryName;
+ }
+
+ /**
+ * Returns a consistent hashcode for this source fragment
+ */
+ public int hashCode() {
+ return fStartPos + fEndPos + fPath.hashCode() + fZipEntryName.hashCode();
+ }
+
+ /**
+ * Returns a string representation of the receiver.
+ */
+ public String toString() {
+ return "SourceFragmentImpl("
+ + fPath
+ + (fZipEntryName == null ? "" : " : " + fZipEntryName)
+ + ")";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateImpl.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateImpl.java
new file mode 100644
index 0000000000..214bfabf1f
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateImpl.java
@@ -0,0 +1,2077 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IPath;
+
+import org.eclipse.core.resources.*;
+
+import org.eclipse.core.resources.*;
+import org.eclipse.jdt.internal.core.builder.*;
+
+import java.io.*;
+import java.util.*;
+import java.util.zip.*;
+
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.core.IClassFile;
+
+import org.eclipse.jdt.internal.core.util.*;
+import org.eclipse.jdt.internal.compiler.classfmt.*;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.core.runtime.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+import org.eclipse.jdt.internal.core.lookup.*;
+import org.eclipse.jdt.internal.core.*;
+import org.eclipse.jdt.internal.compiler.ClassFile;
+
+/**
+ * The concrete representation of a built state.
+ *
+ * @see IState
+ */
+public class StateImpl implements IState {
+
+ /**
+ * The development context corresponding to this state
+ */
+ private JavaDevelopmentContextImpl fDevelopmentContext;
+
+ /**
+ * The build context. Only packages in the build context
+ * are actually built
+ */
+ private IImageContext fBuildContext;
+
+ /**
+ * The project built by this state.
+ */
+ private IProject fProject;
+
+ /**
+ * The name of the project built by this state.
+ */
+ private String fProjectName;
+
+ /**
+ * The paths of the package fragment roots in the class path.
+ */
+ private IPackageFragmentRoot[] fPackageFragmentRootsInClassPath;
+
+ /**
+ * The binary output.
+ */
+ private BinaryOutput fBinaryOutput;
+
+ /**
+ * The package map. A hashtable of package handles to PackageMapEntry objects.
+ * The package map entries store the collection of package fragments that
+ * make up the given builder package.
+ */
+ private PackageMap fPackageMap;
+
+ /**
+ * The path map. A table that maps from paths to package handles. This
+ * is essentially a reverse index of the package map. Note that this
+ * table can always be regenerated from the package map, so it does
+ * not need to be serialized or incrementally updated.
+ */
+ private PathMap fPathMap;
+
+ /**
+ * The source element table. This table holds a source fragment for
+ * all workspace elements.
+ */
+ private SourceElementTable fSourceElementTable;
+
+ /**
+ * The principal structure table. A table of type handles to TypeStructureEntry objects.
+ * This is where build results are stored. This table only contains types that
+ * have been compiled.
+ */
+ private Hashtable fPrincipalStructureTable;
+
+ /**
+ * Table of IPackage to TypeStructureEntry[] for all types in package (lazy).
+ */
+ private Hashtable fPrincipalStructureByPackageTable;
+
+ /**
+ * The problem reporter. All problems for this state are stored in this problem
+ * reporter.
+ */
+ private IProblemReporter fProblemReporter;
+
+ /**
+ * The graph of source element dependencies, used for
+ * incremental compilation
+ */
+ private DependencyGraph fGraph = null;
+
+ /**
+ * The table of subtypes. Maps from IType to TypeStructureEntry[]. Absence in table implies no subtypes.
+ */
+ private Hashtable fSubtypesTable;
+ private IImageContext fSubtypesTableImageContext;
+
+ /**
+ * The image corresponding to this state
+ */
+ private IImage fImage;
+
+ /**
+ * The compiler options that were used to build this state.
+ */
+ private ConfigurableOption[] fCompilerOptions;
+
+ /**
+ * Unique state number
+ */
+ private int fStateNumber;
+
+ /**
+ * Fingerprint bytes
+ */
+ private byte[] fFingerprint;
+
+ /* primitive type handles */
+ final IType fVoidType;
+ final IType fIntType;
+ final IType fByteType;
+ final IType fCharType;
+ final IType fDoubleType;
+ final IType fFloatType;
+ final IType fLongType;
+ final IType fShortType;
+ final IType fBooleanType;
+
+ /**
+ * Counter for unique state numbers (not the fingerprint).
+ */
+ private static int fgStateCounter = 0;
+
+ /**
+ * Namespace flag indicating CU has parse error.
+ * Must not conflict with modifiers or other flags in IConstants.
+ */
+ private static final int F_HAS_PARSE_ERROR = 0x10000000;
+
+ /**
+ * Name for namespace node representing unknown dependencies.
+ */
+ private static final String UNKNOWN_DEPENDENCIES = "$UNKNOWN_DEPENDENCIES$";
+
+ /**
+ * Random number generator, used for generating fingerprints.
+ */
+ private static final Random fgRandom = new Random();
+
+ /**
+ * State constructor comment. The build context, fingerprint, and internal tables
+ * are not instantiated and must be filled in before use.
+ */
+ protected StateImpl(JavaDevelopmentContextImpl dc, IProject project) {
+ fDevelopmentContext = dc;
+ fProject = project;
+ fStateNumber = fgStateCounter++;
+ fImage = new ImageImplSWH(this, (ImageImpl) dc.getImage());
+ fVoidType = new PrimitiveTypeHandleImplSWH(this, dc.fVoidType);
+ fIntType = new PrimitiveTypeHandleImplSWH(this, dc.fIntType);
+ fByteType = new PrimitiveTypeHandleImplSWH(this, dc.fByteType);
+ fCharType = new PrimitiveTypeHandleImplSWH(this, dc.fCharType);
+ fDoubleType = new PrimitiveTypeHandleImplSWH(this, dc.fDoubleType);
+ fFloatType = new PrimitiveTypeHandleImplSWH(this, dc.fFloatType);
+ fLongType = new PrimitiveTypeHandleImplSWH(this, dc.fLongType);
+ fShortType = new PrimitiveTypeHandleImplSWH(this, dc.fShortType);
+ fBooleanType = new PrimitiveTypeHandleImplSWH(this, dc.fBooleanType);
+ fFingerprint = generateFingerprint();
+ }
+
+ /**
+ * State constructor comment.
+ */
+ protected StateImpl(
+ JavaDevelopmentContextImpl dc,
+ IProject project,
+ IImageContext buildContext) {
+ this(dc, project);
+ fBuildContext = buildContext;
+
+ /* state tables */
+ fPackageMap = new PackageMap();
+ fSourceElementTable = new SourceElementTable();
+ fPrincipalStructureTable = new Hashtable();
+ fProblemReporter = new ProblemTable();
+ fGraph = new DependencyGraph();
+ }
+
+ /**
+ * @see IState
+ */
+ public IImageBuilder applySourceDelta(
+ IProject newProject,
+ IResourceDelta projectDelta,
+ IImageContext buildContext) {
+ /* create and return builder */
+ IncrementalImageBuilder builder =
+ new IncrementalImageBuilder(this, newProject, buildContext);
+ builder.applySourceDelta(projectDelta);
+ return builder;
+ }
+
+ /**
+ * Creates state tables that are dependent only on the workspace, and not
+ * on build results. This includes the package map, source element table,
+ * and the namespace table.
+ */
+ protected void buildInitialPackageMap() {
+ fPackageMap = new PackageMap();
+
+ /* do for each package fragment root in (classpath INTERSECT workspace) */
+ try {
+ IPackageFragmentRoot[] roots = getPackageFragmentRootsInClassPath();
+ IPath outputLocation = getJavaProject().getOutputLocation();
+ for (int i = 0; i < roots.length; ++i) {
+ IPackageFragmentRoot root = roots[i];
+ if (root.exists()) {
+ ((PackageFragmentRoot) root).refreshChildren();
+ IJavaElement[] frags = root.getChildren();
+ for (int j = 0; j < frags.length; ++j) {
+ IPackageFragment frag = (IPackageFragment) frags[j];
+ if (frag.exists()) {
+ String pkgName = frag.getElementName();
+ IPackage pkg =
+ pkgName.length() == 0
+ ? defaultPackageForProject()
+ : fDevelopmentContext.getImage().getPackageHandle(pkgName, false);
+ IPath path =
+ root.isArchive() ? root.getPath() : frag.getUnderlyingResource().getFullPath();
+ fPackageMap.putFragment(pkg, path);
+ }
+ }
+ }
+ }
+ } catch (JavaModelException e) {
+ throw internalException(e);
+ }
+
+ /* build the reverse index -- the path map */
+ fPathMap = new PathMap(fPackageMap);
+ }
+
+ protected void buildPrincipalStructureByPackageTable() {
+ IPackage[] pkgs =
+ fBuildContext != null
+ ? fBuildContext.getPackages()
+ : fPackageMap.getAllPackagesAsArray();
+ Hashtable principalStructureByPackageTable = new Hashtable(pkgs.length * 2 + 1);
+ for (int i = 0; i < pkgs.length; ++i) {
+ principalStructureByPackageTable.put(pkgs[i], new Vector(20));
+ }
+ for (Enumeration e = fPrincipalStructureTable.elements();
+ e.hasMoreElements();
+ ) {
+ TypeStructureEntry tsEntry = (TypeStructureEntry) e.nextElement();
+ IPackage pkg = tsEntry.getType().getPackage();
+ Vector v = (Vector) principalStructureByPackageTable.get(pkg);
+ /* Be careful to only gather types for packages in the given list.
+ Other packages may only be partially built. */
+ if (v != null) {
+ v.addElement(tsEntry);
+ }
+ }
+ /* Convert vectors to arrays */
+ for (Enumeration e = principalStructureByPackageTable.keys();
+ e.hasMoreElements();
+ ) {
+ IPackage pkg = (IPackage) e.nextElement();
+ Vector v = (Vector) principalStructureByPackageTable.get(pkg);
+ TypeStructureEntry[] tsEntries = new TypeStructureEntry[v.size()];
+ v.copyInto(tsEntries);
+ principalStructureByPackageTable.put(pkg, tsEntries);
+ }
+ setPrincipalStructureByPackageTable(principalStructureByPackageTable);
+ }
+
+ /**
+ * Returns the type structure entry for the given type handle. Performs lazy
+ * analysis and compilation as necessary. Throws
+ * a NotPresentException if no element exists in the workspace that
+ * matches the given handle.
+ */
+ protected TypeStructureEntry buildTypeStructureEntry(IType handle)
+ throws NotPresentException {
+ TypeStructureEntry tsEntry = getTypeStructureEntry(handle, true);
+ if (tsEntry == null) {
+ throw new NotPresentException();
+ }
+ return tsEntry;
+ }
+
+ /**
+ * Canonicalize a package handle.
+ */
+ protected IPackage canonicalize(IPackage pkg) {
+ PackageMapEntry entry = fPackageMap.getEntry(pkg);
+ return entry != null ? entry.getPackage() : pkg;
+ }
+
+ /**
+ * Canonicalize a type handle.
+ */
+ protected IType canonicalize(IType type) {
+ TypeStructureEntry tsEntry =
+ (TypeStructureEntry) fPrincipalStructureTable.get(type);
+ if (tsEntry != null) {
+ return tsEntry.getType();
+ } else {
+ return type;
+ }
+ }
+
+ /**
+ * Canonicalizes the build context of this state through the package map.
+ */
+ protected void canonicalizeBuildContext() {
+ fBuildContext = canonicalizeBuildContext(fBuildContext);
+ }
+
+ /**
+ * Returns a new build context that contains package handles
+ * that have been canonicalized in this state.
+ */
+ protected IImageContext canonicalizeBuildContext(IImageContext oldContext) {
+ if (oldContext == null) {
+ return null;
+ }
+ IPackage[] oldPackages = oldContext.getPackages();
+ int pkgCount = oldPackages.length;
+ IPackage[] newPackages = new IPackage[pkgCount];
+
+ /* canonicalize packages through package map */
+ for (int i = 0; i < pkgCount; i++) {
+ newPackages[i] = canonicalize(oldPackages[i]);
+ }
+
+ return new ImageContextImpl(fDevelopmentContext, newPackages);
+ }
+
+ /**
+ * Clean up after a build.
+ */
+ protected void cleanUp() {
+ //resetProject(); - no longer clear the project back pointer
+ }
+
+ /**
+ * Adds all binary broker keys still in use by this state
+ * to the given set.
+ */
+ protected void collectBinaryBrokerKeys(Hashtable keysInUse) {
+ for (Enumeration e = fPrincipalStructureTable.elements();
+ e.hasMoreElements();
+ ) {
+ TypeStructureEntry tsEntry = (TypeStructureEntry) e.nextElement();
+ if (!tsEntry.isBinary()) {
+ int crc = tsEntry.getCRC32();
+ if (crc != 0) {
+ IType type = tsEntry.getType();
+ BinaryBrokerKey key = new BinaryBrokerKey(type, crc);
+ keysInUse.put(key, key);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns true if the given source entry contributes to the state, false otherwise.
+ */
+ protected boolean contains(SourceEntry sEntry) {
+ IPackage pkg = packageFromSourceEntry(sEntry);
+ return getSourceElementTable().getSourceEntry(pkg, sEntry.getFileName())
+ != null;
+ }
+
+ /**
+ * Converts a compilation result from the compiler's representation
+ * to the builder's representation. This version is to be called
+ * by the batch builder. The goal is to be able to accomplish
+ * this without having to parse the binary for principal structure
+ * information.
+ */
+ protected ConvertedCompilationResult convertCompilationResult(
+ CompilationResult result,
+ IPackage defaultPackage) {
+ String fileName = new String(result.getFileName());
+ SourceEntry sEntry = SourceEntry.fromPathWithZipEntryName(fileName);
+ PackageElement resultUnit = packageElementFromSourceEntry(sEntry);
+
+ /**
+ * Make sure the CU exists. May be null if unit is unavailable
+ * (e.g. package is not included in package map due to class path omission).
+ * If this is the case, we shouldn't have reached this point.
+ */
+ IPackage resultPkg = resultUnit.getPackage();
+ IProblem[] compilerProblems = result.getProblems();
+ Vector vProblems =
+ new Vector(compilerProblems == null ? 0 : compilerProblems.length);
+
+ /* convert type names to type handles for the produced types */
+ ClassFile[] classFiles = result.getClassFiles();
+ Vector vTSEntries = new Vector(classFiles.length);
+ boolean reportedPackageConflict = false;
+ for (int i = 0; i < classFiles.length; ++i) {
+ ClassFile classFile = classFiles[i];
+ String className = Util.toString(classFile.getCompoundName());
+ if (classFile == null) {
+ // Could not discover principal structure
+ String msg = "Error parsing binary for " + className;
+ ProblemDetailImpl problem = new ProblemDetailImpl(msg, sEntry);
+ vProblems.addElement(problem);
+ // skip it
+ continue;
+ }
+ IType typeHandle = typeNameToHandle(resultPkg, className);
+ IPackage typePkg = typeHandle.getPackage();
+ if (!resultPkg.equals(typePkg)) {
+ if (!reportedPackageConflict) {
+ // Fix for 1FW88LE: ITPJCORE:WIN2000 - What does the error mean (package declaration/package)
+ // and 1FW88DS: ITPJUI:WIN2000 - Go to file from task doesn't show line in editor
+ IPath path = sEntry.getPath().removeLastSegments(1);
+ if (!resultPkg.isUnnamed()) {
+ path =
+ path.removeLastSegments(
+ new Path(resultPkg.getName().replace('.', IPath.SEPARATOR)).segmentCount());
+ }
+ if (!typePkg.isUnnamed()) {
+ path = path.append(typePkg.getName().replace('.', IPath.SEPARATOR));
+ }
+ String msg =
+ "Package declaration does not match folder. Expected folder is " + path + ".";
+ ProblemDetailImpl problem =
+ new ProblemDetailImpl(msg, 0, IProblemDetail.S_ERROR, sEntry, 0, 0, 1);
+ vProblems.addElement(problem);
+ // Only report the conflict once (there may be several types, but there's only one package declaration).
+ reportedPackageConflict = true;
+ }
+ // toss type result
+ continue;
+ }
+ TypeStructureEntry tsEntry = new TypeStructureEntry(sEntry, typeHandle);
+
+ /* squirrel the binary away */
+ byte[] binary = classFile.getBytes();
+ // as a side effect, the following sets the crc32 for the type structure entry
+ getBinaryOutput().putBinary(tsEntry, binary);
+ vTSEntries.addElement(tsEntry);
+ }
+ TypeStructureEntry[] tsEntries = new TypeStructureEntry[vTSEntries.size()];
+ vTSEntries.copyInto(tsEntries);
+
+ /* convert dependencies */
+ Vector dependencies = resolveDependencies(resultUnit, result);
+
+ /* convert problems */
+ if (compilerProblems != null) {
+ for (int i = 0; i < compilerProblems.length; i++) {
+ // The problem factory created the compiler problems as ProblemDetailImpl objects
+ // without the source entry set. Fill it in here.
+ ProblemDetailImpl problem = (ProblemDetailImpl) compilerProblems[i];
+ problem.setSourceEntry(sEntry);
+ vProblems.addElement(problem);
+ }
+ }
+ IProblemDetail[] problems = new IProblemDetail[vProblems.size()];
+ vProblems.copyInto(problems);
+ return new ConvertedCompilationResult(
+ resultUnit,
+ dependencies,
+ problems,
+ tsEntries);
+ }
+
+ /**
+ * Returns a copy of the state with the given workspace and build context.
+ */
+ protected StateImpl copy(IProject newProject, IImageContext context) {
+ StateImpl newState = new StateImpl(this.fDevelopmentContext, newProject);
+ newState.fPackageMap = this.fPackageMap.copy();
+ newState.fPathMap = this.fPathMap;
+ newState.fSourceElementTable = this.fSourceElementTable.copy();
+ newState.fPrincipalStructureTable =
+ (Hashtable) this.fPrincipalStructureTable.clone();
+ newState.fProblemReporter = this.fProblemReporter.copy();
+ newState.fGraph = this.fGraph.copy();
+ newState.fBuildContext = context;
+ newState.fCompilerOptions = this.fCompilerOptions;
+ return newState;
+ }
+
+ /**
+ * Returns the default package which is visible by the given source entry,
+ * or null if there is no visible default package.
+ * Named projects should be able to see the default package
+ * in the same project, if any.
+ * See 1PQ9DWH: LFRE:ALL - default package not found in name lookup.
+ */
+ protected IPackage defaultPackageFor(IPackage pkg) {
+ return pkg.isUnnamed() ? pkg : defaultPackageForProject();
+ }
+
+ /**
+ * Returns the default package for the project.
+ */
+ protected IPackage defaultPackageForProject() {
+ return fDevelopmentContext.getImage().getPackageHandle(
+ PackageImpl.DEFAULT_PACKAGE_PREFIX + getProject().getName(),
+ true);
+ }
+
+ /**
+ * The IBinaryType for this TypeStructureEntry has been flushed from
+ * the cache. Rebuild the IBinaryType from binary. May or may not force
+ * a lazy build, depending on the parameter lazyBuildCU.
+ */
+ protected IBinaryType forceBinaryType(
+ TypeStructureEntry tsEntry,
+ boolean lazyBuildCU) {
+ IType type = tsEntry.getType();
+ SourceEntry sEntry = tsEntry.getSourceEntry();
+ IBinaryType binaryType = null;
+
+ /* if its a class file, get descriptor from binary index */
+ if (sEntry.isBinary()) {
+ try {
+ byte[] bytes = getElementContentBytes(sEntry);
+ binaryType =
+ new ClassFileReader(bytes, sEntry.getPathWithZipEntryName().toCharArray());
+ } catch (ClassFormatException e) {
+ /* problem will be generated below */
+ }
+ } else {
+ /* entry is source in workspace; get binary from broker */
+ IType typeSS = (IType) type.inState(this);
+ byte[] bytes = getBinary(typeSS, lazyBuildCU);
+ if (bytes != null) {
+ try {
+ binaryType =
+ new ClassFileReader(bytes, sEntry.getPathWithZipEntryName().toCharArray());
+ } catch (ClassFormatException e) {
+ /* problem will be generated below */
+ }
+ }
+ }
+ if (lazyBuildCU && binaryType == null) {
+ /* couldn't parse the class file */
+ ProblemDetailImpl problem =
+ new ProblemDetailImpl("unable to parse class file: " + type.getName(), sEntry);
+ fProblemReporter.putProblem(sEntry, problem);
+ }
+ return binaryType;
+ }
+
+ /**
+ * Generate a unique fingerprint for a state.
+ */
+ protected static byte[] generateFingerprint() {
+ // TBD: Better to use a UUID, but we don't have a convenient implementation.
+ // Chances are the fingerprint will be used only on one machine, so this should suffice.
+ byte[] fingerprint = new byte[32];
+ fgRandom.nextBytes(fingerprint);
+ return fingerprint;
+ }
+
+ /**
+ * Returns an array of all packages in the state (non-state-specific handles).
+ */
+ protected IPackage[] getAllPackagesAsArray() {
+ return fPackageMap.getAllPackagesAsArray();
+ }
+
+ /**
+ * Returns an enumeration of TypeStructureEntry objects for all types
+ * in the given package, including nested types. Returns null if the package does not exist.
+ */
+ protected TypeStructureEntry[] getAllTypesForPackage(IPackage pkg) {
+ if (fPrincipalStructureByPackageTable == null) {
+ fPrincipalStructureByPackageTable = new Hashtable(11);
+ }
+ Object o = fPrincipalStructureByPackageTable.get(pkg);
+ if (o != null) {
+ return (TypeStructureEntry[]) o;
+ }
+ if (!fPackageMap.containsPackage(pkg)) {
+ return null;
+ }
+
+ // TBD: Doesn't support lazy builds.
+
+ int max = 30;
+ TypeStructureEntry[] list = new TypeStructureEntry[max];
+ int count = 0;
+ for (Enumeration e = fPrincipalStructureTable.elements();
+ e.hasMoreElements();
+ ) {
+ TypeStructureEntry tsEntry = (TypeStructureEntry) e.nextElement();
+ if (tsEntry.getType().getPackage().equals(pkg)) {
+ if (count == max)
+ System.arraycopy(
+ list,
+ 0,
+ list = new TypeStructureEntry[max = max * 2],
+ 0,
+ count);
+ list[count++] = tsEntry;
+ }
+ }
+ if (count < max)
+ System.arraycopy(list, 0, list = new TypeStructureEntry[count], 0, count);
+ fPrincipalStructureByPackageTable.put(pkg, list);
+ return list;
+ }
+
+ /**
+ * Returns the binary for a given type handle. The type handle must
+ * be state specific.
+ * @param type The type handle to get binaries for
+ * @param lazyBuildCU whether or not to perform a lazy build to get the binary.
+ */
+ protected byte[] getBinary(IType type, boolean lazyBuildCU)
+ throws NotPresentException {
+ if (!type.isStateSpecific()) {
+ throw new StateSpecificException();
+ }
+ IType nssHandle = (IType) type.nonStateSpecific();
+ TypeStructureEntry tsEntry = buildTypeStructureEntry(nssHandle);
+
+ /* Attempt to retrieve binary from binary output */
+ byte[] binary = getBinaryOutput().getBinary(tsEntry, nssHandle);
+ if (binary != null)
+ return binary;
+
+ /*
+ * We have a built entry, but couldn't get the bytes from the binary output.
+ * Need to recompile.
+ */
+ if (!lazyBuildCU) {
+ return null;
+ }
+
+ /* make sure the entry is a compilation unit */
+ PackageElement unit = packageElementFromSourceEntry(tsEntry.getSourceEntry());
+ new BatchImageBuilder(this).lazyBuild(unit);
+ tsEntry = getTypeStructureEntry(nssHandle, false);
+ if (tsEntry == null) {
+ return null;
+ } else {
+ return getBinaryOutput().getBinary(tsEntry, nssHandle);
+ }
+ }
+
+ /**
+ * Returns the binary output for this state.
+ */
+ protected BinaryOutput getBinaryOutput() {
+ BinaryOutput output = fDevelopmentContext.getBinaryOutput();
+ if (output != null) {
+ return output;
+ } else {
+ return fBinaryOutput;
+ }
+ }
+
+ /**
+ * Returns the IBinaryType for the given type structure entry.
+ * Performs lazy builds as necessary.
+ * If there is no possible way of creating the IBinaryType (because
+ * blobs are not available or the class file is corrupt), a NotPresentException
+ * is thrown.
+ */
+ protected IBinaryType getBinaryType(TypeStructureEntry tsEntry)
+ throws NotPresentException {
+
+ /* rebuild descriptor from indexes or binary */
+ IBinaryType binaryType = forceBinaryType(tsEntry, false);
+ // Use false for 1FVQGL1: ITPJCORE:WINNT - SEVERE - Error saving java file
+ if (binaryType == null) {
+ throw new NotPresentException(
+ "Unable to build type: " + tsEntry.getSourceEntry().getFileName());
+ }
+ return binaryType;
+ }
+
+ /**
+ * Returns the IBinaryType for the given type structure entry if it
+ * is available. Parses the binary if necessary, but returns null if
+ * the binary is not available (doesn't invoke a lazy build)
+ */
+ protected IBinaryType getBinaryTypeOrNull(TypeStructureEntry tsEntry) {
+
+ /* rebuild descriptor from binary */
+ return forceBinaryType(tsEntry, false);
+ }
+
+ /**
+ * Returns the ImageContext representing the subset of the
+ * image which is important to have built as early
+ * as possible. Although all parts of the image can be navigated
+ * to and queried, possibly using other ImageContexts, the builder
+ * gives higher priority to maintaining the build context subset
+ * than to other parts of the image.
+ *
+ * @see #applySourceDelta
+ */
+ public IImageContext getBuildContext() {
+ return fBuildContext;
+ }
+
+ /**
+ * Returns the projects mentioned in the class path, including the one for this state.
+ */
+ public IProject[] getClassPathProjects() {
+ Vector projects = new Vector();
+ IPackageFragmentRoot[] roots = fPackageFragmentRootsInClassPath;
+ for (int i = 0; i < roots.length; ++i) {
+ IJavaProject javaProject = roots[i].getJavaProject();
+ if (javaProject != null) {
+ IProject project = javaProject.getProject();
+ if (!projects.contains(project)) {
+ projects.add(project);
+ }
+ }
+ }
+ IProject[] result = new IProject[projects.size()];
+ projects.copyInto(result);
+ return result;
+ }
+
+ /**
+ * Given a compilation unit name from the compiler, and the default package which
+ * was active when it was produced, answer the corresponding CompilationUnit.
+ */
+ protected PackageElement getCompilationUnitFromName(
+ String name,
+ IPackage defaultPackage) {
+ int i = name.lastIndexOf('.');
+ IPackage pkg;
+ String simpleName;
+ if (i == -1) {
+ pkg = defaultPackage;
+ simpleName = name;
+ } else {
+ pkg =
+ fDevelopmentContext.getImage().getPackageHandle(name.substring(0, i), false);
+ simpleName = name.substring(i + 1);
+ }
+ pkg = canonicalize(pkg);
+ if (!fSourceElementTable.containsPackage(pkg)) {
+ getSourceEntries(pkg);
+ }
+ SourceEntry entry =
+ fSourceElementTable.getSourceEntry(pkg, simpleName + ".java");
+ if (entry == null)
+ return null;
+ return new PackageElement(pkg, entry);
+ }
+
+ /**
+ * Returns the compiler options used to build this state.
+ */
+ public ConfigurableOption[] getCompilerOptions() {
+ return fCompilerOptions;
+ }
+
+ /**
+ * Returns an enumeration of TypeStructureEntry objects for all top-level types
+ * in the given package. Returns null if the package does not exist.
+ */
+ protected TypeStructureEntry[] getDeclaredTypesForPackage(IPackage pkg) {
+ TypeStructureEntry[] all = getAllTypesForPackage(pkg);
+ TypeStructureEntry[] declared = new TypeStructureEntry[all.length];
+ int count = 0;
+ for (int i = 0, len = all.length; i < len; ++i) {
+ if (BinaryStructure.isPackageMember(getBinaryType(all[i]))) {
+ declared[count++] = all[i];
+ }
+ }
+ if (count < declared.length) {
+ System.arraycopy(
+ declared,
+ 0,
+ declared = new TypeStructureEntry[count],
+ 0,
+ count);
+ }
+ return declared;
+ }
+
+ /**
+ * Returns the dependency graph for this state, if supported,
+ * or null if the dependency graph is unknown.
+ */
+ public IDependencyGraph getDependencyGraph() {
+ return new DependencyGraphImpl(this);
+ }
+
+ /**
+ * Returns this state's development context.
+ */
+ public IDevelopmentContext getDevelopmentContext() {
+ return fDevelopmentContext;
+ }
+
+ /**
+ * Returns the byte contents for a source entry.
+ */
+ protected byte[] getElementContentBytes(SourceEntry entry) {
+ if (entry.fZipEntryFileName != null) {
+ ZipFile zipFile = null;
+ try {
+ IPath path = entry.getPath();
+ JavaModelManager manager =
+ (JavaModelManager) JavaModelManager.getJavaModelManager();
+ zipFile = manager.getZipFile(path);
+ if (zipFile == null) {
+ //throw internalException("Error reading file " + entry + "due to missing zip/jar file");
+ return new byte[0];
+ }
+ ZipEntry zipEntry = zipFile.getEntry(entry.getZipEntryName());
+ if (zipEntry == null) {
+ //throw internalException("Error reading file " + entry + " due to missing zip/jar entry");
+ return new byte[0];
+ }
+ InputStream input = zipFile.getInputStream(zipEntry);
+ if (input == null) {
+ //throw internalException("Error reading file " + entry + " due to missing zip/jar entry");
+ return new byte[0];
+ }
+ byte[] contents = Util.readContentsAsBytes(input);
+ if (contents == null) {
+ //throw internalException("Error reading file " + entry + " due to error reading contents");
+ return new byte[0];
+ }
+ return contents;
+ } catch (CoreException e) {
+ //throw internalException(e);
+ return new byte[0];
+ } catch (IOException e) {
+ String message = e.getMessage();
+ message = (message == null ? "." : " due to " + message + ".");
+ //throw internalException("Error reading file " + entry + message);
+ return new byte[0];
+ } finally {
+ if (zipFile != null) {
+ try {
+ zipFile.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+ } else {
+ IFile file = getFile(entry);
+ try {
+ // Fix for 1FVTLHB: ITPCORE:WINNT - Importing a project does not import class files
+ JavaModelManager.getJavaModelManager().ensureLocal(file);
+ return Util.readContentsAsBytes(file.getContents(true));
+ } catch (CoreException e) {
+ return fDevelopmentContext.getBinaryFromFileSystem(file);
+ } catch (IOException e) {
+ String message = e.getMessage();
+ message = (message == null ? "." : " due to " + message + ".");
+ //throw internalException("Error reading file " + entry + message);
+ return new byte[0];
+ }
+ }
+ }
+
+ /**
+ * Returns the contents for a source entry as a char array.
+ */
+ protected char[] getElementContentCharArray(SourceEntry entry) {
+ // TBD: need proper byte->char conversion
+ byte[] bytes = getElementContentBytes(entry);
+ BufferedReader reader = null;
+ try {
+ reader =
+ new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bytes)));
+ int length = bytes.length;
+ char[] contents = new char[length];
+ int len = 0;
+ int readSize = 0;
+ while ((readSize != -1) && (len != length)) {
+ // See PR 1FMS89U
+ // We record first the read size. In this case len is the actual read size.
+ len += readSize;
+ readSize = reader.read(contents, len, length - len);
+ }
+ reader.close();
+ // See PR 1FMS89U
+ // Now we need to resize in case the default encoding used more than one byte for each
+ // character
+ if (len != length)
+ System.arraycopy(contents, 0, (contents = new char[len]), 0, len);
+ return contents;
+ } catch (IOException e) {
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (IOException ioe) {
+ }
+ }
+ String message = e.getMessage();
+ message = (message == null ? "." : " due to " + message + ".");
+ throw internalException("Error reading file " + entry + message);
+ }
+ }
+
+ /**
+ * Returns the file for a workspace-relative path.
+ */
+ protected IFile getFile(IPath path) {
+ return getProject().getWorkspace().getRoot().getFile(makeAbsolute(path));
+ }
+
+ /**
+ * Returns the file for a source entry.
+ */
+ protected IFile getFile(SourceEntry sEntry) {
+ return getFile(sEntry.getPath());
+ }
+
+ /**
+ * Answer a unique fingerprint for this state.
+ * It is guaranteed that no other state can have the same
+ * fingerprint.
+ * The result should not be modified.
+ */
+ public byte[] getFingerprint() {
+ return (byte[]) fFingerprint.clone(); // Trust no one.
+ }
+
+ /**
+ * Returns the folder for a project-relative path.
+ */
+ protected IFolder getFolder(IPath path) {
+ return getProject().getFolder(makeAbsolute(path));
+ }
+
+ /**
+ * Returns the image described by this state. The result is state-specific.
+ *
+ * @see IDevelopmentContext
+ * @see IDevelopmentContext#getImage
+ */
+ public IImage getImage() {
+ return fImage;
+ }
+
+ /**
+ * Returns the dependency graph for the state. Used by the incremental builder.
+ */
+ protected DependencyGraph getInternalDependencyGraph() {
+ return fGraph;
+ }
+
+ /**
+ * Returns the Java Model element for a source entry.
+ */
+ protected IJavaElement getJavaElement(SourceEntry sEntry) {
+ try {
+ JavaProject javaProject = (JavaProject) getJavaProject();
+ String zipEntryFileName = sEntry.fZipEntryFileName;
+ IPackageFragment frag = null;
+ if (zipEntryFileName != null) {
+ IPackageFragmentRoot root;
+ IPath path = sEntry.getPath();
+ if (!path.isAbsolute()
+ || javaProject.getWorkspace().getRoot().findMember(path) != null) {
+ root = javaProject.getPackageFragmentRoot(getFile(path));
+ } else {
+ root = javaProject.getPackageFragmentRoot(path.toOSString());
+ }
+ String zipEntryPath = sEntry.fZipEntryPath;
+ String pkgName =
+ zipEntryPath == null
+ ? IPackageFragment.DEFAULT_PACKAGE_NAME
+ : zipEntryPath.replace('/', '.');
+ frag = root.getPackageFragment(pkgName);
+ } else {
+ IPackageFragmentRoot[] roots = getPackageFragmentRootsInClassPath();
+ for (int i = 0; i < roots.length; ++i) {
+ IPackageFragmentRoot root = roots[i];
+ if (!root.isArchive() && root.exists()) {
+ IPath rootPath = root.getUnderlyingResource().getFullPath();
+ if (rootPath.isPrefixOf(sEntry.getPath())) {
+ String pkgName =
+ sEntry
+ .getPath()
+ .removeLastSegments(1)
+ .removeFirstSegments(rootPath.segmentCount())
+ .toString()
+ .replace('/', '.');
+ frag = root.getPackageFragment(pkgName);
+ break;
+ }
+ }
+ }
+ }
+ if (frag == null) {
+ throw internalException("Missing file for " + sEntry);
+ }
+ String fileName = sEntry.getPath().lastSegment();
+ if (sEntry.isSource()) {
+ return frag.getCompilationUnit(fileName);
+ } else {
+ if (zipEntryFileName != null) {
+ return frag.getClassFile(zipEntryFileName);
+ } else {
+ return frag.getClassFile(fileName);
+ }
+ }
+ } catch (JavaModelException e) {
+ throw internalException(e);
+ }
+ }
+
+ /**
+ * Returns the Java Model element for the project.
+ */
+ protected IJavaProject getJavaProject() {
+ return JavaCore.create(getProject());
+ }
+
+ /**
+ * For debugging only.
+ */
+ protected INode getNode(String qualifiedNameWithSuffix) {
+ PackageElement element = getPackageElement(qualifiedNameWithSuffix);
+ if (element == null)
+ return null;
+ return fGraph.getNodeFor(element, false);
+ }
+
+ /**
+ * Returns the output location for this state.
+ * The binary output must be a ProjectBinaryOutput.
+ */
+ protected IPath getOutputLocation() {
+ BinaryOutput output = getBinaryOutput();
+ if (output instanceof ProjectBinaryOutput) {
+ return ((ProjectBinaryOutput) output).getOutputPath();
+ } else {
+ return null;
+ }
+ }
+
+ static Comparator getPackageComparator() {
+ return new Comparator() {
+ public int compare(Object o1, Object o2) {
+ IPackage p1 = (IPackage) o1;
+ IPackage p2 = (IPackage) o2;
+ return p1.getName().compareTo(p2.getName());
+ }
+ };
+ }
+
+ /**
+ * For debugging only.
+ */
+ protected PackageElement getPackageElement(String qualifiedNameWithSuffix) {
+ SourceEntry sEntry = getSourceEntry(qualifiedNameWithSuffix);
+ if (sEntry == null)
+ return null;
+ return packageElementFromSourceEntry(sEntry);
+ }
+
+ /**
+ * Returns the package fragment roots to build in classpath order.
+ */
+ protected IPackageFragmentRoot[] getPackageFragmentRootsInClassPath() {
+ return fPackageFragmentRootsInClassPath;
+ }
+
+ /**
+ * Returns the package map
+ */
+ protected PackageMap getPackageMap() {
+ return fPackageMap;
+ }
+
+ static Comparator getPathComparator() {
+ return new Comparator() {
+ public int compare(Object o1, Object o2) {
+ IPath p1 = (IPath) o1;
+ IPath p2 = (IPath) o2;
+ return p1.toString().compareTo(p2.toString());
+ }
+ };
+ }
+
+ /**
+ * Returns the path map.
+ */
+ protected PathMap getPathMap() {
+ return fPathMap;
+ }
+
+ /**
+ * Returns the principal structure by package table.
+ */
+ protected Hashtable getPrincipalStructureByPackageTable() {
+ if (fPrincipalStructureByPackageTable == null) {
+ fPrincipalStructureByPackageTable = new Hashtable(11);
+ }
+ return fPrincipalStructureByPackageTable;
+ }
+
+ /**
+ * Returns the principal structure table
+ */
+ protected Hashtable getPrincipalStructureTable() {
+ return fPrincipalStructureTable;
+ }
+
+ /**
+ * Returns the problem reporter
+ */
+ protected IProblemReporter getProblemReporter() {
+ return fProblemReporter;
+ }
+
+ /**
+ * Returns the problems that were reported against the image itself
+ */
+ protected Enumeration getProblems() {
+ return fProblemReporter.getImageProblems();
+ }
+
+ /**
+ * For debugging only.
+ */
+ protected Vector getProblems(String qualifiedNameWithSuffix) {
+ SourceEntry sEntry = getSourceEntry(qualifiedNameWithSuffix);
+ return fProblemReporter.getProblemVector(sEntry);
+ }
+
+ /**
+ * @see IState
+ */
+ public IProject getProject() {
+ return fProject;
+ }
+
+ /**
+ * Returns the name of the project built by this state.
+ */
+ protected String getProjectName() {
+ if (fProjectName == null)
+ fProjectName = getProject().getName();
+ return fProjectName;
+ }
+
+ /**
+ * Returns an array of Package objects representing all other
+ * packages which this package directly references.
+ * This is the union of all packages directly referenced by all
+ * classes and interfaces in this package, including packages
+ * mentioned in import declarations.
+ * <p>
+ * A direct reference in source code is a use of a package's
+ * name other than as a prefix of another package name.
+ * For example, 'java.lang.Object' contains a direct reference
+ * to the package 'java.lang', but not to the package 'java'.
+ * Also note that every package that declares at least one type
+ * contains a direct reference to java.lang in virtue of the
+ * automatic import of java.lang.*.
+ * The result does not include this package (so contrary to the note
+ * above, the result for package java.lang does not include java.lang).
+ * In other words, the result is non-reflexive and typically
+ * non-transitive.
+ * <p>
+ * The resulting packages may or may not be present in the image,
+ * since the classes and interfaces in this package may refer to missing
+ * packages.
+ * The resulting packages are in no particular order.
+ */
+ protected IPackage[] getReferencedPackages(IPackage pkgHandle) {
+
+ /* set of referenced builder packages */
+ Hashtable pkgTable = getTableOfReferencedPackages(pkgHandle);
+
+ /* convert to array and return */
+ IPackage[] results = new IPackage[pkgTable.size()];
+ int i = 0;
+ for (Enumeration e = pkgTable.elements(); e.hasMoreElements(); i++) {
+ results[i] = (IPackage) e.nextElement();
+ }
+ return results;
+ }
+
+ /**
+ * Returns the references for the given package element. Returns null
+ * if the references could not be found.
+ */
+ protected ReferenceInfo getReferencesForPackageElement(PackageElement builderUnit) {
+ if (!builderUnit.isSource()) {
+ return null;
+ }
+ SourceEntry sEntry = getSourceEntry(builderUnit);
+ IJavaElement javaElement = getJavaElement(sEntry);
+ ICompilationUnit unit = (ICompilationUnit) javaElement;
+ try {
+ return ((CompilationUnit) unit).getReferenceInfo();
+ } catch (JavaModelException e) {
+ System.out.println("Caught not present exception for unit: " + unit + e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns an array of Package objects representing all packages
+ * in the given image context which directly reference this package.
+ * The result does not include this package.
+ * In other words, the result is non-transitive and non-reflexive.
+ * <p>
+ * The intersection of all packages in the image and those in the
+ * image context are considered, so the resulting packages are
+ * guaranteed to be present in the image.
+ * The resulting packages are in no particular order.
+ *
+ * This is an extremely slow implementation (n^3?). Avoid using it if possible.
+ */
+ protected IPackage[] getReferencingPackages(
+ IPackage pkgHandle,
+ IImageContext context) {
+
+ /* the results */
+ Vector vResults = new Vector();
+ IImage image = fDevelopmentContext.getImage();
+
+ /* do for each package in the image context */
+ IPackage[] pkgs = context.getPackages();
+ for (int i = 0; i < pkgs.length; i++) {
+ /* skip the package we are looking for */
+ if (pkgs[i].equals(pkgHandle)) {
+ continue;
+ }
+ Hashtable table = getTableOfReferencedPackages(pkgs[i]);
+ /* if the package references this package */
+ if (table.contains(pkgHandle)) {
+ /* add it to results */
+ vResults.addElement(pkgs[i]);
+ }
+ }
+ IPackage[] results = new IPackage[vResults.size()];
+ vResults.copyInto(results);
+ return results;
+ }
+
+ /**
+ * Returns a report card for this state., restricted to
+ * the given image context.
+ * Problems are organized by workspace element identifiers.
+ * This method is on <code>IState</code> rather than
+ * <code>IImage</code> to make it clear that
+ * the result is inherently state-specific.
+ * @param imageContext the image context in which to
+ * restrict the report card.
+ */
+ public IReportCard getReportCard(IImageContext imageContext) {
+ return new ReportCardImpl(this, imageContext);
+ }
+
+ /**
+ * Iterates through the children of a package fragment and adds all visible source element entries to the table.
+ */
+ protected void getSourceElementEntries(
+ IPackage pkg,
+ IPath path,
+ LookupTable entryTable) {
+ try {
+ IPackageFragmentRoot root = null;
+ IPackageFragment frag = null;
+ boolean isDefault = pkg.isUnnamed();
+ String pkgName =
+ isDefault ? IPackageFragment.DEFAULT_PACKAGE_NAME : pkg.getName();
+ String pkgPath = pkgName.replace('.', '/');
+ if (isZipElement(path)) {
+ IResource member = null;
+ if (!path.isAbsolute()
+ || getProject().getWorkspace().getRoot().findMember(path) != null) {
+ root = getJavaProject().getPackageFragmentRoot(getFile(path));
+ } else {
+ root = getJavaProject().getPackageFragmentRoot(path.toOSString());
+ }
+ frag = root.getPackageFragment(pkgName);
+ } else {
+ IPackageFragmentRoot[] roots = getPackageFragmentRootsInClassPath();
+ for (int i = 0; i < roots.length; ++i) {
+ IPackageFragmentRoot testRoot = roots[i];
+ if (!testRoot.isArchive()
+ && testRoot.getUnderlyingResource().getFullPath().isPrefixOf(path)) {
+ root = testRoot;
+ frag = testRoot.getPackageFragment(pkgName);
+ break;
+ }
+ }
+ }
+ boolean isArchive = root.isArchive();
+ if (!isArchive && !root.exists()) {
+ return;
+ }
+ if (isArchive
+ && root.getUnderlyingResource() != null
+ && !root.getUnderlyingResource().isLocal(IResource.DEPTH_ZERO)) {
+ return;
+ }
+ if (frag == null || !frag.exists()) {
+ return;
+ }
+ IPath entryPath = null;
+ String zipEntryPath = null;
+ String zipEntryFileName = null;
+ ((PackageFragment) frag).refreshChildren();
+ ICompilationUnit[] units = frag.getCompilationUnits();
+ for (int i = 0; i < units.length; ++i) {
+ ICompilationUnit unit = units[i];
+ String fileName = unit.getElementName();
+ /* see if a source entry exists for this file name */
+ if (entryTable.get(fileName) == null) {
+ if (isArchive) {
+ entryPath = path;
+ zipEntryPath = isDefault || pkgPath.length() == 0 ? null : pkgPath;
+ zipEntryFileName = fileName;
+ } else {
+ entryPath = unit.getUnderlyingResource().getFullPath();
+ zipEntryPath = null;
+ zipEntryFileName = null;
+ }
+ SourceEntry sEntry = new SourceEntry(entryPath, zipEntryPath, zipEntryFileName);
+ entryTable.put(fileName, sEntry);
+ }
+ }
+ IClassFile[] classFiles = frag.getClassFiles();
+ for (int i = 0; i < classFiles.length; ++i) {
+ IClassFile classFile = classFiles[i];
+ String fileName = classFile.getElementName();
+ /* see if a source entry exists for this file name */
+ if (entryTable.get(fileName) == null) {
+ if (isArchive) {
+ entryPath = path;
+ zipEntryPath = isDefault || pkgPath.length() == 0 ? null : pkgPath;
+ zipEntryFileName = fileName;
+ } else {
+ if (!classFile.getUnderlyingResource().isLocal(IResource.DEPTH_ZERO))
+ continue;
+ entryPath = classFile.getUnderlyingResource().getFullPath();
+ zipEntryPath = null;
+ zipEntryFileName = null;
+ }
+ SourceEntry sEntry = new SourceEntry(entryPath, zipEntryPath, zipEntryFileName);
+ entryTable.put(fileName, sEntry);
+ }
+ }
+ } catch (JavaModelException e) {
+ throw internalException(e);
+ }
+ }
+
+ /**
+ * Returns the source element table
+ */
+ protected SourceElementTable getSourceElementTable() {
+ return fSourceElementTable;
+ }
+
+ /**
+ * Returns the source entries in the given package. Does lazy analysis
+ * of source entry table as necessary. Returns null if the package is not present.
+ */
+ protected SourceEntry[] getSourceEntries(IPackage pkg) {
+ SourceEntry[] entries = fSourceElementTable.getSourceEntries(pkg);
+ if (entries != null) {
+ return entries;
+ }
+
+ /* Need to build the table for the package */
+
+ /* go through package fragments and compute all source entries */
+ IPath[] frags = fPackageMap.getFragments(pkg);
+ if (frags == null) {
+ return null; // package not present
+ }
+
+ /* build a table of source entries, keyed by filename */
+ LookupTable entryTable = new LookupTable(20);
+ for (int i = 0; i < frags.length; i++) {
+ getSourceElementEntries(pkg, frags[i], entryTable);
+ }
+ fSourceElementTable.putPackageTable(pkg, entryTable);
+ return fSourceElementTable.getSourceEntries(pkg);
+ }
+
+ /**
+ * For debugging only.
+ */
+ protected SourceEntry getSourceEntry(String qualifiedNameWithSuffix) {
+ int dot = qualifiedNameWithSuffix.lastIndexOf('.');
+ dot = qualifiedNameWithSuffix.lastIndexOf('.', dot - 1);
+ String pkgName =
+ (dot == -1 ? ".default" : qualifiedNameWithSuffix.substring(0, dot));
+ String fileName =
+ (dot == -1
+ ? qualifiedNameWithSuffix
+ : qualifiedNameWithSuffix.substring(dot + 1));
+ IPackage pkg = fDevelopmentContext.getImage().getPackageHandle(pkgName, false);
+ getSourceEntries(pkg); // force
+ return fSourceElementTable.getSourceEntry(pkg, fileName);
+ }
+
+ /**
+ * Looks up and returns the source entry for a source element in the source element table.
+ * Returns null if the type does not exist.
+ */
+ protected SourceEntry getSourceEntry(PackageElement element) {
+ IPackage pkg = element.getPackage();
+ // lazy build if necessary
+ if (!fSourceElementTable.containsPackage(pkg)) {
+ getSourceEntries(pkg);
+ }
+ return fSourceElementTable.getSourceEntry(pkg, element.getFileName());
+ }
+
+ /**
+ * Returns the source entry for a type. Returns null if the type
+ * does not exist
+ */
+ protected SourceEntry getSourceEntry(IType type) {
+ IPackage pkg = type.getPackage();
+ // lazy build if necessary
+ if (!fSourceElementTable.containsPackage(pkg)) {
+ getSourceEntries(pkg);
+ }
+ String simpleName = type.getSimpleName();
+ SourceEntry entry =
+ fSourceElementTable.getSourceEntry(pkg, simpleName + ".java");
+ if (entry == null) {
+ entry = fSourceElementTable.getSourceEntry(pkg, simpleName + ".class");
+ if (entry == null) {
+ int firstDollar = simpleName.indexOf('$');
+ if (firstDollar != -1) {
+ simpleName = simpleName.substring(0, firstDollar);
+ entry = fSourceElementTable.getSourceEntry(pkg, simpleName + ".java");
+ if (entry == null) {
+ entry = fSourceElementTable.getSourceEntry(pkg, simpleName + ".class");
+ }
+ }
+ }
+ }
+ return entry;
+ }
+
+ /**
+ * Returns the table of subtypes which covers the given image context.
+ * All types in the table are state-specific
+ */
+ protected Hashtable getSubtypesTable(IImageContext imageContext) {
+ if (fSubtypesTable != null) {
+ if (imageContext == null) {
+ if (fSubtypesTableImageContext == null) {
+ return fSubtypesTable;
+ }
+ } else {
+ if (fSubtypesTableImageContext == null
+ || ((ImageContextImpl) imageContext).isSubsetOf(
+ (ImageContextImpl) fSubtypesTableImageContext)) {
+ return fSubtypesTable;
+ }
+ }
+ }
+ IPackage[] pkgs =
+ (imageContext == null
+ ? fPackageMap.getAllPackagesAsArray()
+ : imageContext.getPackages());
+ Hashtable table = new Hashtable(Math.max(pkgs.length * 5, 1));
+ for (int i = 0; i < pkgs.length; ++i) {
+ IPackage pkg = pkgs[i];
+ TypeStructureEntry[] tsEntries = getAllTypesForPackage(pkg);
+ if (tsEntries != null) {
+ for (int j = 0; j < tsEntries.length; ++j) {
+ IType type = (IType) tsEntries[j].getType().inState(this);
+ if (!type.isInterface()) {
+ IType superclass = type.getSuperclass();
+ if (superclass != null) {
+ Vector vSubtypes = (Vector) table.get(superclass);
+ if (vSubtypes == null) {
+ vSubtypes = new Vector(5);
+ table.put(superclass, vSubtypes);
+ }
+ vSubtypes.addElement(type);
+ }
+ }
+ IType[] interfaces = type.getInterfaces();
+ for (int k = 0; k < interfaces.length; ++k) {
+ IType intf = interfaces[k];
+ Vector vSubtypes = (Vector) table.get(intf);
+ if (vSubtypes == null) {
+ vSubtypes = new Vector(5);
+ table.put(intf, vSubtypes);
+ }
+ vSubtypes.addElement(type);
+ }
+ }
+ }
+ }
+ for (Enumeration e = table.keys(); e.hasMoreElements();) {
+ IType type = (IType) e.nextElement();
+ Vector vSubtypes = (Vector) table.get(type);
+ IType[] subtypes = new IType[vSubtypes.size()];
+ vSubtypes.copyInto(subtypes);
+ table.put(type, subtypes);
+ }
+ fSubtypesTable = table;
+ fSubtypesTableImageContext = imageContext;
+ return table;
+ }
+
+ /**
+ * Returns a hashtable of IPackage objects representing all other
+ * packages which this package directly references.
+ */
+ protected Hashtable getTableOfReferencedPackages(IPackage pkgHandle) {
+ /* set of referenced builder packages */
+ Hashtable pkgTable = new Hashtable();
+
+ /* do for each type in this package */
+ TypeStructureEntry[] types = getAllTypesForPackage(pkgHandle);
+ if (types != null) {
+ for (int i = 0; i < types.length; i++) {
+ PackageElement element =
+ packageElementFromSourceEntry(types[i].getSourceEntry());
+ IPackage[] deps =
+ getInternalDependencyGraph().getNamespaceDependencies(element);
+
+ /* make sure namespaces are actually packages */
+ for (int j = 0; j < deps.length; j++) {
+ if (fPackageMap.getEntry(deps[j]) != null) {
+ pkgTable.put(deps[j], deps[j]);
+ }
+ }
+ }
+ }
+
+ /* remove this package */
+ pkgTable.remove(pkgHandle);
+ return pkgTable;
+ }
+
+ /**
+ * For debugging only.
+ */
+ protected TypeStructureEntry getTypeStructureEntry(String qualifiedNameWithoutSuffix) {
+ int dot = qualifiedNameWithoutSuffix.lastIndexOf('.');
+ String pkgName =
+ (dot == -1 ? ".default" : qualifiedNameWithoutSuffix.substring(0, dot));
+ String typeName =
+ (dot == -1
+ ? qualifiedNameWithoutSuffix
+ : qualifiedNameWithoutSuffix.substring(dot + 1));
+ IPackage pkg = fDevelopmentContext.getImage().getPackageHandle(pkgName, false);
+ IType type = pkg.getClassHandle(typeName);
+ return (TypeStructureEntry) fPrincipalStructureTable.get(type);
+ }
+
+ /**
+ * Returns the type structure entry for the given type handle.
+ * If lazyBuildCU is true, performs lazy building of compilation units if necessary.
+ * Always performs lazy building of class files if necessary.
+ * Returns null if no type descriptor can be found.
+ */
+ protected TypeStructureEntry getTypeStructureEntry(
+ IType handle,
+ boolean lazyBuildCU) {
+ TypeStructureEntry tsEntry =
+ (TypeStructureEntry) fPrincipalStructureTable.get(handle);
+ if (tsEntry != null) {
+ return tsEntry;
+ }
+
+ // TBD: Doesn't handle lazy builds.
+
+ /* get the source element */
+ IPackage pkg = handle.getPackage();
+ SourceEntry sEntry = getSourceEntry(handle);
+ if (sEntry == null) {
+ return null;
+ }
+
+ /* if its a class file, parse it */
+ if (sEntry.isBinary()) {
+ //byte[] bytes = getElementContentBytes(sEntry);
+ // Canonicalize package part of type handle
+ handle = canonicalize(pkg).getClassHandle(handle.getSimpleName());
+ tsEntry = new TypeStructureEntry(sEntry, handle);
+ //tsEntry.setCRC32(getBinaryOutput().crc32(bytes));
+ fPrincipalStructureTable.put(handle, tsEntry);
+ } else
+ if (lazyBuildCU) {
+ if (fProblemReporter.hasProblems(sEntry)) {
+ // If the entry has problems, that's a sure sign it has already been compiled.
+ // Don't try again.
+ return null;
+ }
+
+ // make sure the entry is a compilation unit
+ PackageElement unit = packageElementFromSourceEntry(sEntry);
+
+ // compile it
+ new BatchImageBuilder(this).lazyBuild(unit);
+
+ // try to get the entry again; may still be null
+ tsEntry = (TypeStructureEntry) fPrincipalStructureTable.get(handle);
+ }
+ return tsEntry;
+ }
+
+ /**
+ * Returns the (non-state-specific) package handle representing the namespace
+ * for unknown dependencies. All compilation units which have unknown dependencies
+ * depend on this namespace.
+ */
+ protected IPackage getUnknownDependenciesNamespace() {
+ return fDevelopmentContext.getImage().getPackageHandle(
+ UNKNOWN_DEPENDENCIES,
+ true);
+ }
+
+ /**
+ * Process an internal exception: if we're being called by the compiler, throw an AbortCompilation
+ * otherwise throw an internal image builder exception.
+ */
+ protected RuntimeException internalException(String message) {
+ return fDevelopmentContext.internalException(message);
+ }
+
+ /**
+ * Process an internal exception: if we're being called by the compiler, throw an AbortCompilation
+ * otherwise throw an internal image builder exception.
+ */
+ protected RuntimeException internalException(Throwable t) {
+ return fDevelopmentContext.internalException(t);
+ }
+
+ /**
+ * Returns whether the given path represents a zip file.
+ */
+ protected static boolean isZipElement(IPath path) {
+ String extension = path.getFileExtension();
+ return extension != null
+ && (extension.equalsIgnoreCase("zip") || extension.equalsIgnoreCase("jar"));
+ }
+
+ /**
+ * Given a project-relative path, returns an absolute path.
+ */
+ protected IPath makeAbsolute(IPath path) {
+ if (path.isAbsolute()) {
+ return path;
+ }
+ IProject project = getProject();
+ return project.getFullPath().append(path);
+ }
+
+ /**
+ * Returns a new image delta representing the differences between this
+ * state (the new state) and another one (the old state). The delta is naive in that no delta information is initially provided.
+ * Only the portion of the states within the given image context are examined.
+ */
+ public IDelta newNaiveDeltaWith(IState oldState, IImageContext imgCtx) {
+ return new DeltaImpl(oldState, this, imgCtx);
+ }
+
+ /**
+ * Returns a package element corresponding to the given source entry.
+ * The source entry may or may not be present.
+ */
+ protected PackageElement packageElementFromSourceEntry(SourceEntry entry) {
+ IPackage pkgHandle = packageFromSourceEntry(entry);
+ return new PackageElement(pkgHandle, entry);
+ }
+
+ /**
+ * Returns a package handle corresponding to the given source entry's package.
+ * The source entry may or may not be present.
+ */
+ protected IPackage packageFromSourceEntry(SourceEntry entry) {
+ IPath path = entry.getPath();
+ IPackage pkgHandle;
+
+ /* if it's a zip file */
+ String zipEntryFileName = entry.fZipEntryFileName;
+ if (zipEntryFileName != null) {
+ /* compute filename and package from zip name */
+ String zipEntryPath = entry.fZipEntryPath;
+ if (zipEntryPath == null) {
+ /* default unnamed package */
+ pkgHandle = defaultPackageForProject();
+ } else {
+ String pkgName = zipEntryPath.replace('/', '.');
+ pkgHandle = fDevelopmentContext.getImage().getPackageHandle(pkgName, false);
+ }
+ } else {
+ /* compute filename and package from element id */
+ IPath parent = path.removeLastSegments(1);
+ pkgHandle = fPathMap.packageHandleFromPath(parent);
+ }
+ return canonicalize(pkgHandle);
+ }
+
+ /**
+ * Stores the result of a compilation in the state tables
+ */
+ protected void putCompilationResult(ConvertedCompilationResult result) {
+ PackageElement unit = result.getPackageElement();
+
+ /* get source entry for result */
+ SourceEntry sEntry = getSourceEntry(unit);
+
+ /* record problems */
+ fProblemReporter.removeNonSyntaxErrors(sEntry);
+ IProblemDetail[] problems = result.getProblems();
+ for (int i = 0; i < problems.length; ++i) {
+ fProblemReporter.putProblem(sEntry, problems[i]);
+ }
+
+ /* This records the types actually contributed, */
+ /* to record in the dependency graph. */
+ TypeStructureEntry[] tsEntries = result.getTypes();
+ IType[] types = new IType[tsEntries.length];
+ int count = 0;
+
+ /* record type structure */
+ for (int i = 0; i < tsEntries.length; i++) {
+ TypeStructureEntry tsEntry = tsEntries[i];
+ IType typeHandle = tsEntry.getType();
+ // Sanity check before putting in table
+ TypeStructureEntry tsExisting =
+ (TypeStructureEntry) fPrincipalStructureTable.get(typeHandle);
+ if (tsExisting != null) {
+ if (!tsExisting.getSourceEntry().getFileName().equals(sEntry.getFileName())) {
+ // Same type provided by different files
+ String msg =
+ "Type "
+ + typeHandle.getName()
+ + " already provided by "
+ + tsExisting.getSourceEntry().getFileName();
+ ProblemDetailImpl problem = new ProblemDetailImpl(msg, sEntry);
+ fProblemReporter.putProblem(sEntry, problem);
+ // skip it
+ continue;
+ }
+ }
+
+ // Finally, put it in table.
+ fPrincipalStructureTable.put(typeHandle, tsEntry);
+ types[count++] = typeHandle;
+ }
+
+ /* Update the dependency graph. */
+ if (count < types.length) {
+ System.arraycopy(types, 0, types = new IType[count], 0, count);
+ }
+ fGraph.add(unit, types, result.getDependencies());
+ }
+
+ /**
+ * Stores the results of a compilation in the state tables
+ */
+ protected void putCompilationResults(ConvertedCompilationResult[] results) {
+ for (int i = 0; i < results.length; i++) {
+ putCompilationResult(results[i]);
+ }
+ }
+
+ /**
+ * Adds one source entry in the source element table
+ */
+ public void putSourceEntry(IPackage pkg, SourceEntry sourceEntry) {
+ this.fSourceElementTable.putSourceEntry(pkg, sourceEntry);
+ }
+
+ /**
+ * Reads the class path.
+ */
+ protected void readClassPath() {
+ try {
+ JavaProject jp = (JavaProject) getJavaProject();
+ fPackageFragmentRootsInClassPath = jp.getBuilderRoots(null);
+ fBinaryOutput =
+ new ProjectBinaryOutput(
+ getProject(),
+ jp.getOutputLocation(),
+ fDevelopmentContext);
+ } catch (JavaModelException e) {
+ throw internalException(e);
+ }
+ }
+
+ /**
+ * Reads the class path.
+ */
+ protected void readClassPath(IResourceDelta delta) {
+ try {
+ JavaProject jp = (JavaProject) getJavaProject();
+ fPackageFragmentRootsInClassPath = jp.getBuilderRoots(delta);
+ fBinaryOutput =
+ new ProjectBinaryOutput(
+ getProject(),
+ jp.getOutputLocation(),
+ fDevelopmentContext);
+ } catch (JavaModelException e) {
+ throw internalException(e);
+ }
+ }
+
+ /**
+ * Remove one source entry from the source element table
+ */
+ public void removeSourceEntry(IPackage pkg, IType handle, String fileName) {
+ this.fSourceElementTable.removeSourceEntry(pkg, fileName);
+ this.getPrincipalStructureTable().remove(handle);
+ }
+
+ protected void resetProject() {
+ // Remembers the name of the project before reseting it
+ if (fProjectName == null)
+ fProjectName = fProject.getName();
+ fProject = null;
+ }
+
+ /**
+ * This method recalculates the dependency info to refer to the source element
+ * each type came from. Stand-alone sources and binaries are represented by
+ * PackageElement objects, zips are represented by the IPath of the zip file,
+ * and namespaces by IPackage objects.
+ */
+ protected Vector resolveDependencies(
+ PackageElement resultUnit,
+ CompilationResult result) {
+ IPackage resultPackage = resultUnit.getPackage();
+ SourceEntry resultSourceEntry = getSourceEntry(resultUnit);
+ char[][] fileDependencies = result.getFileDependencies();
+ char[][] namespaceDependencies = result.getNamespaceDependencies();
+ Vector vSourceDeps = new Vector();
+ if (namespaceDependencies != null) {
+ for (int i = 0; i < namespaceDependencies.length; i++) {
+ String namespace = Util.toString(namespaceDependencies[i]);
+ if (namespace.length() == 0) {
+ IPackage defaultPkg = defaultPackageFor(resultUnit.getPackage());
+ if (defaultPkg != null && !vSourceDeps.contains(defaultPkg)) {
+ vSourceDeps.addElement(defaultPkg);
+ }
+ } else {
+ IPackage pkg =
+ fDevelopmentContext.getImage().getPackageHandle(namespace, false);
+ pkg = canonicalize(pkg);
+ if (!vSourceDeps.contains(pkg)) {
+ vSourceDeps.addElement(pkg);
+ }
+ }
+ }
+ }
+ if (!vSourceDeps.contains(resultPackage)) {
+ vSourceDeps.addElement(resultPackage);
+ }
+ if (!vSourceDeps.contains(fDevelopmentContext.getDefaultPackage())) {
+ vSourceDeps.addElement(fDevelopmentContext.getDefaultPackage());
+ }
+
+ /* do for each file dependency */
+ if (fileDependencies != null) {
+ for (int i = 0; i < fileDependencies.length; i++) {
+ if (fileDependencies[i] != null) {
+ SourceEntry sEntry =
+ SourceEntry.fromPathWithZipEntryName(Util.toString(fileDependencies[i]));
+ if (sEntry.fZipEntryFileName != null) {
+ IPath path = sEntry.getPath();
+ if (!vSourceDeps.contains(path)) {
+ vSourceDeps.addElement(path);
+ }
+ } else {
+ PackageElement element = packageElementFromSourceEntry(sEntry);
+ /* Make sure it's a valid ref. */
+ if (getSourceEntry(element) != null) {
+ if (!vSourceDeps.contains(element.getPackage())) {
+ vSourceDeps.addElement(element.getPackage());
+ }
+ vSourceDeps.addElement(element);
+ }
+ }
+ }
+ }
+ }
+ return vSourceDeps;
+ }
+
+ /**
+ * setBuildContext method comment.
+ */
+ protected void setBuildContext(IImageContext context) {
+ fBuildContext = context;
+ }
+
+ /**
+ * Sets the compiler options that were in effect when
+ * this state was built.
+ */
+ protected void setCompilerOptions(ConfigurableOption[] options) {
+ fCompilerOptions = options;
+ }
+
+ /**
+ * Sets the fingerprint for this state.
+ */
+ protected void setFingerprint(byte[] fp) {
+ fFingerprint = fp;
+ }
+
+ /**
+ * Sets the dependency graph for the state.
+ */
+ protected void setInternalDependencyGraph(DependencyGraph graph) {
+ fGraph = graph;
+ }
+
+ /**
+ * Sets the package map
+ */
+ protected void setPackageMap(PackageMap map) {
+ fPackageMap = map;
+ /* build the reverse index -- the path map */
+ fPathMap = new PathMap(fPackageMap);
+ }
+
+ /**
+ * Sets the path map
+ */
+ protected void setPathMap(PathMap map) {
+ fPathMap = map;
+ }
+
+ /**
+ * Sets the principal structure by package table.
+ */
+ protected void setPrincipalStructureByPackageTable(Hashtable table) {
+ fPrincipalStructureByPackageTable = table;
+ }
+
+ /**
+ * Sets the principal structure table.
+ */
+ protected void setPrincipalStructureTable(Hashtable table) {
+ fPrincipalStructureTable = table;
+ }
+
+ /**
+ * Sets the problem reporter.
+ */
+ protected void setProblemReporter(IProblemReporter problemReporter) {
+ fProblemReporter = problemReporter;
+ }
+
+ /**
+ * Sets the source element table.
+ */
+ protected void setSourceElementTable(SourceElementTable table) {
+ fSourceElementTable = table;
+ }
+
+ /**
+ * Returns a string representation of the receiver.
+ */
+ public String toString() {
+ return "StateImpl(" + fStateNumber + ")";
+ }
+
+ /**
+ * Returns the type handle for the given type name,
+ * relative to the referring type given by tsEntry.
+ * If typeName is unqualified, the resulting type is in
+ * the default package visible by tsEntry (which may not be
+ * the same package as tsEntry's).
+ */
+ protected IType typeNameToHandle(TypeStructureEntry tsEntry, String typeName) {
+ return typeNameToHandle(tsEntry.getType().getPackage(), typeName);
+ }
+
+ /**
+ * Returns the type handle for the given type name,
+ * relative to the referring package refPkg.
+ * If typeName is unqualified, the resulting type is in
+ * the default package visible by the referring package (which may not be
+ * the same as refPkg).
+ */
+ protected IType typeNameToHandle(IPackage refPkg, String typeName) {
+ int lastDot = typeName.lastIndexOf('.');
+ if (lastDot == -1) {
+ IPackage pkg = defaultPackageFor(refPkg);
+ if (pkg == null) {
+ // typeName is unqualified but there is no visible default package.
+ // Should not occur, but be resilient, and assume it's in the same package
+ // as tsEntry.
+ pkg = refPkg;
+ }
+ return pkg.getClassHandle(typeName);
+ }
+ String packageName = typeName.substring(0, lastDot);
+ String simpleName = typeName.substring(lastDot + 1);
+ if (!refPkg.isUnnamed() && refPkg.getName().equals(packageName)) {
+ return refPkg.getClassHandle(simpleName);
+ }
+ IPackage pkg =
+ fDevelopmentContext.getImage().getPackageHandle(packageName, false);
+ pkg = canonicalize(pkg);
+ return canonicalize(pkg.getClassHandle(simpleName));
+ }
+
+ /**
+ * Convert a type signature to a non-state-specific type handle.
+ */
+ protected IType typeSignatureToHandle(TypeStructureEntry tsEntry, String sig) {
+ int nestingDepth = 0;
+ int i = 0;
+ char c = sig.charAt(i);
+ while (c == '[') {
+ ++nestingDepth;
+ ++i;
+ c = sig.charAt(i);
+ }
+
+ /* if its a class */
+ IType elementType;
+ if (c == 'L') {
+ /* class or interface */
+ int semicolon = sig.indexOf(';', i + 1);
+ elementType = typeNameToHandle(tsEntry, sig.substring(i + 1, semicolon));
+ } else {
+ /* base type or invalid type name */
+ elementType = fDevelopmentContext.primitiveTypeFromTypeCode(c);
+ }
+ if (nestingDepth == 0) {
+ return elementType;
+ } else {
+ return new ArrayTypeHandleImpl((TypeImpl) elementType, nestingDepth);
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateSnap.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateSnap.java
new file mode 100644
index 0000000000..68b7da8d62
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateSnap.java
@@ -0,0 +1,106 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.IProject;
+
+import org.eclipse.jdt.internal.core.builder.*;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * This class takes and restores snapshots of a State.
+ *
+ * <p> What is saved:
+ * <dl>
+ * <dd> - the build context
+ * <dd> - information about package fragments
+ * <dd> - principal structure of all built types
+ * <dd> - any known problems
+ * <dd> - information needed to retrieve binaries from the binary output
+ * <dd> - dependency graph information
+ * </dl>
+ * <p> What is not saved:
+ * <dl>
+ * <dd> - the project
+ * <dd> - binaries
+ * </dl>
+ *
+ * <p> This class exists separate from <code>StateImpl</code>,
+ * making it is easy to support other saved formats of workspace.
+ *
+ * <p> Example usage:
+<code><pre>
+StateImpl state;
+DataOutput dout; // should be open
+new StateSnap().save(state, dout);
+...
+DataInput din;
+DevelopmentContext devctx;
+IProject project;
+StateImpl state = new StateSnap().restore(devctx, project, din);
+</pre></code>
+ * Note that reading in a state snapshot requires a project in hand.
+ * The project must correspond to the state's project at the time it was saved.
+ *
+ * @see StateImpl
+ */
+public class StateSnap {
+ /**
+ * Table from IType to IBuilderType, used only when reading.
+ */
+ Hashtable fBuilderTypeTable;
+
+ IPackage currentPackage;
+
+ static final int MAGIC = 0x53544154; // magic = "STAT"e
+ static final int VERSION5 = 0x0005;
+ static final int VERSION6 = 0x0006;
+ /**
+ * Creates a new StateSnap.
+ */
+ public StateSnap() {
+ super();
+ }
+
+ /**
+ * Reads and reconstructs a state from the given input stream.
+ */
+ public StateImpl read(
+ JavaDevelopmentContextImpl dc,
+ IProject project,
+ DataInputStream in)
+ throws IOException {
+
+ int magic = in.readInt();
+ int version = in.readShort();
+ if (magic != MAGIC) { // magic = "STAT"e
+ throw new IOException("Unrecognized format");
+ }
+
+ /* dispatch to appropriate reader */
+ switch (version) {
+ case VERSION5 :
+ return new StateSnapV5().read(dc, project, in);
+ case VERSION6 :
+ return new StateSnapV6().read(dc, project, in);
+ default :
+ throw new IOException("Unrecognized state format");
+ }
+ }
+
+ /**
+ * Saves key information about the given state
+ * to the given output stream. This snapshot can be used
+ * subsequently in reconstructing the state.
+ */
+ public void save(StateImpl state, DataOutputStream out) throws IOException {
+
+ /* current version for writing state is version 6 */
+ new StateSnapV6().save(state, out);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateSnapConstantPool.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateSnapConstantPool.java
new file mode 100644
index 0000000000..6b3c5baab1
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateSnapConstantPool.java
@@ -0,0 +1,673 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.internal.core.Assert;
+import org.eclipse.jdt.internal.core.builder.*;
+
+import java.io.*;
+
+class StateSnapConstantPool {
+ OrderedSet fSet;
+
+ /**
+ * The number of special pool entries at the beginning.
+ */
+ static final int NUM_SPECIAL = 11;
+ /**
+ * StateSnapConstantPool constructor comment.
+ */
+ StateSnapConstantPool(IDevelopmentContext dc) {
+ init(dc, 500);
+ }
+
+ /**
+ * Read a StateSnapConstantPool from an input stream.
+ */
+ StateSnapConstantPool(
+ IDevelopmentContext dc,
+ DataInputStream in,
+ StateSnapV5 snap)
+ throws IOException {
+ read(dc, in, snap);
+ }
+
+ /**
+ * Add a Number to the pool.
+ */
+ public void add(Number num) {
+ fSet.put(num);
+ }
+
+ /**
+ * Add a String to the pool.
+ */
+ public void add(String str) {
+ fSet.put(str);
+ }
+
+ /**
+ * Add an IPath to the pool.
+ */
+ public void add(IPath path) {
+ if (!fSet.includes(path)) {
+ // Special handling needed to preserve device
+ if (path.isRoot()) {
+ fSet.put(path.toString());
+ } else {
+ IPath parent = path.removeLastSegments(1);
+ add(parent);
+ fSet.put(path.lastSegment());
+ }
+ fSet.put(path);
+ }
+ }
+
+ /**
+ * Add an IPackage to the pool.
+ */
+ public void add(IHandle handle) {
+ switch (handle.kind()) {
+ case IHandle.K_JAVA_PACKAGE :
+ add((IPackage) handle);
+ break;
+ case IHandle.K_JAVA_TYPE :
+ add((IType) handle);
+ break;
+ case IHandle.K_JAVA_FIELD :
+ if (!fSet.includes(handle)) {
+ IField f = (IField) handle;
+ add(f.getDeclaringClass());
+ add(f.getName());
+ fSet.put(handle);
+ }
+ break;
+ case IHandle.K_JAVA_CONSTRUCTOR :
+ if (!fSet.includes(handle)) {
+ IConstructor c = (IConstructor) handle;
+ add(c.getDeclaringClass());
+ IType[] parms = c.getParameterTypes();
+ for (int i = 0; i < parms.length; ++i) {
+ add(parms[i]);
+ }
+ fSet.put(handle);
+ }
+ break;
+ case IHandle.K_JAVA_METHOD :
+ if (!fSet.includes(handle)) {
+ IMethod m = (IMethod) handle;
+ add(m.getDeclaringClass());
+ add(m.getName());
+ IType[] parms = m.getParameterTypes();
+ for (int i = 0; i < parms.length; ++i) {
+ add(parms[i]);
+ }
+ fSet.put(handle);
+ }
+ break;
+ case IHandle.K_JAVA_IMAGE :
+ // NOP
+ break;
+ default :
+ Assert.isTrue(false, "Unknown kind of handle");
+ }
+ }
+
+ /**
+ * Add a SourceEntry to the pool.
+ */
+ public void add(SourceEntry entry) {
+ Assert.isNotNull(
+ entry,
+ "Null SourceEntry being added to StateSnapConstantPool");
+ if (!fSet.includes(entry)) {
+ add(entry.getPath());
+ String zipEntryPath = entry.fZipEntryPath;
+ if (zipEntryPath != null) {
+ fSet.put(zipEntryPath);
+ }
+ String zipEntryFileName = entry.fZipEntryFileName;
+ if (zipEntryFileName != null) {
+ fSet.put(zipEntryFileName);
+ }
+ fSet.put(entry);
+ }
+ }
+
+ /**
+ * Add an IPackage to the pool.
+ */
+ public void add(IPackage pkg) {
+ if (!fSet.includes(pkg)) {
+ fSet.put(pkg.getName());
+ fSet.put(pkg);
+ }
+ }
+
+ /**
+ * Add an IType to the pool.
+ */
+ public void add(IType type) {
+ Assert.isTrue(!type.isStateSpecific());
+ if (type.isPrimitive()) {
+ return; // Already added
+ }
+ if (!fSet.includes(type)) {
+ if (type.isArray()) {
+ add(((ArrayTypeHandleImpl) type).getElementType());
+ } else {
+ ClassOrInterfaceHandleImpl cls = (ClassOrInterfaceHandleImpl) type;
+ add(cls.getPackage());
+ fSet.put(cls.getSimpleName());
+ }
+ fSet.put(type);
+ }
+ }
+
+ /**
+ * Returns the IHandle at the given index. It must not be null.
+ */
+ public IHandle getHandle(int index) throws IOException {
+ try {
+ IHandle result = (IHandle) fSet.get(index);
+ if (result == null) {
+ throw new IOException("Error in format");
+ }
+ return result;
+ } catch (ClassCastException e) {
+ throw new IOException("Error in format");
+ }
+ }
+
+ /**
+ * Returns the Object at the given index. It may be null.
+ */
+ public Object getObject(int index) throws IOException {
+ return fSet.get(index);
+ }
+
+ /**
+ * Returns the IPackage at the given index. It must not be null.
+ */
+ public IPackage getPackage(int index) throws IOException {
+ try {
+ IPackage result = (IPackage) fSet.get(index);
+ if (result == null) {
+ throw new IOException("Error in format");
+ }
+ return result;
+ } catch (ClassCastException e) {
+ throw new IOException("Error in format");
+ }
+ }
+
+ /**
+ * Returns the IPath at the given index. It must not be null.
+ */
+ public IPath getPath(int index) throws IOException {
+ try {
+ IPath result = (IPath) fSet.get(index);
+ if (result == null) {
+ throw new IOException("Error in format");
+ }
+ return result;
+ } catch (ClassCastException e) {
+ throw new IOException("Error in format");
+ }
+ }
+
+ /**
+ * Returns the SourceEntry at the given index. It must not be null.
+ */
+ public SourceEntry getSourceEntry(int index) throws IOException {
+ try {
+ SourceEntry result = (SourceEntry) fSet.get(index);
+ if (result == null) {
+ throw new IOException("Error in format");
+ }
+ return result;
+ } catch (ClassCastException e) {
+ throw new IOException("Error in format");
+ }
+ }
+
+ /**
+ * Returns the String at the given index. It must not be null.
+ */
+ public String getString(int index) throws IOException {
+ try {
+ String result = (String) fSet.get(index);
+ if (result == null) {
+ throw new IOException("Error in format");
+ }
+ return result;
+ } catch (ClassCastException e) {
+ throw new IOException("Error in format");
+ }
+ }
+
+ /**
+ * Returns the String at the given index. It may be null.
+ */
+ public String getStringOrNull(int index) throws IOException {
+ return index == 0 ? null : getString(index);
+ }
+
+ /**
+ * Returns the String or Number at the given index. It may be null.
+ */
+ public Object getStringOrNumber(int index) throws IOException {
+ if (index == 0) {
+ return null;
+ }
+ Object result = (Object) fSet.get(index);
+ if (result != null
+ && ((result instanceof Number) || (result instanceof String))) {
+ return result;
+ } else {
+ throw new IOException("Error in format");
+ }
+ }
+
+ /**
+ * Returns the IType at the given index. It must not be null.
+ */
+ public IType getType(int index) throws IOException {
+ try {
+ IType result = (IType) fSet.get(index);
+ if (result == null) {
+ throw new IOException("Error in format");
+ }
+ return result;
+ } catch (ClassCastException e) {
+ throw new IOException("Error in format");
+ }
+ }
+
+ /**
+ * For debugging.
+ */
+ public String histogram() {
+ int nStr = 0, nID = 0, nSE = 0, nH = 0, nN = 0;
+
+ int n = fSet.size();
+ for (int i = 10; i < n; ++i) {
+ Object obj = fSet.get(i);
+ if (obj instanceof String) {
+ ++nStr;
+ } else
+ if (obj instanceof IPath) {
+ ++nID;
+ } else
+ if (obj instanceof SourceEntry) {
+ ++nSE;
+ } else
+ if (obj instanceof IHandle) {
+ ++nH;
+ } else
+ if (obj instanceof Number) {
+ ++nN;
+ } else {
+ Assert.isTrue(false, "Unexpected pool item");
+ }
+ }
+ return "nStr="
+ + nStr
+ + ", nID="
+ + nID
+ + ", nSE="
+ + nSE
+ + ", nH="
+ + nH
+ + ",nN="
+ + nN;
+
+ }
+
+ /**
+ * Returns the index of the given object.
+ */
+ public int index(Object obj) {
+ if (obj == null) {
+ return 0;
+ }
+ try {
+ return fSet.index(obj);
+ } catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException(
+ "Internal error in state serialization. Expected object missing from constant pool: "
+ + obj);
+ }
+ }
+
+ /**
+ * Initialize the constant pool for the given DC and initial size estimate.
+ */
+ private void init(IDevelopmentContext dc, int initSize) {
+ // Set up constant pool with the special entries.
+ // Number of entries must correspond with NUM_SPECIAL
+ IImage image = dc.getImage();
+ fSet = new OrderedSet(initSize * 2 + 1, 0.5f);
+ fSet.put(new Object()); // 0: placeholder for null
+ fSet.put(image.booleanType()); // 1: type boolean
+ fSet.put(image.byteType()); // 2: type byte
+ fSet.put(image.charType()); // 3: type char
+ fSet.put(image.doubleType()); // 4: type double
+ fSet.put(image.floatType()); // 5: type float
+ fSet.put(image.intType()); // 6: type int
+ fSet.put(image.longType()); // 7: type long
+ fSet.put(image.shortType()); // 8: type short
+ fSet.put(image.voidType()); // 9: type void
+ fSet.put(image); // 10: image handle
+
+ }
+
+ /**
+ * Read a StateSnapConstantPool from an input stream.
+ */
+ private void read(IDevelopmentContext dc, DataInputStream in, StateSnapV5 snap)
+ throws IOException {
+ int n = in.readInt(); // Actual size of pool is (NUM_SPECIAL + n)
+ init(dc, n);
+
+ int i = NUM_SPECIAL;
+ for (int j = 0; j < n; ++j, ++i) {
+ int tag = in.readByte();
+ switch (tag) {
+ case 1 :
+ // String
+ String str = in.readUTF();
+ fSet.put(i, str);
+ break;
+ case 2 :
+ // IPath
+ int temp = in.readInt();
+ IPath parent = temp == 0 ? null : getPath(temp);
+ String elementName = getString(in.readInt());
+ if (parent == null) {
+ fSet.put(i, new Path(elementName));
+ } else {
+ fSet.put(i, parent.append(elementName));
+ }
+ break;
+ case 3 :
+ // SourceEntry
+ SourceEntry entry = snap.readSourceEntry(this, in);
+ fSet.put(i, entry);
+ break;
+ case 4 :
+ case 5 :
+ case 6 :
+ case 7 :
+ case 8 :
+ case 9 :
+ case 10 :
+ case 11 :
+ fSet.put(i, readHandle(dc, in, tag));
+ break;
+ case 12 :
+ case 13 :
+ case 14 :
+ case 15 :
+ fSet.put(i, readNumber(in, tag));
+ break;
+ default :
+ throw new IOException("Unexpected kind of pool item");
+ }
+ }
+ }
+
+ /**
+ * Internal -- Read an IHandle from an input stream into the pool.
+ */
+ private IHandle readHandle(IDevelopmentContext dc, DataInputStream in, int tag)
+ throws IOException {
+ switch (tag) {
+ case 4 :
+ {
+ // package
+ String name = getString(in.readInt());
+ boolean isUnnamed = in.readBoolean();
+ return dc.getImage().getPackageHandle(name, isUnnamed);
+ }
+ case 5 :
+ {
+ // primitive type
+ // Should not occur since primitive types are well known and not written
+ throw new IOException("Internal error");
+ }
+ case 6 :
+ {
+ // array type
+ TypeImpl elementType = (TypeImpl) getType(in.readInt());
+ int nesting = in.readByte() & 0xFF;
+ return new ArrayTypeHandleImpl(elementType, nesting);
+ }
+ case 7 :
+ {
+ // class or interface type
+ IPackage pkg = getPackage(in.readInt());
+ String simpleName = getString(in.readInt());
+ return pkg.getClassHandle(simpleName);
+ }
+ case 8 :
+ {
+ // method
+ IType declaringClass = getType(in.readInt());
+ if (declaringClass.isPrimitive() || declaringClass.isArray()) {
+ throw new IOException("Bad format");
+ }
+ String name = getString(in.readInt());
+ int numParams = in.readByte() & 0xFF;
+ IType[] params = new IType[numParams];
+ for (int i = 0; i < numParams; ++i) {
+ params[i] = getType(in.readInt());
+ }
+ return declaringClass.getMethodHandle(name, params);
+ }
+ case 9 :
+ {
+ // constructor
+ IType declaringClass = getType(in.readInt());
+ if (declaringClass.isPrimitive() || declaringClass.isArray()) {
+ throw new IOException("Bad format");
+ }
+ int numParams = in.readByte() & 0xFF;
+ IType[] params = new IType[numParams];
+ for (int i = 0; i < numParams; ++i) {
+ params[i] = getType(in.readInt());
+ }
+ return declaringClass.getConstructorHandle(params);
+ }
+ case 10 :
+ {
+ // field
+ IType declaringClass = getType(in.readInt());
+ if (declaringClass.isPrimitive() || declaringClass.isArray()) {
+ throw new IOException("Bad format");
+ }
+ String name = getString(in.readInt());
+ return declaringClass.getFieldHandle(name);
+ }
+ case 11 :
+ // image
+ return dc.getImage();
+ default :
+ throw new IOException("Unexpected kind of pool item");
+ }
+ }
+
+ /**
+ * Internal -- Read a Number from an input stream into the pool.
+ */
+ private Number readNumber(DataInputStream in, int tag) throws IOException {
+ switch (tag) {
+ case 12 :
+ // Integer
+ return new Integer(in.readInt());
+ case 13 :
+ // Long
+ return new Long(in.readLong());
+ case 14 :
+ // Float
+ return new Float(Float.intBitsToFloat(in.readInt()));
+ case 15 :
+ // Double
+ return new Double(Double.longBitsToDouble(in.readLong()));
+ default :
+ throw new IOException("Unexpeced kind of Number");
+ }
+ }
+
+ /**
+ * Returns the number of entries in the pool.
+ */
+ public int size() {
+ return fSet.size();
+ }
+
+ /**
+ * Write the constant pool to the given stream.
+ */
+ public void write(DataOutputStream out) throws IOException {
+ int n = fSet.size();
+ out.writeInt(n - NUM_SPECIAL);
+ for (int i = NUM_SPECIAL; i < n; ++i) {
+ Object obj = fSet.get(i);
+ if (obj instanceof String) {
+ out.writeByte(1);
+ out.writeUTF((String) obj);
+ } else
+ if (obj instanceof IHandle) {
+ writeHandle((IHandle) obj, out); // tags 4 through 11
+ } else
+ if (obj instanceof IPath) {
+ IPath path = (IPath) obj;
+ out.writeByte(2);
+ // Special handling needed to preserve device
+ if (path.isRoot()) {
+ out.writeInt(0);
+ out.writeInt(index(path.toString()));
+ } else {
+ IPath parent = path.removeLastSegments(1);
+ out.writeInt(index(parent));
+ out.writeInt(index(path.lastSegment()));
+ }
+ } else
+ if (obj instanceof SourceEntry) {
+ SourceEntry e = (SourceEntry) obj;
+ out.writeByte(3);
+ out.writeInt(index(e.getPath()));
+ out.writeInt(index(e.fZipEntryPath));
+ out.writeInt(index(e.fZipEntryFileName));
+ } else
+ if (obj instanceof Number) {
+ writeNumber((Number) obj, out); // tags 12 through 15
+ } else {
+ Assert.isTrue(false, "Unexpected pool item");
+ }
+ }
+ }
+
+ /**
+ * Write a handle to the given stream.
+ */
+ private void writeHandle(IHandle h, DataOutputStream out) throws IOException {
+ switch (h.kind()) {
+ case IHandle.K_JAVA_PACKAGE :
+ IPackage pkg = (IPackage) h;
+ out.writeByte(4);
+ out.writeInt(index(pkg.getName()));
+ out.writeBoolean(pkg.isUnnamed());
+ break;
+ case IHandle.K_JAVA_TYPE :
+ IType t = (IType) h;
+ if (t.isPrimitive()) {
+ // tag=5
+ // Primitive types should not show up since they are well known and are not written.
+ throw new IOException("Internal error");
+ } else
+ if (t.isArray()) {
+ ArrayTypeHandleImpl at = (ArrayTypeHandleImpl) t;
+ out.writeByte(6);
+ out.writeInt(index(at.getElementType()));
+ int nesting = at.getNestingDepth();
+ Assert.isTrue(nesting < 256);
+ out.writeByte(nesting);
+ } else {
+ Assert.isTrue(t instanceof ClassOrInterfaceHandleImpl);
+ out.writeByte(7);
+ out.writeInt(index(t.getPackage()));
+ out.writeInt(index(t.getSimpleName()));
+ }
+ break;
+ case IHandle.K_JAVA_METHOD :
+ {
+ IMethod m = (IMethod) h;
+ out.writeByte(8);
+ out.writeInt(index(m.getDeclaringClass()));
+ out.writeInt(index(m.getName()));
+ IType[] params = m.getParameterTypes();
+ Assert.isTrue(params.length < 256);
+ out.writeByte(params.length);
+ for (int j = 0; j < params.length; ++j) {
+ out.writeInt(index(params[j]));
+ }
+ break;
+ }
+ case IHandle.K_JAVA_CONSTRUCTOR :
+ {
+ IConstructor c = (IConstructor) h;
+ out.writeByte(9);
+ out.writeInt(index(c.getDeclaringClass()));
+ IType[] params = c.getParameterTypes();
+ Assert.isTrue(params.length < 256);
+ out.writeByte(params.length);
+ for (int j = 0; j < params.length; ++j) {
+ out.writeInt(index(params[j]));
+ }
+ break;
+ }
+ case IHandle.K_JAVA_FIELD :
+ IField f = (IField) h;
+ out.writeByte(10);
+ out.writeInt(index(f.getDeclaringClass()));
+ out.writeInt(index(f.getName()));
+ break;
+ case IHandle.K_JAVA_IMAGE :
+ out.writeByte(11);
+ break;
+ default :
+ Assert.isTrue(false, "Unknown handle type");
+ }
+ }
+
+ /**
+ * Write a Number to the given stream.
+ */
+ private void writeNumber(Number num, DataOutputStream out) throws IOException {
+ if (num instanceof Integer) {
+ out.writeByte(12);
+ out.writeInt(num.intValue());
+ } else
+ if (num instanceof Long) {
+ out.writeByte(13);
+ out.writeLong(num.longValue());
+ } else
+ if (num instanceof Float) {
+ out.writeByte(14);
+ out.writeInt(Float.floatToIntBits(num.floatValue()));
+ } else
+ if (num instanceof Double) {
+ out.writeByte(15);
+ out.writeLong(Double.doubleToLongBits(num.doubleValue()));
+ } else {
+ Assert.isTrue(false, "Unexpeced kind of Number");
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateSnapV5.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateSnapV5.java
new file mode 100644
index 0000000000..a6d141f424
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateSnapV5.java
@@ -0,0 +1,817 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.internal.core.Assert;
+import org.eclipse.jdt.internal.core.builder.*;
+import org.eclipse.jdt.internal.core.util.LookupTable;
+
+import java.io.*;
+import java.util.*;
+
+import org.eclipse.jdt.internal.core.JavaModelManager;
+
+/**
+ * StateSnap for state file format version 5.
+ * @see StateSnap
+ */
+public class StateSnapV5 {
+ /**
+ * Table from IType to IBuilderType, used only when reading.
+ */
+ Hashtable fBuilderTypeTable;
+ IPackage currentPackage;
+ static final int MAGIC = 0x53544154; // magic = "STAT"e
+ static final int VERSION = 0x0005;
+ /**
+ * Add pool constants for the build context.
+ */
+ protected void addBuildContextToPool(
+ IState state,
+ StateSnapConstantPool pool) {
+ IImageContext ctx = state.getBuildContext();
+ if (ctx != null) {
+ IPackage[] pkgs = ctx.getPackages();
+ for (int i = 0; i < pkgs.length; ++i) {
+ pool.add(pkgs[i]);
+ }
+ }
+ }
+
+ /**
+ * Add pool constants for the dependency graph.
+ */
+ protected void addDependencyGraphToPool(
+ StateImpl state,
+ StateSnapConstantPool pool) {
+ DependencyGraph graph = state.getInternalDependencyGraph();
+ for (Enumeration e = graph.getNodes(); e.hasMoreElements();) {
+ INode node = (INode) e.nextElement();
+ switch (node.getKind()) {
+ case INode.JCU_NODE :
+ JCUNode jcuNode = (JCUNode) node;
+ pool.add(state.getSourceEntry(jcuNode.getPackageElement()));
+ IType[] types = jcuNode.getTypes();
+ for (int i = 0; i < types.length; ++i) {
+ pool.add(types[i]);
+ }
+ break;
+ case INode.TYPE_NODE :
+ TypeNode typeNode = (TypeNode) node;
+ pool.add(state.getSourceEntry(typeNode.getPackageElement()));
+ break;
+ case INode.NAMESPACE_NODE :
+ pool.add(((NamespaceNode) node).getPackage());
+ break;
+ case INode.ZIP_NODE :
+ pool.add(((ZipNode) node).getZipFile());
+ break;
+ default :
+ Assert.isTrue(false, "Unexpected kind of node");
+ }
+ // Don't need to process node dependents here, since they're nodes as well
+ // and will have their info added to the pool above.
+ }
+ }
+
+ /**
+ * Add pool constants for the package map.
+ */
+ protected void addPackageMapToPool(
+ StateImpl state,
+ StateSnapConstantPool pool) {
+ PackageMap map = state.getPackageMap();
+ for (Enumeration e = map.getAllPackages(); e.hasMoreElements();) {
+ IPackage pkg = (IPackage) e.nextElement();
+ pool.add(pkg);
+ IPath[] fragments = map.getFragments(pkg);
+ for (int i = 0; i < fragments.length; ++i) {
+ pool.add(fragments[i]);
+ }
+ }
+ }
+
+ /**
+ * Add pool constants for the principal structure table.
+ */
+ protected void addPrincipalStructureTableToPool(
+ StateImpl state,
+ StateSnapConstantPool pool) {
+ Hashtable table = state.getPrincipalStructureTable();
+ for (Enumeration e = table.elements(); e.hasMoreElements();) {
+ TypeStructureEntry tsEntry = (TypeStructureEntry) e.nextElement();
+ addTypeStructureEntryToPool(tsEntry, pool);
+ }
+ }
+
+ /**
+ * Add pool constants for the problem table.
+ */
+ protected void addProblemTableToPool(
+ StateImpl state,
+ StateSnapConstantPool pool) {
+ IProblemReporter reporter = state.getProblemReporter();
+ if (reporter instanceof ProblemTable) {
+ for (Enumeration e = reporter.getAllProblems(); e.hasMoreElements();) {
+ addProblemToPool((ProblemDetailImpl) e.nextElement(), pool);
+ }
+ for (Enumeration e = reporter.getImageProblems(); e.hasMoreElements();) {
+ addProblemToPool((ProblemDetailImpl) e.nextElement(), pool);
+ }
+ }
+ }
+
+ /**
+ * Add pool constants for a problem.
+ */
+ protected void addProblemToPool(
+ ProblemDetailImpl pb,
+ StateSnapConstantPool pool) {
+ SourceEntry sourceEntry = pb.getSourceEntry();
+ if (sourceEntry != null) {
+ pool.add(sourceEntry);
+ }
+ pool.add(pb.getMessage());
+ }
+
+ /**
+ * Add pool constants for the source element table.
+ */
+ protected void addSourceElementTableToPool(
+ StateImpl state,
+ StateSnapConstantPool pool) {
+ SourceElementTable table = state.getSourceElementTable();
+ for (Enumeration e = state.getPackageMap().getAllPackages();
+ e.hasMoreElements();
+ ) {
+ IPackage pkg = (IPackage) e.nextElement();
+ // Assume pkg has already been added to the pool
+ LookupTable entryTable = table.getPackageTable(pkg);
+ for (Enumeration keys = entryTable.keys(); keys.hasMoreElements();) {
+ String fileName = (String) keys.nextElement();
+ pool.add(fileName);
+ SourceEntry sEntry = (SourceEntry) entryTable.get(fileName);
+ pool.add(sEntry);
+ }
+ }
+ }
+
+ /**
+ * Add pool constants for a type structure entry.
+ */
+ protected void addTypeStructureEntryToPool(
+ TypeStructureEntry tsEntry,
+ StateSnapConstantPool pool) {
+ pool.add(tsEntry.getType());
+ }
+
+ protected void badFormat() throws IOException {
+ throw new IOException("Bad format");
+ }
+
+ /**
+ * Check that the next section has the given name.
+ */
+ protected void checkSection(DataInputStream in, String name)
+ throws IOException {
+ String toCheck = in.readUTF();
+ if (!toCheck.equals(name))
+ badFormat();
+ }
+
+ protected PackageElement getPackageElement(
+ int entryNum,
+ PackageElement[] packageElements,
+ StateSnapConstantPool pool,
+ StateImpl state)
+ throws IOException {
+ if (packageElements[entryNum] == null) {
+ SourceEntry sourceEntry = pool.getSourceEntry(entryNum);
+ packageElements[entryNum] = state.packageElementFromSourceEntry(sourceEntry);
+ }
+ return packageElements[entryNum];
+ }
+
+ /**
+ * Reads and reconstructs a state from the given input stream.
+ */
+ public StateImpl read(
+ JavaDevelopmentContextImpl dc,
+ IProject project,
+ DataInputStream in)
+ throws IOException {
+
+ /* magic number and version have already been read */
+ StateImpl state = new StateImpl(dc, project);
+ int fingerprintLen = in.readShort();
+ byte[] fingerprint = new byte[fingerprintLen];
+ in.readFully(fingerprint);
+ state.setFingerprint(fingerprint);
+
+ // Read pool.
+ StateSnapConstantPool pool = new StateSnapConstantPool(dc, in, this);
+ state.readClassPath(); // Read classpath from the project
+ state.setBuildContext(readBuildContext(dc, pool, in));
+ PackageMap packageMap = readPackageMap(pool, in);
+ state.setPackageMap(packageMap);
+ state.setSourceElementTable(readSourceElementTable(pool, in));
+ state.setPrincipalStructureTable(readPrincipalStructureTable(pool, in, state));
+ state.setProblemReporter(readProblemReporter(project, pool, in));
+ state.setInternalDependencyGraph(readDependencyGraph(pool, in, state));
+ state.buildPrincipalStructureByPackageTable();
+
+ // We don't need the project any more
+ //state.resetProject();
+ return state;
+ }
+
+ /**
+ * Read the build context.
+ */
+ protected IImageContext readBuildContext(
+ IDevelopmentContext dc,
+ StateSnapConstantPool pool,
+ DataInputStream in)
+ throws IOException {
+ checkSection(in, "BuildContext");
+ int numPkgs = in.readInt();
+ if (numPkgs == -1) {
+ return null;
+ }
+ IPackage[] pkgs = new IPackage[numPkgs];
+ for (int i = 0; i < pkgs.length; ++i) {
+ pkgs[i] = pool.getPackage(in.readInt());
+ }
+ return dc.getImage().createImageContext(pkgs);
+ }
+
+ /**
+ * Read the dependency graph.
+ * The state is needed to create CompilationUnit objects from SourceEntry objects.
+ */
+ protected DependencyGraph readDependencyGraph(
+ StateSnapConstantPool pool,
+ DataInputStream in,
+ StateImpl state)
+ throws IOException {
+ checkSection(in, "DependencyGraph");
+ DependencyGraph graph = new DependencyGraph();
+
+ // Avoid creating package elements for each node and dependency.
+ PackageElement[] packageElements = new PackageElement[pool.size()];
+ while (in.readBoolean()) {
+ JCUNode jcu = null;
+ try {
+ int entryNum = in.readInt();
+ PackageElement unit = getPackageElement(entryNum, packageElements, pool, state);
+ jcu = (JCUNode) graph.getNodeFor(unit);
+ int numTypes = in.readByte() & 0xFF;
+ IType[] types = new IType[numTypes];
+ for (int j = 0; j < numTypes; ++j) {
+ types[j] = pool.getType(in.readInt());
+ }
+ jcu.setTypes(types);
+ } catch (ClassCastException e) { // the source entry should be a CU
+ badFormat();
+ }
+
+ // Read dependencies
+ int numDep = in.readShort() & 0xFFFF;
+ INode[] dependencies = new INode[numDep];
+ for (int j = 0; j < numDep; ++j) {
+ int entryNum = in.readInt();
+ Object obj = pool.getObject(entryNum);
+ if (obj instanceof SourceEntry) {
+ PackageElement unit = getPackageElement(entryNum, packageElements, pool, state);
+ dependencies[j] = graph.getNodeFor(unit);
+ } else
+ if (obj instanceof IPackage) {
+ dependencies[j] = graph.getNodeFor((IPackage) obj);
+ } else
+ if (obj instanceof IPath) {
+ dependencies[j] = graph.getNodeFor((IPath) obj);
+ } else {
+ // Unexpected referrent
+ badFormat();
+ }
+ }
+ jcu.setDependencies(dependencies);
+ }
+ skipAttributes(in);
+ graph.integrityCheck();
+ return graph;
+ }
+
+ /**
+ * Read the package map.
+ */
+ protected PackageMap readPackageMap(
+ StateSnapConstantPool pool,
+ DataInputStream in)
+ throws IOException {
+ checkSection(in, "PackageMap");
+ PackageMap map = new PackageMap();
+ int size = in.readInt();
+ for (int i = 0; i < size; ++i) {
+ IPackage pkg = pool.getPackage(in.readInt());
+ int numFragments = in.readShort() & 0xFFFF;
+ IPath[] fragments = new IPath[numFragments];
+ for (int j = 0; j < numFragments; ++j) {
+ fragments[j] = pool.getPath(in.readInt());
+ }
+ map.putFragments(pkg, fragments);
+ }
+ return map;
+ }
+
+ /**
+ * Read the principal structure table.
+ */
+ protected Hashtable readPrincipalStructureTable(
+ StateSnapConstantPool pool,
+ DataInputStream in,
+ StateImpl state)
+ throws IOException {
+ checkSection(in, "PrincipalStructureTable");
+ int numEntries = in.readInt();
+ Hashtable table = new Hashtable(numEntries * 2 + 1);
+ for (int i = 0; i < numEntries; ++i) {
+ TypeStructureEntry entry = readTypeStructureEntry(pool, in, state);
+ table.put(entry.getType(), entry);
+ }
+ return table;
+ }
+
+ /**
+ * Read a problem.
+ */
+ protected ProblemDetailImpl readProblem(
+ StateSnapConstantPool pool,
+ DataInputStream in)
+ throws IOException {
+ String msg = pool.getString(in.readInt());
+ int id = in.readInt();
+ int severity = in.readInt();
+ int temp = in.readInt();
+ SourceEntry sourceEntry = (temp == 0) ? null : pool.getSourceEntry(temp);
+ int startPos = in.readInt();
+ int endPos = in.readInt();
+ int lineNumber = in.readInt();
+ skipAttributes(in);
+ return new ProblemDetailImpl(
+ msg,
+ id,
+ severity,
+ sourceEntry,
+ startPos,
+ endPos,
+ lineNumber);
+ }
+
+ /**
+ * Read the problem reporter.
+ */
+ protected IProblemReporter readProblemReporter(
+ IProject project,
+ StateSnapConstantPool pool,
+ DataInputStream in)
+ throws IOException {
+ checkSection(in, "Problems");
+ IProblemReporter reporter = null;
+ boolean isProblemTable = in.readBoolean();
+ if (isProblemTable) {
+ reporter = new ProblemTable();
+ int numProblems = in.readInt();
+ for (int i = 0; i < numProblems; ++i) {
+ ProblemDetailImpl pb = readProblem(pool, in);
+ reporter.putProblem(pb.getSourceEntry(), pb);
+ }
+ } else {
+ String className = in.readUTF();
+ Class clazz = null;
+ try {
+ clazz = Class.forName(className);
+ } catch (ClassNotFoundException e) {
+ throw new IOException("Class " + className + " was not found.");
+ }
+ try {
+ reporter = (IProblemReporter) clazz.newInstance();
+ } catch (InstantiationException e) {
+ throw new IOException("Could not instanciate " + clazz.getName());
+ } catch (IllegalAccessException e) {
+ throw new IOException("Could not instanciate " + clazz.getName());
+ }
+ reporter.initialize(
+ project,
+ JavaModelManager.getJavaModelManager().getDevelopmentContext(project));
+ }
+ return reporter;
+ }
+
+ /**
+ * Read the source element table.
+ */
+ protected SourceElementTable readSourceElementTable(
+ StateSnapConstantPool pool,
+ DataInputStream in)
+ throws IOException {
+ checkSection(in, "SourceElementTable");
+ SourceElementTable table = new SourceElementTable();
+ int numPackages = in.readInt();
+ for (int i = 0; i < numPackages; ++i) {
+ IPackage pkg = pool.getPackage(in.readInt());
+ int numEntries = in.readInt();
+ LookupTable entryTable = new LookupTable(numEntries);
+ for (int j = 0; j < numEntries; ++j) {
+ String fileName = pool.getString(in.readInt());
+ SourceEntry sEntry = pool.getSourceEntry(in.readInt());
+ entryTable.put(fileName, sEntry);
+ }
+ table.putPackageTable(pkg, entryTable);
+ }
+ return table;
+ }
+
+ /**
+ * Read the next source entry.
+ */
+ protected SourceEntry readSourceEntry(
+ StateSnapConstantPool pool,
+ DataInputStream in)
+ throws IOException {
+ IPath path = pool.getPath(in.readInt());
+ String zipEntryName = pool.getStringOrNull(in.readInt());
+ String zipEntryPath = null, zipEntryFileName = null;
+ if (zipEntryName != null) {
+ int pos = zipEntryName.lastIndexOf('/');
+ if (pos != -1) {
+ zipEntryPath = zipEntryName.substring(0, pos);
+ zipEntryFileName = zipEntryName.substring(pos + 1);
+ } else {
+ zipEntryPath = null;
+ zipEntryFileName = zipEntryName;
+ }
+ }
+ return new SourceEntry(path, zipEntryPath, zipEntryFileName);
+ }
+
+ /**
+ * Read a type handle.
+ * Allow null if allowNull is true.
+ */
+ IType readTypeHandle(
+ StateSnapConstantPool pool,
+ DataInputStream in,
+ boolean allowNull)
+ throws IOException {
+ int index = in.readInt();
+ if (index == 0) {
+ if (!allowNull)
+ badFormat();
+ return null;
+ }
+ return pool.getType(index);
+ }
+
+ /**
+ * Read a class or interface type handle and return its name.
+ * Allow null if allowNull is true.
+ */
+ String readTypeHandleAsName(
+ StateSnapConstantPool pool,
+ DataInputStream in,
+ boolean allowNull)
+ throws IOException {
+ IType typeHandle = readTypeHandle(pool, in, allowNull);
+ if (typeHandle == null) {
+ if (!allowNull)
+ badFormat();
+ return null;
+ }
+ Assert.isTrue(!typeHandle.isPrimitive() && !typeHandle.isArray());
+ // must not be a class or interface handle
+ return typeHandle.getName(); //.intern(); // intern it
+ }
+
+ /**
+ * Read a class or interface type handle and return its name.
+ * Allow null if allowNull is true.
+ */
+ String readTypeHandleAsSignature(
+ StateSnapConstantPool pool,
+ DataInputStream in)
+ throws IOException {
+ IType typeHandle = readTypeHandle(pool, in, false);
+ return ((TypeImpl) typeHandle).getVMSignature(); //.intern(); // intern it
+ }
+
+ /**
+ * Read a type structure entry.
+ */
+ protected TypeStructureEntry readTypeStructureEntry(
+ StateSnapConstantPool pool,
+ DataInputStream in,
+ StateImpl state)
+ throws IOException {
+ SourceEntry sEntry = pool.getSourceEntry(in.readInt());
+ IType type = readTypeHandle(pool, in, false);
+ return new TypeStructureEntry(sEntry, type);
+ }
+
+ /**
+ * Saves key information about the given state
+ * to the given output stream. This snapshot can be used
+ * subsequently in reconstructing the state.
+ */
+ public void save(StateImpl state, DataOutputStream out) throws IOException {
+
+ // Build up pool.
+ IDevelopmentContext dc = state.getDevelopmentContext();
+ StateSnapConstantPool pool = new StateSnapConstantPool(dc);
+ addBuildContextToPool(state, pool);
+ addPackageMapToPool(state, pool);
+ addSourceElementTableToPool(state, pool);
+ addPrincipalStructureTableToPool(state, pool);
+ addProblemTableToPool(state, pool);
+ addDependencyGraphToPool(state, pool);
+
+ // Write all.
+ out.writeInt(MAGIC);
+ out.writeShort(VERSION);
+
+ byte[] fingerprint = state.getFingerprint();
+ // regression test for 1F9M2KH: RQIB:ALL - Problem saving incrementally built state
+ Assert.isNotNull(fingerprint);
+ out.writeShort(fingerprint.length);
+ out.write(fingerprint);
+
+ pool.write(out);
+ writeBuildContext(state, pool, out);
+ writePackageMap(state, pool, out);
+ writeSourceElementTable(state, pool, out);
+ writePrincipalStructureTable(state, pool, out);
+ writeProblemReporter(state, pool, out);
+ writeDependencyGraph(state, pool, out);
+
+ }
+
+ /**
+ * Skip over the attributes on read.
+ */
+ protected void skipAttributes(DataInputStream in) throws IOException {
+ int numAttributes = in.readShort() & 0xFFFF;
+ for (int i = 0; i < numAttributes; ++i) {
+ int nameIndex = in.readInt();
+ int len = in.readShort() & 0xFFFF;
+ in.skipBytes(len);
+ }
+ }
+
+ /**
+ * Write the build context.
+ */
+ protected void writeBuildContext(
+ StateImpl state,
+ StateSnapConstantPool pool,
+ DataOutputStream out)
+ throws IOException {
+ out.writeUTF("BuildContext");
+ IImageContext ctx = state.getBuildContext();
+ if (ctx == null) {
+ out.writeInt(-1);
+ } else {
+ IPackage[] pkgs = ctx.getPackages();
+ out.writeInt(pkgs.length);
+ for (int i = 0; i < pkgs.length; ++i) {
+ out.writeInt(pool.index(pkgs[i]));
+ }
+ }
+ }
+
+ /**
+ * Write the dependency graph.
+ */
+ protected void writeDependencyGraph(
+ StateImpl state,
+ StateSnapConstantPool pool,
+ DataOutputStream out)
+ throws IOException {
+ out.writeUTF("DependencyGraph");
+ DependencyGraph graph = state.getInternalDependencyGraph();
+ graph.integrityCheck();
+ /**
+ * We only care about serializing JCU nodes, since they
+ * are the only nodes with dependency information. All
+ * other nodes will be serialized indirectly as dependencies
+ * of JCU nodes.
+ * Do we care about Type/Zip/Namespace nodes that have no dependents???
+ */
+ for (Enumeration e = graph.getJCUNodes(); e.hasMoreElements();) {
+ JCUNode jcu = (JCUNode) e.nextElement();
+ out.writeBoolean(true);
+ SourceEntry sEntry = state.getSourceEntry(jcu.getPackageElement());
+ if (sEntry == null) {
+ System.out.println(
+ "Warning: StatSnap: Attempt to serialize dependency graph node for missing JCU: "
+ + jcu.getPackageElement()
+ + ". Skipping...");
+ } else {
+ Assert.isNotNull(sEntry);
+ out.writeInt(pool.index(sEntry));
+ IType[] types = jcu.getTypes();
+ Assert.isTrue(types.length < 256);
+ out.writeByte(types.length);
+ for (int i = 0; i < types.length; ++i) {
+ out.writeInt(pool.index(types[i]));
+ }
+
+ // Write dependencies
+ INode[] dependencies = jcu.getDependencies();
+ int numDep = dependencies.length;
+ Assert.isTrue(numDep < 65536);
+ out.writeShort(numDep);
+ for (int i = 0; i < numDep; ++i) {
+ INode dep = dependencies[i];
+ switch (dep.getKind()) {
+ case INode.JCU_NODE :
+ {
+ PackageElement element = ((JCUNode) dep).getPackageElement();
+ SourceEntry depEntry = state.getSourceEntry(element);
+ out.writeInt(pool.index(depEntry));
+ break;
+ }
+ case INode.TYPE_NODE :
+ {
+ PackageElement element = ((TypeNode) dep).getPackageElement();
+ SourceEntry depEntry = state.getSourceEntry(element);
+ out.writeInt(pool.index(depEntry));
+ break;
+ }
+ case INode.NAMESPACE_NODE :
+ {
+ IPackage pkg = ((NamespaceNode) dep).getPackage();
+ out.writeInt(pool.index(pkg));
+ break;
+ }
+ case INode.ZIP_NODE :
+ {
+ IPath path = ((ZipNode) dep).getZipFile();
+ out.writeInt(pool.index(path));
+ break;
+ }
+ default :
+ badFormat();
+ }
+ }
+ }
+ }
+ out.writeBoolean(false);
+ writeEmptyAttributes(out);
+ }
+
+ /**
+ * Write an empty set of attributes.
+ */
+ protected void writeEmptyAttributes(DataOutputStream out) throws IOException {
+ out.writeShort(0);
+ }
+
+ /**
+ * Write the package map.
+ */
+ protected void writePackageMap(
+ StateImpl state,
+ StateSnapConstantPool pool,
+ DataOutputStream out)
+ throws IOException {
+ out.writeUTF("PackageMap");
+ PackageMap map = state.getPackageMap();
+ out.writeInt(map.size());
+ int count = 0;
+ for (Enumeration e = map.getAllPackages(); e.hasMoreElements();) {
+ ++count;
+ IPackage pkg = (IPackage) e.nextElement();
+ IPath[] fragments = map.getFragments(pkg);
+ out.writeInt(pool.index(pkg));
+ out.writeShort(fragments.length);
+ for (int i = 0; i < fragments.length; ++i) {
+ out.writeInt(pool.index(fragments[i]));
+ }
+ }
+ Assert.isTrue(count == map.size()); // Sanity check
+ }
+
+ /**
+ * Write the principal structure table.
+ */
+ protected void writePrincipalStructureTable(
+ StateImpl state,
+ StateSnapConstantPool pool,
+ DataOutputStream out)
+ throws IOException {
+ out.writeUTF("PrincipalStructureTable");
+ Hashtable table = state.getPrincipalStructureTable();
+ int num = table.size();
+ out.writeInt(num);
+ int count = 0;
+ for (Enumeration e = table.elements(); e.hasMoreElements();) {
+ ++count;
+ TypeStructureEntry tsEntry = (TypeStructureEntry) e.nextElement();
+ writeTypeStructureEntry(tsEntry, pool, out);
+ }
+ Assert.isTrue(count == num); // Sanity check
+ }
+
+ /**
+ * Write a problem.
+ */
+ protected void writeProblem(
+ ProblemDetailImpl pb,
+ StateSnapConstantPool pool,
+ DataOutputStream out)
+ throws IOException {
+ out.writeInt(pool.index(pb.getMessage()));
+ out.writeInt(pb.getID());
+ out.writeInt(pb.getSeverity());
+ out.writeInt(pool.index(pb.getSourceEntry()));
+ out.writeInt(pb.getStartPos());
+ out.writeInt(pb.getEndPos());
+ out.writeInt(pb.getLineNumber());
+ writeEmptyAttributes(out);
+ }
+
+ /**
+ * Write the problem reporter.
+ */
+ protected void writeProblemReporter(
+ StateImpl state,
+ StateSnapConstantPool pool,
+ DataOutputStream out)
+ throws IOException {
+ out.writeUTF("Problems");
+ IProblemReporter reporter = state.getProblemReporter();
+ if (reporter instanceof ProblemTable) {
+ out.writeBoolean(true);
+ Vector problems = new Vector();
+ for (Enumeration e = reporter.getAllProblems(); e.hasMoreElements();) {
+ problems.addElement(e.nextElement());
+ }
+ for (Enumeration e = reporter.getImageProblems(); e.hasMoreElements();) {
+ problems.addElement(e.nextElement());
+ }
+ out.writeInt(problems.size());
+ for (Enumeration e = problems.elements(); e.hasMoreElements();) {
+ writeProblem((ProblemDetailImpl) e.nextElement(), pool, out);
+ }
+ } else {
+ out.writeBoolean(false);
+ out.writeUTF(reporter.getClass().getName());
+ }
+ }
+
+ /**
+ * Write the source element table.
+ */
+ protected void writeSourceElementTable(
+ StateImpl state,
+ StateSnapConstantPool pool,
+ DataOutputStream out)
+ throws IOException {
+ out.writeUTF("SourceElementTable");
+ SourceElementTable table = state.getSourceElementTable();
+ int num = table.numPackages();
+ out.writeInt(num);
+ for (Enumeration e = state.getPackageMap().getAllPackages();
+ e.hasMoreElements();
+ ) {
+ IPackage pkg = (IPackage) e.nextElement();
+ out.writeInt(pool.index(pkg));
+ LookupTable entryTable = table.getPackageTable(pkg);
+ out.writeInt(entryTable.size());
+ for (Enumeration keys = entryTable.keys(); keys.hasMoreElements();) {
+ String fileName = (String) keys.nextElement();
+ out.writeInt(pool.index(fileName));
+ SourceEntry sEntry = (SourceEntry) entryTable.get(fileName);
+ out.writeInt(pool.index(sEntry));
+ }
+ }
+ }
+
+ /**
+ * Write a type structure entry.
+ */
+ protected void writeTypeStructureEntry(
+ TypeStructureEntry tsEntry,
+ StateSnapConstantPool pool,
+ DataOutputStream out)
+ throws IOException {
+ out.writeInt(pool.index(tsEntry.getSourceEntry()));
+ out.writeInt(pool.index(tsEntry.getType()));
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateSnapV6.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateSnapV6.java
new file mode 100644
index 0000000000..055a3e7e02
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateSnapV6.java
@@ -0,0 +1,66 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.jdt.internal.core.Assert;
+import org.eclipse.jdt.internal.core.builder.*;
+import java.io.*;
+
+/**
+ * StateSnap for state file format version 6.
+ * @see StateSnap
+ */
+public class StateSnapV6 extends StateSnapV5 {
+ /**
+ * Read the next source entry.
+ */
+ protected SourceEntry readSourceEntry(
+ StateSnapConstantPool pool,
+ DataInputStream in)
+ throws IOException {
+ IPath path = pool.getPath(in.readInt());
+ String zipEntryPath = pool.getStringOrNull(in.readInt());
+ String zipEntryFileName = pool.getStringOrNull(in.readInt());
+ return new SourceEntry(path, zipEntryPath, zipEntryFileName);
+ }
+
+ /**
+ * Saves key information about the given state
+ * to the given output stream. This snapshot can be used
+ * subsequently in reconstructing the state.
+ */
+ public void save(StateImpl state, DataOutputStream out) throws IOException {
+
+ // Build up pool.
+ IDevelopmentContext dc = state.getDevelopmentContext();
+ StateSnapConstantPool pool = new StateSnapConstantPool(dc);
+ addBuildContextToPool(state, pool);
+ addPackageMapToPool(state, pool);
+ addSourceElementTableToPool(state, pool);
+ addPrincipalStructureTableToPool(state, pool);
+ addProblemTableToPool(state, pool);
+ addDependencyGraphToPool(state, pool);
+
+ // Write all.
+ out.writeInt(MAGIC);
+ out.writeShort(StateSnap.VERSION6);
+
+ byte[] fingerprint = state.getFingerprint();
+ // regression test for 1F9M2KH: RQIB:ALL - Problem saving incrementally built state
+ Assert.isNotNull(fingerprint);
+ out.writeShort(fingerprint.length);
+ out.write(fingerprint);
+
+ pool.write(out);
+ writeBuildContext(state, pool, out);
+ writePackageMap(state, pool, out);
+ writeSourceElementTable(state, pool, out);
+ writePrincipalStructureTable(state, pool, out);
+ writeProblemReporter(state, pool, out);
+ writeDependencyGraph(state, pool, out);
+
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateSpecificHandleImpl.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateSpecificHandleImpl.java
new file mode 100644
index 0000000000..ec386596e5
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateSpecificHandleImpl.java
@@ -0,0 +1,69 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.builder.IHandle;
+import org.eclipse.jdt.internal.core.builder.IState;
+import org.eclipse.jdt.internal.core.builder.IDevelopmentContext;
+
+/**
+ * The root of the State Specific Handle implementation hierarchy.
+ */
+public abstract class StateSpecificHandleImpl implements IHandle {
+ StateImpl fState; // The state
+ //NonStateSpecificHandleImpl fHandle; //Put this in the subclasses
+ /**
+ * Returns whether the receiver and anObject have the same handle and
+ * same wrapped object; i.e., same states and objects.
+ */
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof StateSpecificHandleImpl))
+ return false;
+
+ StateSpecificHandleImpl ssh = (StateSpecificHandleImpl) o;
+ return nonStateSpecific().equals(ssh.nonStateSpecific())
+ && fState.equals(ssh.fState);
+ }
+
+ public IDevelopmentContext getDevelopmentContext() {
+ return fState.getDevelopmentContext();
+ }
+
+ public IState getState() {
+ return fState;
+ }
+
+ public int hashCode() {
+ return nonStateSpecific().hashCode();
+ }
+
+ public IHandle inState(IState state) {
+ throw new org.eclipse.jdt.internal.core.builder.StateSpecificException();
+ }
+
+ public boolean isFictional() {
+ return false;
+ }
+
+ public abstract boolean isPresent();
+ public boolean isStateSpecific() {
+ return true;
+ }
+
+ public int kind() {
+ return nonStateSpecific().kind();
+ }
+
+ /**
+ * Return the non state specific handle associated with this handle
+ */
+ public abstract IHandle nonStateSpecific();
+ public String toString() {
+ return nonStateSpecific().toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateTables.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateTables.java
new file mode 100644
index 0000000000..accc9bfdeb
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/StateTables.java
@@ -0,0 +1,14 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+/**
+ * This class is just used for organizing the classes that make up the state
+ * tables and their various entries. Ideally, all of these could be nested types
+ * within StateImpl, but unfortunately that would look ugly and would be difficult
+ * to work with.
+ */
+class StateTables implements Cloneable {
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeCollaboratorIndictment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeCollaboratorIndictment.java
new file mode 100644
index 0000000000..4772d8d5e6
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeCollaboratorIndictment.java
@@ -0,0 +1,27 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+class TypeCollaboratorIndictment extends Indictment {
+ /**
+ * Creates a new TypeCollaboratorIndictment.
+ */
+ protected TypeCollaboratorIndictment(char[] name) {
+ super(name);
+ }
+
+ /**
+ * Returns what kind of indictment this is
+ */
+ public int getKind() {
+ return K_TYPE;
+ }
+
+ /**
+ * Returns a string representation of this class. For debugging purposes
+ * only (NON-NLS).
+ */
+ public String toString() {
+ // don't use + with char[]
+ return new StringBuffer("TypeIndictment(").append(fName).append(")").toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeHierarchyIndictment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeHierarchyIndictment.java
new file mode 100644
index 0000000000..02d0849260
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeHierarchyIndictment.java
@@ -0,0 +1,30 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+public class TypeHierarchyIndictment extends Indictment {
+ /**
+ * Creates a new TypeHierarchyIndictment.
+ */
+ protected TypeHierarchyIndictment(char[] name) {
+ super(name);
+ }
+
+ /**
+ * Returns what kind of indictment this is
+ */
+ public int getKind() {
+ return K_HIERARCHY;
+ }
+
+ /**
+ * Returns a string representation of this class. For debugging purposes
+ * only (NON-NLS).
+ */
+ public String toString() {
+ // don't use + with char[]
+ return new StringBuffer("TypeHierarchyIndictment(")
+ .append(fName)
+ .append(")")
+ .toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeImpl.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeImpl.java
new file mode 100644
index 0000000000..929e61f827
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeImpl.java
@@ -0,0 +1,526 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.Assert;
+import org.eclipse.jdt.internal.core.builder.*;
+import org.eclipse.jdt.internal.core.Util;
+
+public abstract class TypeImpl
+ extends NonStateSpecificHandleImpl
+ implements IType {
+ public static Util.Comparer COMPARER = new Util.Comparer() {
+ public int compare(Object a, Object b) {
+ IType typeA = null, typeB = null;
+ try {
+ typeA = (IType) a;
+ typeB = (IType) b;
+ } catch (ClassCastException e) {
+ Assert.isTrue(false, "Should only be comparing ITypes");
+ }
+ return typeA.getName().compareTo(typeB.getName());
+ }
+ };
+
+ /**
+ * Appends the signature for this type to the StringBuffer
+ * If includeUnnamed is true, then the identifiers for unnamed packages
+ * are included, preceded by '$'. Otherwise, they are excluded.
+ */
+ abstract void appendSignature(StringBuffer sb, boolean includeUnnamed);
+ /**
+ * Appends the VM signature of the type to the StringBuffer.
+ */
+ abstract void appendVMSignature(StringBuffer sb);
+ /**
+ * Returns a Type object representing an array type with
+ * the type represented by this object as its component type.
+ * This is a handle-only method.
+ */
+ public org.eclipse.jdt.internal.core.builder.IType getArrayHandle() {
+ return new ArrayTypeHandleImpl(this, 1);
+ }
+
+ /**
+ * If this class represents an array type, returns the Type
+ * object representing the component type of the array; otherwise
+ * returns null. The component type of an array may itself be
+ * an array type.
+ * This is a handle-only method.
+ */
+ public org.eclipse.jdt.internal.core.builder.IType getComponentType() {
+ return null;
+ }
+
+ /**
+ * Returns a Constructor object that represents the specified
+ * constructor of the class represented by this object.
+ * The parameterTypes parameter is an array of Type objects that
+ * identify the constructor's formal parameter types, in declared
+ * order.
+ * Returns null if this type does not represent a class or interface.
+ * This is a handle-only method; the specified constructor may
+ * or may not actually be present in the class or interface.
+ */
+ public IConstructor getConstructorHandle(IType[] parameterTypes) {
+ return null;
+ }
+
+ /**
+ * @see IType#getCRC
+ */
+ public int getCRC() throws NotPresentException {
+ return 0;
+ }
+
+ /**
+ * Returns an array of Type objects representing all the classes
+ * and interfaces declared as members of the class represented by
+ * this object. This includes public, protected, default
+ * (package) access, and private classes and interfaces declared
+ * by the class, but excludes inherited classes and interfaces.
+ * Returns an array of length 0 if the class declares no classes
+ * or interfaces as members, or if this object represents an
+ * array type or primitive type.
+ * The resulting Types are in no particular order.
+ */
+ public IType[] getDeclaredClasses() throws NotPresentException {
+ return new IType[0];
+ }
+
+ /**
+ * Returns an array of Constructor objects representing all the
+ * constructors declared by the class represented by this
+ * object. These are public, protected, default (package) access,
+ * and private constructors. Returns an array of length 0 if this
+ * object represents an interface, an array type or a primitive type.
+ * The resulting Constructors are in no particular order.
+ */
+ public IConstructor[] getDeclaredConstructors() throws NotPresentException {
+ return new IConstructor[0];
+ }
+
+ /**
+ * Returns an array of Field objects representing all the fields
+ * declared by the class or interface represented by this
+ * object. This includes public, protected, default (package)
+ * access, and private fields, but excludes inherited
+ * fields. Returns an array of length 0 if the class or interface
+ * declares no fields, or if this object represents a
+ * primitive type or an array type (the implicit <code>length</code>
+ * field of array types is not considered to be a declared field).
+ * The resulting Fields are in no particular order.
+ */
+ public IField[] getDeclaredFields() throws NotPresentException {
+ return new IField[0];
+ }
+
+ /**
+ * Returns an array of Method objects representing all the methods
+ * declared by the class or interface represented by this
+ * object. This includes public, protected, default (package)
+ * access, and private methods, but excludes inherited
+ * methods. Returns an array of length 0 if the class or interface
+ * declares no methods, or if this object represents an
+ * array type or primitive type.
+ * The resulting Methods are in no particular order.
+ */
+ public IMethod[] getDeclaredMethods() throws NotPresentException {
+ return new IMethod[0];
+ }
+
+ /**
+ * Returns the declared Java language modifiers, as specified in the declaration
+ * of this class or interface, encoded in an integer.
+ * The modifiers consist of the Java Virtual Machine's constants
+ * for public, protected, private, and final; they should be decoded
+ * using the methods of class Modifier.
+ * The result may not correspond to the modifiers in the compiled
+ * binary, since the compiler may change them (in particular,
+ * for inner classes). The <code>getModifiers()</code>
+ * method should be used if the compiled modifiers are needed.
+ * Returns 0 if this type does not represent a class or interface.
+ *
+ * <p>The modifier encodings are defined in <em>The Java Virtual
+ * Machine Specification</em>, table 4.1.
+ */
+ public int getDeclaredModifiers() throws NotPresentException {
+ return 0;
+ }
+
+ /**
+ * Returns the declared name of the class or interface represented
+ * by this object, as a String.
+ * The name is the simple, unqualified name used in the source code.
+ * If this represents an inner class, it does not include the names
+ * of any containing classes.
+ * If this represents an anonymous class, it returns a String of length 0.
+ * If this does not represent a class or interface, it returns
+ * a String of length 0.
+ */
+ public String getDeclaredName() throws NotPresentException {
+ return "";
+ }
+
+ /**
+ * If the class or interface represented by this Type object is
+ * a member of another class or interface (i.e. it is a nested class),
+ * this returns the Type object representing the class or interface
+ * of which it is a member (its <em>declaring class</em>).
+ * If this class or interface is a local class, returns the Type
+ * object representing the class containing the member in which
+ * this class is declared.
+ * Returns null if this class or interface is not a nested class,
+ * or if this type does not represent a class or interface.
+ */
+ public IType getDeclaringClass() {
+ return null;
+ }
+
+ /**
+ * Returns a Field object that represents the specified
+ * member field of the class or interface represented
+ * by this object. The name parameter is a String specifying
+ * the simple name of the desired field.
+ * Returns null if this type does not represent a class or interface.
+ * This is a handle-only method; the specified field may
+ * or may not actually be present in the class or interface.
+ */
+ public IField getFieldHandle(String name) {
+ return null;
+ }
+
+ /**
+ * Returns an array of Type objects representing the
+ * classes in the given ImageContext which directly implement this interface.
+ * A class is said to directly implement this interface if the interface
+ * appears in the <code>implements</code> clause of the class's declaration.
+ * Although all array types are considered to implement the <code>Cloneable</code>
+ * interface, this method never returns array types, only class types.
+ * Returns an array of length 0 if this object does not represent
+ * an interface.
+ * The resulting Types are in no particular order.
+ * See <em>The Java Language Specification</em> section 8.1.4
+ * for more details.
+ */
+ public IType[] getImplementingClasses(IImageContext imageContext)
+ throws NotPresentException {
+ return new IType[0];
+ }
+
+ /**
+ * Returns an array of Type objects representing the direct
+ * superinterfaces of the class or interface represented by this object.
+ * <p>
+ * If this object represents a class, the return value is an array
+ * containing objects representing all interfaces directly implemented by the
+ * class. The order of the interface objects in the array corresponds
+ * to the order of the interface names in the <code>implements</code>
+ * clause of the declaration of the class represented by this object.
+ * <p>
+ * If this object represents an interface, the array contains
+ * objects representing all interfaces directly extended by the interface.
+ * The order of the interface objects in the array corresponds to the
+ * order of the interface names in the <code>extends</code> clause of
+ * the declaration of the interface represented by this object.
+ * <p>
+ * If the class or interface implements no interfaces, or if this
+ * object represents neither a class nor an interface, this method
+ * returns an array of length 0.
+ *
+ * See <em>The Java Language Specification</em> sections 8.1.4 and 9.1.3
+ * for more details.
+ */
+ public IType[] getInterfaces() throws NotPresentException {
+ return new IType[0];
+ }
+
+ /**
+ * Returns a Method object that represents the specified
+ * member method of the class or interface represented
+ * by this object. The name parameter is a String specifying the
+ * simple name the desired method, and the parameterTypes
+ * parameter is an array of Type objects that identify the
+ * method's formal parameter types, in declared order.
+ * Returns null if this type does not represent a class or interface.
+ * This is a handle-only method; the specified method may
+ * or may not actually be present in the class or interface.
+ */
+ public IMethod getMethodHandle(String name, IType[] parameterTypes) {
+ return null;
+ }
+
+ /**
+ * Returns the compiled Java language modifiers for this class or
+ * interface, encoded in an integer. The modifiers consist of the
+ * Java Virtual Machine's constants for public, protected,
+ * private, and final; they should be decoded using the
+ * methods of class Modifier.
+ * The result may not correspond to the modifiers as declared in
+ * the source, since the compiler may change them (in particular,
+ * for inner classes). The <code>getDeclaredModifiers()</code>
+ * method should be used if the original modifiers are needed.
+ * Returns 0 if this type does not represent a class or interface.
+ */
+ public int getModifiers() throws NotPresentException {
+ return 0;
+ }
+
+ /**
+ * Returns the fully-qualified name of the type (class, interface,
+ * array, or primitive) represented by this object, as a String.
+ * For classes and interfaces, the name is the VM class name,
+ * including the package name.
+ * For inner classes, the name is as described in the
+ * <em>Inner Classes Specification</em>.
+ * For array types, the name is the name of the component type, followed by '[]'.
+ * For primitive types, the name is the keyword for the primitive type.
+ * This is a handle-only method.
+ */
+ public abstract String getName();
+ /**
+ * Returns the Package in which this class or interface is declared.
+ * Returns null if this object represents a primitive type or array type.
+ * This is a handle-only method.
+ */
+ public IPackage getPackage() {
+ return null;
+ }
+
+ /**
+ * Returns the simple name of the type (class, interface, array,
+ * or primitive) represented by this object, as a String.
+ * For classes and interfaces, this is the VM class name,
+ * excluding the package name.
+ * For array types, this is the simple name of the component type, followed by '[]'.
+ * For primitive types, this is the keyword for the primitive type.
+ * This is a handle-only method.
+ */
+ public abstract String getSimpleName();
+ /**
+ * Returns a SourceFragment describing the fragment of source
+ * from which this member is derived.
+ * Returns null if this type represent a primitive type or an
+ * array type, or if this type is not derived directly from source
+ * (e.g. a fictional type, which is created by the image builder).
+ */
+ public ISourceFragment getSourceFragment() throws NotPresentException {
+ return null;
+ }
+
+ /**
+ * Returns an array of Type objects representing the
+ * classes in the given ImageContext which are direct subclasses of
+ * this class.
+ * Returns an array of length 0 if this object does not represent
+ * a class.
+ * The resulting Types are in no particular order.
+ * See <em>The Java Language Specification</em> sections 8.1.3 and 20.3.4
+ * for more details.
+ */
+ public IType[] getSubclasses(IImageContext imageContext)
+ throws NotPresentException {
+ return new IType[0];
+ }
+
+ /**
+ * Returns an array of Type objects representing the
+ * interfaces in the given ImageContext which are direct subinterfaces of
+ * this interface.
+ * Returns an array of length 0 if this object does not represent
+ * an interface.
+ * The resulting Types are in no particular order.
+ * See <em>The Java Language Specification</em> section 9.1.3
+ * for more details.
+ */
+ public IType[] getSubinterfaces(IImageContext imageContext)
+ throws NotPresentException {
+ return new IType[0];
+ }
+
+ /**
+ * If this object represents any class other than the class
+ * <code>java.lang.Object</code>, then the object that represents
+ * the direct superclass of that class is returned.
+ * <p>
+ * If this object represents the class <code>java.lang.Object</code>
+ * or this object represents an interface or a primitive type,
+ * <code>null</code> is returned.
+ * If this object represents an array type, then the Type that represents
+ * class <code>java.lang.Object</code> is returned.
+ * <p>
+ * See <em>The Java Language Specification</em> sections 8.1.3 and 20.3.4
+ * for more details.
+ */
+ public org.eclipse.jdt.internal.core.builder.IType getSuperclass()
+ throws org.eclipse.jdt.internal.core.builder.NotPresentException {
+ return null;
+ }
+
+ /**
+ * Returns the VM signature of the type.
+ */
+ String getVMSignature() {
+ StringBuffer sb = new StringBuffer();
+ appendVMSignature(sb);
+ return sb.toString();
+ }
+
+ /**
+ * Returns true if this object represents an anonymous class,
+ * false otherwise.
+ * An anonymous class is a local inner class with no declared name.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ */
+ public boolean isAnonymous()
+ throws org.eclipse.jdt.internal.core.builder.NotPresentException {
+ return false;
+ }
+
+ /**
+ * If this Type object represents an array type, returns true,
+ * otherwise returns false.
+ * This is a handle-only method.
+ */
+ public boolean isArray() {
+ return false;
+ }
+
+ /**
+ * Return true if this represents a binary class or interface, false otherwise.
+ * A binary type is one which is in .class file format in the source tree.
+ * Returns false if this represents a primitive type or an array type.
+ */
+ public boolean isBinary() throws NotPresentException {
+ return false;
+ }
+
+ /**
+ * Determines if this object represents a class type.
+ * This returns false if this object represents an interface,
+ * an array type, or a primitive type.
+ */
+ public boolean isClass() throws NotPresentException {
+ // overridden for classes and interfaces
+ return false;
+ }
+
+ /**
+ * @see IType
+ */
+ public boolean isDeprecated() throws NotPresentException {
+ return false;
+ }
+
+ /**
+ * Returns true if this object represents an inner class or interface,
+ * false otherwise.
+ * An inner class is one which can only be created in the context of
+ * an instance of its outer class. This does not include package member
+ * classes or other top-level classes. Such a class cannot be static.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ */
+ public boolean isInnerClass() throws NotPresentException {
+ return false;
+ }
+
+ /**
+ * Determines if this object represents an interface type.
+ * This returns false if this object represents a class,
+ * an array type, or a primitive type.
+ */
+ public boolean isInterface() throws NotPresentException {
+ return false;
+ }
+
+ /**
+ * Returns true if this object represents a local inner class,
+ * false otherwise.
+ * A local inner class is an inner class which is defined in the body of
+ * a method or other block, not as a class field.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ */
+ public boolean isLocal() throws NotPresentException {
+ return false;
+ }
+
+ /**
+ * Returns true if this object represents a class or interface
+ * which is declared as a package member (i.e. a 'normal' class
+ * as in JDK 1.02). Returns false otherwise.
+ * In particular, this method returns false if this object represents a
+ * top-level class which is declared as a member of a class.
+ * For the sake of consistent terminology, a class which is
+ * not a package member is considered 'nested', whether or not
+ * it is top-level.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ */
+ public boolean isPackageMember() throws NotPresentException {
+ return false;
+ }
+
+ /**
+ * Determines if the specified Type object represents a primitive Java
+ * type.
+ * This is a handle-only method.
+ *
+ * <p>There are nine predefined Type objects to represent the eight
+ * primitive Java types and void. These are created by the Java
+ * Virtual Machine, and have the same names as the primitive types
+ * that they represent, namely boolean, byte, char, short, int,
+ * long, float, and double, and void.
+ */
+ public boolean isPrimitive() {
+ return false;
+ }
+
+ /**
+ * Returns true if the type represented by this object is
+ * synthetic, false otherwise. A synthetic object is one that
+ * was invented by the compiler, but was not declared in the source.
+ * See <em>The Inner Classes Specification</em>.
+ * A synthetic object is not the same as a fictitious object.
+ */
+ public boolean isSynthetic() throws NotPresentException {
+ return false;
+ }
+
+ /**
+ * Returns true if this object represents a top-level class or interface,
+ * false otherwise.
+ * A top-level class is declared either as a package member or as a
+ * static member of another top-level class. Unlike inner classes,
+ * instances of top-level classes are not created in the context of
+ * another object.
+ * Given the appropriate access modifiers, a top-level class can be
+ * referred to directly by a qualified name.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ */
+ public boolean isTopLevel()
+ throws org.eclipse.jdt.internal.core.builder.NotPresentException {
+ return false;
+ }
+
+ /**
+ * Returns a constant indicating what kind of handle this is.
+ */
+ public int kind() {
+ return K_JAVA_TYPE;
+ }
+
+ /**
+ * Returns a string representation of the package. For debugging purposes
+ * only (NON-NLS).
+ */
+ public String toString() {
+ return "type " + getName();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeImplSWH.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeImplSWH.java
new file mode 100644
index 0000000000..6c985d5127
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeImplSWH.java
@@ -0,0 +1,493 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.IConstants;
+import org.eclipse.jdt.internal.core.builder.*;
+
+abstract class TypeImplSWH extends StateSpecificHandleImpl implements IType {
+ /**
+ * Returns a Type object representing an array type with
+ * the type represented by this object as its component type.
+ * This is a handle-only method.
+ */
+ public IType getArrayHandle() {
+ return (IType) getHandle().getArrayHandle().inState(fState);
+ }
+
+ /**
+ * If this class represents an array type, returns the Type
+ * object representing the component type of the array; otherwise
+ * returns null. The component type of an array may itself be
+ * an array type.
+ * This is a handle-only method.
+ */
+ public org.eclipse.jdt.internal.core.builder.IType getComponentType() {
+ return null;
+ }
+
+ /**
+ * Returns a Constructor object that represents the specified
+ * constructor of the class represented by this object.
+ * The parameterTypes parameter is an array of Type objects that
+ * identify the constructor's formal parameter types, in declared
+ * order.
+ * Returns null if this type does not represent a class or interface.
+ * This is a handle-only method; the specified constructor may
+ * or may not actually be present in the class or interface.
+ */
+ public IConstructor getConstructorHandle(IType[] parameterTypes) {
+ return null;
+ }
+
+ /**
+ * @see IType#getCRC
+ */
+ public int getCRC() throws NotPresentException {
+ return 0;
+ }
+
+ /**
+ * Returns an array of Type objects representing all the classes
+ * and interfaces declared as members of the class represented by
+ * this object. This includes public, protected, default
+ * (package) access, and private classes and interfaces declared
+ * by the class, but excludes inherited classes and interfaces.
+ * Returns an array of length 0 if the class declares no classes
+ * or interfaces as members, or if this object represents an
+ * array type or primitive type.
+ * The resulting Types are in no particular order.
+ */
+ public IType[] getDeclaredClasses() throws NotPresentException {
+ return new IType[0];
+ }
+
+ /**
+ * Returns an array of Constructor objects representing all the
+ * constructors declared by the class represented by this
+ * object. These are public, protected, default (package) access,
+ * and private constructors. Returns an array of length 0 if this
+ * object represents an interface, an array type or a primitive type.
+ * The resulting Constructors are in no particular order.
+ */
+ public IConstructor[] getDeclaredConstructors() throws NotPresentException {
+ return new IConstructor[0];
+ }
+
+ /**
+ * Returns an array of Field objects representing all the fields
+ * declared by the class or interface represented by this
+ * object. This includes public, protected, default (package)
+ * access, and private fields, but excludes inherited
+ * fields. Returns an array of length 0 if the class or interface
+ * declares no fields, or if this object represents a
+ * primitive type or an array type (the implicit <code>length</code>
+ * field of array types is not considered to be a declared field).
+ * The resulting Fields are in no particular order.
+ */
+ public IField[] getDeclaredFields() throws NotPresentException {
+ return new IField[0];
+ }
+
+ /**
+ * Returns an array of Method objects representing all the methods
+ * declared by the class or interface represented by this
+ * object. This includes public, protected, default (package)
+ * access, and private methods, but excludes inherited
+ * methods. Returns an array of length 0 if the class or interface
+ * declares no methods, or if this object represents an
+ * array type or primitive type.
+ * The resulting Methods are in no particular order.
+ */
+ public IMethod[] getDeclaredMethods() throws NotPresentException {
+ return new IMethod[0];
+ }
+
+ /**
+ * Returns the declared Java language modifiers, as specified in the declaration
+ * of this class or interface, encoded in an integer.
+ * The modifiers consist of the Java Virtual Machine's constants
+ * for public, protected, private, and final; they should be decoded
+ * using the methods of class Modifier.
+ * The result may not correspond to the modifiers in the compiled
+ * binary, since the compiler may change them (in particular,
+ * for inner classes). The <code>getModifiers()</code>
+ * method should be used if the compiled modifiers are needed.
+ * Returns 0 if this type does not represent a class or interface.
+ *
+ * <p>The modifier encodings are defined in <em>The Java Virtual
+ * Machine Specification</em>, table 4.1.
+ */
+ public int getDeclaredModifiers() throws NotPresentException {
+ return 0;
+ }
+
+ /**
+ * Returns the declared name of the class or interface represented
+ * by this object, as a String.
+ * The name is the simple, unqualified name used in the source code.
+ * If this represents an inner class, it does not include the names
+ * of any containing classes.
+ * If this represents an anonymous class, it returns a String of length 0.
+ * If this does not represent a class or interface, it returns
+ * a String of length 0.
+ */
+ public String getDeclaredName() throws NotPresentException {
+ return "";
+ }
+
+ /**
+ * If the class or interface represented by this Type object is
+ * a member of another class or interface (i.e. it is a nested class),
+ * this returns the Type object representing the class or interface
+ * of which it is a member (its <em>declaring class</em>).
+ * If this class or interface is a local class, returns the Type
+ * object representing the class containing the member in which
+ * this class is declared.
+ * Returns null if this class or interface is not a nested class,
+ * or if this type does not represent a class or interface.
+ */
+ public IType getDeclaringClass() {
+ return null;
+ }
+
+ /**
+ * Returns a Field object that represents the specified
+ * member field of the class or interface represented
+ * by this object. The name parameter is a String specifying
+ * the simple name of the desired field.
+ * Returns null if this type does not represent a class or interface.
+ * This is a handle-only method; the specified field may
+ * or may not actually be present in the class or interface.
+ */
+ public IField getFieldHandle(String name) {
+ return null;
+ }
+
+ /**
+ * Returns the handle for this type
+ */
+ protected abstract TypeImpl getHandle();
+ /**
+ * Returns an array of Type objects representing the
+ * classes in the given ImageContext which directly implement this interface.
+ * A class is said to directly implement this interface if the interface
+ * appears in the <code>implements</code> clause of the class's declaration.
+ * Although all array types are considered to implement the <code>Cloneable</code>
+ * interface, this method never returns array types, only class types.
+ * Returns an array of length 0 if this object does not represent
+ * an interface.
+ * The resulting Types are in no particular order.
+ * See <em>The Java Language Specification</em> section 8.1.4
+ * for more details.
+ */
+ public IType[] getImplementingClasses(IImageContext imageContext)
+ throws NotPresentException {
+ return new IType[0];
+ }
+
+ /**
+ * Returns an array of Type objects representing the direct
+ * superinterfaces of the class or interface represented by this object.
+ * <p>
+ * If this object represents a class, the return value is an array
+ * containing objects representing all interfaces directly implemented by the
+ * class. The order of the interface objects in the array corresponds
+ * to the order of the interface names in the <code>implements</code>
+ * clause of the declaration of the class represented by this object.
+ * <p>
+ * If this object represents an interface, the array contains
+ * objects representing all interfaces directly extended by the interface.
+ * The order of the interface objects in the array corresponds to the
+ * order of the interface names in the <code>extends</code> clause of
+ * the declaration of the interface represented by this object.
+ * <p>
+ * If the class or interface implements no interfaces, or if this
+ * object represents neither a class nor an interface, this method
+ * returns an array of length 0.
+ *
+ * See <em>The Java Language Specification</em> sections 8.1.4 and 9.1.3
+ * for more details.
+ */
+ public IType[] getInterfaces() throws NotPresentException {
+ return new IType[0];
+ }
+
+ /**
+ * Returns a Method object that represents the specified
+ * member method of the class or interface represented
+ * by this object. The name parameter is a String specifying the
+ * simple name the desired method, and the parameterTypes
+ * parameter is an array of Type objects that identify the
+ * method's formal parameter types, in declared order.
+ * Returns null if this type does not represent a class or interface.
+ * This is a handle-only method; the specified method may
+ * or may not actually be present in the class or interface.
+ */
+ public IMethod getMethodHandle(String name, IType[] parameterTypes) {
+ return null;
+ }
+
+ /**
+ * Returns the compiled Java language modifiers for this class or
+ * interface, encoded in an integer. The modifiers consist of the
+ * Java Virtual Machine's constants for public, protected,
+ * private, and final; they should be decoded using the
+ * methods of class Modifier.
+ * The result may not correspond to the modifiers as declared in
+ * the source, since the compiler may change them (in particular,
+ * for inner classes). The <code>getDeclaredModifiers()</code>
+ * method should be used if the original modifiers are needed.
+ * Returns 0 if this type does not represent a class or interface.
+ */
+ public int getModifiers() throws NotPresentException {
+ return 0;
+ }
+
+ /**
+ * Returns the fully-qualified name of the type (class, interface,
+ * array, or primitive) represented by this object, as a String.
+ * For classes and interfaces, the name is the VM class name,
+ * including the package name.
+ * For inner classes, the name is as described in the
+ * <em>Inner Classes Specification</em>.
+ * For array types, the name is the name of the component type, followed by '[]'.
+ * For primitive types, the name is the keyword for the primitive type.
+ * This is a handle-only method.
+ */
+ public String getName() {
+ return getHandle().getName();
+ }
+
+ /**
+ * Returns the Package in which this class or interface is declared.
+ * Returns null if this object represents a primitive type or array type.
+ * This is a handle-only method.
+ */
+ public IPackage getPackage() {
+ return null;
+ }
+
+ /**
+ * Returns the simple name of the type (class, interface, array,
+ * or primitive) represented by this object, as a String.
+ * For classes and interfaces, this is the VM class name,
+ * excluding the package name.
+ * For array types, this is the simple name of the component type, followed by '[]'.
+ * For primitive types, this is the keyword for the primitive type.
+ * This is a handle-only method.
+ */
+ public String getSimpleName() {
+ return getHandle().getSimpleName();
+ }
+
+ /**
+ * Returns a SourceFragment describing the fragment of source
+ * from which this member is derived.
+ * Returns null if this type represent a primitive type or an
+ * array type, or if this type is not derived directly from source
+ * (e.g. a fictional type, which is created by the image builder).
+ */
+ public ISourceFragment getSourceFragment() throws NotPresentException {
+ return null;
+ }
+
+ /**
+ * Returns an array of Type objects representing the
+ * classes in the given ImageContext which are direct subclasses of
+ * this class.
+ * Returns an array of length 0 if this object does not represent
+ * a class.
+ * The resulting Types are in no particular order.
+ * See <em>The Java Language Specification</em> sections 8.1.3 and 20.3.4
+ * for more details.
+ */
+ public IType[] getSubclasses(IImageContext imageContext)
+ throws NotPresentException {
+ return new IType[0];
+ }
+
+ /**
+ * Returns an array of Type objects representing the
+ * interfaces in the given ImageContext which are direct subinterfaces of
+ * this interface.
+ * Returns an array of length 0 if this object does not represent
+ * an interface.
+ * The resulting Types are in no particular order.
+ * See <em>The Java Language Specification</em> section 9.1.3
+ * for more details.
+ */
+ public IType[] getSubinterfaces(IImageContext imageContext)
+ throws NotPresentException {
+ return new IType[0];
+ }
+
+ /**
+ * If this object represents any class other than the class
+ * <code>java.lang.Object</code>, then the object that represents
+ * the direct superclass of that class is returned.
+ * <p>
+ * If this object represents the class <code>java.lang.Object</code>
+ * or this object represents an interface or a primitive type,
+ * <code>null</code> is returned.
+ * If this object represents an array type, then the Type that represents
+ * class <code>java.lang.Object</code> is returned.
+ * <p>
+ * See <em>The Java Language Specification</em> sections 8.1.3 and 20.3.4
+ * for more details.
+ */
+ public org.eclipse.jdt.internal.core.builder.IType getSuperclass()
+ throws org.eclipse.jdt.internal.core.builder.NotPresentException {
+ return null;
+ }
+
+ /**
+ * Returns true if this object represents an anonymous class,
+ * false otherwise.
+ * An anonymous class is a local inner class with no declared name.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ */
+ public boolean isAnonymous()
+ throws org.eclipse.jdt.internal.core.builder.NotPresentException {
+ return false;
+ }
+
+ /**
+ * If this Type object represents an array type, returns true,
+ * otherwise returns false.
+ * This is a handle-only method.
+ */
+ public boolean isArray() {
+ return false;
+ }
+
+ /**
+ * Return true if this represents a binary class or interface, false otherwise.
+ * A binary type is one which is in .class file format in the source tree.
+ * Returns false if this represents a primitive type or an array type.
+ */
+ public boolean isBinary() throws NotPresentException {
+ return false;
+ }
+
+ /**
+ * Determines if this object represents a class type.
+ * This returns false if this object represents an interface,
+ * an array type, or a primitive type.
+ */
+ public boolean isClass() throws NotPresentException {
+ // overridden for classes and interfaces
+ return false;
+ }
+
+ /**
+ * @see IType
+ */
+ public boolean isDeprecated() throws NotPresentException {
+ return false;
+ }
+
+ /**
+ * Returns true if this object represents an inner class or interface,
+ * false otherwise.
+ * An inner class is one which can only be created in the context of
+ * an instance of its outer class. This does not include package member
+ * classes or other top-level classes. Such a class cannot be static.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ */
+ public boolean isInnerClass() throws NotPresentException {
+ return false;
+ }
+
+ /**
+ * Determines if this object represents an interface type.
+ * This returns false if this object represents a class,
+ * an array type, or a primitive type.
+ */
+ public boolean isInterface() throws NotPresentException {
+ return false;
+ }
+
+ /**
+ * Returns true if this object represents a local inner class,
+ * false otherwise.
+ * A local inner class is an inner class which is defined in the body of
+ * a method or other block, not as a class field.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ */
+ public boolean isLocal() throws NotPresentException {
+ return false;
+ }
+
+ /**
+ * Returns true if this object represents a class or interface
+ * which is declared as a package member (i.e. a 'normal' class
+ * as in JDK 1.02). Returns false otherwise.
+ * In particular, this method returns false if this object represents a
+ * top-level class which is declared as a member of a class.
+ * For the sake of consistent terminology, a class which is
+ * not a package member is considered 'nested', whether or not
+ * it is top-level.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ */
+ public boolean isPackageMember() throws NotPresentException {
+ return false;
+ }
+
+ /**
+ * Determines if the specified Type object represents a primitive Java
+ * type.
+ * This is a handle-only method.
+ *
+ * <p>There are nine predefined Type objects to represent the eight
+ * primitive Java types and void. These are created by the Java
+ * Virtual Machine, and have the same names as the primitive types
+ * that they represent, namely boolean, byte, char, short, int,
+ * long, float, and double, and void.
+ */
+ public boolean isPrimitive() {
+ return false;
+ }
+
+ /**
+ * Returns true if the type represented by this object is
+ * synthetic, false otherwise. A synthetic object is one that
+ * was invented by the compiler, but was not declared in the source.
+ * See <em>The Inner Classes Specification</em>.
+ * A synthetic object is not the same as a fictitious object.
+ */
+ public boolean isSynthetic() throws NotPresentException {
+ return false;
+ }
+
+ /**
+ * Returns true if this object represents a top-level class or interface,
+ * false otherwise.
+ * A top-level class is declared either as a package member or as a
+ * static member of another top-level class. Unlike inner classes,
+ * instances of top-level classes are not created in the context of
+ * another object.
+ * Given the appropriate access modifiers, a top-level class can be
+ * referred to directly by a qualified name.
+ * <p>
+ * See the <em>Java Inner Classes Specification</em> for more details.
+ */
+ public boolean isTopLevel()
+ throws org.eclipse.jdt.internal.core.builder.NotPresentException {
+ return false;
+ }
+
+ /**
+ * Return the non state specific handle associated with this handle
+ */
+ public IHandle nonStateSpecific() {
+ return getHandle();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeNode.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeNode.java
new file mode 100644
index 0000000000..1497a81422
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeNode.java
@@ -0,0 +1,75 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.builder.IType;
+
+import java.util.*;
+
+/**
+ * Type nodes represent compiled types in the graph. They are types
+ * that were importing into the workspace with no source code available.
+ * They cannot be compiled, but they still have dependents and dependencies.
+ */
+public class TypeNode extends AbstractNode {
+ PackageElement fType;
+ /**
+ * Creates a new type node with the given type
+ */
+ public TypeNode(PackageElement type) {
+ fType = type;
+ }
+
+ /**
+ * Returns a copy of this node, without copying dependencies. Used
+ * by DependencyGraph.copy().
+ */
+ public AbstractNode copy() {
+ return new TypeNode(fType);
+ }
+
+ /**
+ * Returns the element which this node represents.
+ */
+ public Object getElement() {
+ return fType;
+ }
+
+ /**
+ * Returns the number of bytes that this node uses.
+ * For debugging and profiling purposes only.
+ */
+ int getFootprint() {
+ /* one slot for type */
+ return super.getFootprint() + 4;
+ }
+
+ /**
+ * Returns what kind of node this is.
+ */
+ public int getKind() {
+ return TYPE_NODE;
+ }
+
+ public PackageElement getPackageElement() {
+ return fType;
+ }
+
+ public IType[] getTypes() {
+ String fileName = fType.getFileName();
+ int lastDot = fileName.lastIndexOf('.');
+ IType type = fType.getPackage().getClassHandle(fileName.substring(0, lastDot));
+ return new IType[] { type };
+ }
+
+ /**
+ * Prints a string representation of the node. This method is for debugging
+ * purposes only.
+ */
+ public String toString() {
+ return "TypeNode(" + fType.getFileName() + ")";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeStructureEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeStructureEntry.java
new file mode 100644
index 0000000000..cb3d3aee06
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/TypeStructureEntry.java
@@ -0,0 +1,113 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.Assert;
+import org.eclipse.jdt.internal.core.builder.*;
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+
+/**
+ * An entry in the state's principal structure table
+ */
+public class TypeStructureEntry extends StateTables {
+ SourceEntry fSourceEntry;
+ IType fType;
+ int fCRC32;
+
+ static IType[] fgEmptyTypeList = new IType[0];
+ /**
+ * Creates a new TypeStructureEntry.
+ */
+ TypeStructureEntry(SourceEntry sEntry, IType type) {
+ this(sEntry, type, 0);
+ }
+
+ /**
+ * Creates a new TypeStructureEntry.
+ */
+ TypeStructureEntry(SourceEntry sEntry, IType type, int crc) {
+ fSourceEntry = sEntry;
+ fType = type;
+ fCRC32 = crc;
+ }
+
+ /**
+ * Returns true if the given object is equal to this one, and false otherwise
+ * A TypeStructureEntry equals method is needed because they are keys to the
+ * TypeDescriptorCache in the State.
+ */
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof TypeStructureEntry))
+ return false;
+
+ TypeStructureEntry e = (TypeStructureEntry) o;
+ return fType.equals(e.fType);
+ }
+
+ int getCRC32() {
+ Assert.isTrue(fCRC32 != 0);
+ return fCRC32;
+ }
+
+ /**
+ * Returns the key for this type in the dependency graph.
+ */
+ Object getDependencyGraphKey() {
+ if (fSourceEntry.isSource()) {
+ return new PackageElement(fType.getPackage(), fSourceEntry);
+ } else {
+ return fType;
+ }
+ }
+
+ public SourceEntry getSourceEntry() {
+ return fSourceEntry;
+ }
+
+ ISourceFragment getSourceFragment() {
+ return new SourceFragmentImpl(-1, -1, fSourceEntry);
+ }
+
+ public IType getType() {
+ return fType;
+ }
+
+ /**
+ * Returns a consistent hashcode for this entry.
+ * A hashcode method is needed because TypeStructureEntrys are keys to the
+ * TypeDescriptorCache in the State.
+ */
+ public int hashcode() {
+ return fType.hashCode();
+ }
+
+ /**
+ * Returns true if this entry comes from a binary file, otherwise
+ * returns false.
+ */
+ boolean isBinary() {
+ return fSourceEntry.isBinary();
+ }
+
+ void setCRC32(int val) {
+ fCRC32 = val;
+ }
+
+ /**
+ * Returns a String that represents the value of this object.
+ * @return a string representation of the receiver
+ */
+ public String toString() {
+ StringBuffer buf = new StringBuffer("TypeStructureEntry(");
+ if (fType != null) {
+ buf.append(fType.getName());
+ }
+ buf.append(")");
+ return buf.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/UnmodifiedBuilderType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/UnmodifiedBuilderType.java
new file mode 100644
index 0000000000..90cd974024
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/UnmodifiedBuilderType.java
@@ -0,0 +1,65 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.Assert;
+
+/**
+ * A type that exists in the old state, and is not being
+ * compiled during the current build. Its structure will
+ * be the same in both the old and new states.
+ */
+public class UnmodifiedBuilderType extends NewBuilderType {
+ /**
+ * UnmodifiedBuilderType constructor comment.
+ */
+ public UnmodifiedBuilderType(
+ IncrementalImageBuilder builder,
+ TypeStructureEntry entry) {
+ super(builder, entry);
+
+ /* we don't yet know if there is a hierarchy change */
+ fComputedHierarchy = false;
+ }
+
+ /**
+ * Should not be trying to compute indictments for an unmodified type.
+ */
+ public void computeIndictments(IndictmentSet indictments) {
+ Assert.isTrue(false);
+ }
+
+ /**
+ * Returns true if there is a change to the supertype hierarchy of this type.
+ * Needs to check the whole hierarchy because changes from higher up are -not-
+ * automatically propagated through the dependency graph.
+ */
+ protected boolean detectHierarchyChange() {
+ return false;
+ }
+
+ /**
+ * Returns the tsEntry in the old state (same in both states)
+ */
+ public TypeStructureEntry getOldTypeStructureEntry() {
+ return fNewTSEntry;
+ }
+
+ /**
+ * Returns true if the given type was affected by the build
+ * (either added, removed, or changed)
+ */
+ public boolean isAffected() {
+ return false;
+ }
+
+ /**
+ * For debugging only
+ */
+ public String toString() {
+ return "UnmodifiedBuilderType(" + fNewTSEntry.getType().getName() + ")";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/WorkQueue.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/WorkQueue.java
new file mode 100644
index 0000000000..f55bc0ec9c
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/WorkQueue.java
@@ -0,0 +1,133 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.*;
+
+public class WorkQueue {
+ /**
+ * Table which maps from PackageElement to Entry.
+ */
+ protected Hashtable entries = new Hashtable(11);
+
+ /**
+ * Vector which keeps the elements marked NEEDS_COMPILE,
+ * in the order in which they were added to the queue.
+ */
+ protected Vector needsCompileList = new Vector();
+
+ protected static class Entry {
+ protected PackageElement element;
+ protected int status;
+
+ public Entry(PackageElement e) {
+ element = e;
+ status = NEEDS_COMPILE;
+ }
+ }
+
+ /**
+ * Status flag. The element is unaffected by the latest changes.
+ */
+ private static final int UNAFFECTED = 0;
+
+ /**
+ * Status flag. The element has been convicted and must be compiled before any other
+ * type can use it.
+ */
+ private static final int NEEDS_COMPILE = 2;
+
+ /**
+ * Status flag. The element was affected by the changes, and was compiled as a result.
+ */
+ private static final int COMPILED = 3;
+
+ /**
+ * Creates a new WorkQueue.
+ */
+ public WorkQueue() {
+ }
+
+ /**
+ * Adds an element to the queue. The element is marked as NEEDS_COMPILE.
+ */
+ public void add(PackageElement element) {
+ Entry entry = (Entry) entries.get(element);
+ if (entry == null) {
+ entry = new Entry(element);
+ entries.put(element, entry);
+ needsCompileList.addElement(element);
+ } else {
+ if (entry.status != NEEDS_COMPILE) {
+ if (entry.status == COMPILED) {
+ System.out.println(
+ "Warning: image builder wants to recompile already compiled element: "
+ + element);
+ }
+ entry.status = NEEDS_COMPILE;
+ needsCompileList.addElement(element);
+ }
+ }
+ }
+
+ /**
+ * Marks the given element as COMPILED.
+ */
+ public void compiled(PackageElement element) {
+ Entry entry = (Entry) entries.get(element);
+ if (entry == null) {
+ //System.out.println("Warning: Java builder compiled unexpected element: " + element);
+ entry = new Entry(element);
+ entries.put(element, entry);
+ } else {
+ if (entry.status != NEEDS_COMPILE) {
+ System.out.println(
+ "Warning: Java builder compiled the same element twice: " + element);
+ }
+ needsCompileList.removeElement(element);
+ }
+ entry.status = COMPILED;
+
+ }
+
+ /**
+ * Returns true if the given element is in the queue, false otherwise.
+ */
+ public boolean contains(PackageElement element) {
+ return entries.containsKey(element);
+ }
+
+ /**
+ * Returns the elements which are marked NEEDS_COMPILE,
+ * in the order in which they should be compiled.
+ */
+ public Vector getElementsToCompile() {
+ // Important to clone because needsCompileList may
+ // be modified while the result is being examined.
+ // Also, the caller may modify the result.
+ return (Vector) needsCompileList.clone();
+ }
+
+ /**
+ * Returns true if the given element is marked as COMPILED.
+ */
+ public boolean hasBeenCompiled(PackageElement element) {
+ Entry entry = (Entry) entries.get(element);
+ return entry != null && entry.status == COMPILED;
+ }
+
+ /**
+ * Returns true if the given element is marked as NEEDS_COMPILE.
+ */
+ public boolean needsCompile(PackageElement element) {
+ Entry entry = (Entry) entries.get(element);
+ return entry != null && entry.status == NEEDS_COMPILE;
+ }
+
+ public String toString() {
+ return "WorkQueue: " + needsCompileList;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ZipNode.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ZipNode.java
new file mode 100644
index 0000000000..5259a751d0
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/impl/ZipNode.java
@@ -0,0 +1,63 @@
+package org.eclipse.jdt.internal.core.builder.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * A node in the dependency graph representing a jar or zip file. All
+ * types and JCUs that depend on a file in the jar have a dependency
+ * to the JarNode for that file.
+ */
+public class ZipNode extends AbstractNode {
+ /**
+ * The fully qualified name of the jar file. Should
+ * this be an IPath or an IFile?
+ */
+ IPath fZipFile;
+ /**
+ * Creates a new JarNode instance.
+ */
+ protected ZipNode(IPath zipPath) {
+ fZipFile = zipPath;
+ }
+
+ /**
+ * Creates and returns a copy of this node.
+ */
+ public AbstractNode copy() {
+ return new ZipNode(fZipFile);
+ }
+
+ /**
+ * @see INode
+ */
+ public Object getElement() {
+ return fZipFile;
+ }
+
+ /**
+ * @see INode
+ */
+ public int getKind() {
+ return INode.ZIP_NODE;
+ }
+
+ /**
+ * Returns the name of the jar associated with this jar node
+ */
+ public IPath getZipFile() {
+ return fZipFile;
+ }
+
+ /**
+ * Prints a string representation of the node. This method is for debugging
+ * purposes only.
+ */
+ public String toString() {
+ return "ZipNode(" + fZipFile + ")";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/EvaluationContextWrapper.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/EvaluationContextWrapper.java
new file mode 100644
index 0000000000..5078019101
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/EvaluationContextWrapper.java
@@ -0,0 +1,341 @@
+package org.eclipse.jdt.internal.core.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.internal.codeassist.ISelectionRequestor;
+import org.eclipse.jdt.internal.codeassist.ICompletionRequestor;
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.eval.*;
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+import org.eclipse.jdt.internal.core.*;
+import org.eclipse.jdt.internal.core.builder.impl.JavaBuilder;
+import org.eclipse.jdt.internal.core.builder.impl.ProblemFactory;
+import org.eclipse.jdt.internal.eval.*;
+
+import java.util.Locale;
+
+/**
+ * A wrapper around the infrastructure evaluation context.
+ */
+public class EvaluationContextWrapper implements IEvaluationContext {
+ protected EvaluationContext context;
+ protected JavaProject project;
+ /**
+ * Creates a new wrapper around the given infrastructure evaluation context
+ * and project.
+ */
+ public EvaluationContextWrapper(
+ EvaluationContext context,
+ JavaProject project) {
+ this.context = context;
+ this.project = project;
+ }
+
+ /**
+ * @see org.eclipse.jdt.core.eval.IEvaluationContext#allVariables
+ */
+ public IGlobalVariable[] allVariables() {
+ GlobalVariable[] vars = this.context.allVariables();
+ int length = vars.length;
+ GlobalVariableWrapper[] result = new GlobalVariableWrapper[length];
+ for (int i = 0; i < length; i++) {
+ result[i] = new GlobalVariableWrapper(vars[i]);
+ }
+ return result;
+ }
+
+ /**
+ * Checks to ensure that there is a previously built state.
+ */
+ protected void checkBuilderState() throws JavaModelException {
+ if (!getProject().hasBuildState()) {
+ throw new JavaModelException(
+ new JavaModelStatus(
+ IJavaModelStatusConstants.EVALUATION_ERROR,
+ "Cannot evaluate if the project has not been built once"));
+ }
+ }
+
+ /**
+ * @see org.eclipse.jdt.core.eval.IEvaluationContext#codeComplete.
+ */
+ public void codeComplete(
+ String codeSnippet,
+ int position,
+ ICodeCompletionRequestor requestor)
+ throws JavaModelException {
+ this.context.complete(
+ codeSnippet.toCharArray(),
+ position,
+ this.project.getSearchableNameEnvironment(),
+ new CompletionRequestorWrapper(requestor),
+ JavaModelManager.convertConfigurableOptions(JavaCore.getOptions()));
+ }
+
+ /**
+ * @see org.eclipse.jdt.core.eval.IEvaluationContext#codeSelect.
+ */
+ public IJavaElement[] codeSelect(String codeSnippet, int offset, int length)
+ throws JavaModelException {
+ SelectionRequestor requestor =
+ new SelectionRequestor(this.project.getNameLookup(), null);
+ // null because there is no need to look inside the code snippet itself
+ this.context.select(
+ codeSnippet.toCharArray(),
+ offset,
+ offset + length,
+ this.project.getSearchableNameEnvironment(),
+ requestor,
+ JavaModelManager.convertConfigurableOptions(JavaCore.getOptions()));
+ return requestor.getElements();
+ }
+
+ /**
+ * @see org.eclipse.jdt.core.eval.IEvaluationContext#deleteVariable.
+ */
+ public void deleteVariable(IGlobalVariable variable) {
+ if (variable instanceof GlobalVariableWrapper) {
+ GlobalVariableWrapper wrapper = (GlobalVariableWrapper) variable;
+ this.context.deleteVariable(wrapper.variable);
+ } else {
+ throw new Error("Unknown implementation of IGlobalVariable");
+ }
+ }
+
+ /**
+ * @see IEvaluationContext#evaluateCodeSnippet
+ */
+ public void evaluateCodeSnippet(
+ String codeSnippet,
+ String[] localVariableTypeNames,
+ String[] localVariableNames,
+ int[] localVariableModifiers,
+ IType declaringType,
+ boolean isStatic,
+ boolean isConstructorCall,
+ ICodeSnippetRequestor requestor,
+ IProgressMonitor progressMonitor)
+ throws org.eclipse.jdt.core.JavaModelException {
+
+ checkBuilderState();
+
+ int length = localVariableTypeNames.length;
+ char[][] varTypeNames = new char[length][];
+ for (int i = 0; i < length; i++) {
+ varTypeNames[i] = localVariableTypeNames[i].toCharArray();
+ }
+
+ length = localVariableNames.length;
+ char[][] varNames = new char[length][];
+ for (int i = 0; i < length; i++) {
+ varNames[i] = localVariableNames[i].toCharArray();
+ }
+
+ // transfer the imports of the IType to the evaluation context
+ if (declaringType != null) {
+ // retrieves the package statement
+ this.context.setPackageName(
+ declaringType.getPackageFragment().getElementName().toCharArray());
+ ICompilationUnit compilationUnit = declaringType.getCompilationUnit();
+ if (compilationUnit != null) {
+ // retrieves the import statement
+ IImportDeclaration[] imports = compilationUnit.getImports();
+ int importsLength = imports.length;
+ if (importsLength != 0) {
+ char[][] importsNames = new char[importsLength][];
+ for (int i = 0; i < importsLength; i++) {
+ importsNames[i] = imports[i].getElementName().toCharArray();
+ }
+ this.context.setImports(importsNames);
+ }
+ }
+ }
+ try {
+ this.context.evaluate(
+ codeSnippet.toCharArray(),
+ varTypeNames,
+ varNames,
+ localVariableModifiers,
+ declaringType == null
+ ? null
+ : declaringType.getFullyQualifiedName().toCharArray(),
+ isStatic,
+ isConstructorCall,
+ getBuildNameEnvironment(),
+ getCompilerOptions(),
+ getInfrastructureEvaluationRequestor(requestor),
+ getProblemFactory());
+ } catch (InstallException e) {
+ handleInstallException(e);
+ }
+ }
+
+ /**
+ * @see IEvaluationContext#evaluateCodeSnippet
+ */
+ public void evaluateCodeSnippet(
+ String codeSnippet,
+ ICodeSnippetRequestor requestor,
+ IProgressMonitor progressMonitor)
+ throws JavaModelException {
+ checkBuilderState();
+ try {
+ this.context.evaluate(
+ codeSnippet.toCharArray(),
+ getBuildNameEnvironment(),
+ getCompilerOptions(),
+ getInfrastructureEvaluationRequestor(requestor),
+ getProblemFactory());
+ } catch (InstallException e) {
+ handleInstallException(e);
+ }
+ }
+
+ /**
+ * @see IEvaluationContext#evaluateVariable
+ */
+ public void evaluateVariable(
+ IGlobalVariable variable,
+ ICodeSnippetRequestor requestor,
+ IProgressMonitor progressMonitor)
+ throws JavaModelException {
+ checkBuilderState();
+ try {
+ this.context.evaluateVariable(
+ ((GlobalVariableWrapper) variable).variable,
+ getBuildNameEnvironment(),
+ getCompilerOptions(),
+ getInfrastructureEvaluationRequestor(requestor),
+ getProblemFactory());
+ } catch (InstallException e) {
+ handleInstallException(e);
+ }
+ }
+
+ /**
+ * Returns a name environment for the last built state.
+ */
+ protected INameEnvironment getBuildNameEnvironment()
+ throws JavaModelException {
+ return JavaModelManager.getJavaModelManager().getNameEnvironment(
+ getProject().getProject());
+ }
+
+ /**
+ * Returns the compiler's configurable options.
+ */
+ protected ConfigurableOption[] getCompilerOptions() throws JavaModelException {
+ return JavaModelManager.convertConfigurableOptions(JavaCore.getOptions());
+ }
+
+ /**
+ * @see org.eclipse.jdt.core.eval.IEvaluationContext#getImports
+ */
+ public String[] getImports() {
+ char[][] imports = this.context.getImports();
+ int length = imports.length;
+ String[] result = new String[length];
+ for (int i = 0; i < length; i++) {
+ result[i] = new String(imports[i]);
+ }
+ return result;
+ }
+
+ /**
+ * Returns the infrastructure evaluation context.
+ */
+ public EvaluationContext getInfrastructureEvaluationContext() {
+ return this.context;
+ }
+
+ /**
+ * Returns a new infrastructure evaluation requestor instance.
+ */
+ protected IRequestor getInfrastructureEvaluationRequestor(ICodeSnippetRequestor requestor) {
+ return new RequestorWrapper(requestor);
+ }
+
+ /**
+ * @see org.eclipse.jdt.core.eval.IEvaluationContext#getPackageName
+ */
+ public String getPackageName() {
+ return new String(this.context.getPackageName());
+ }
+
+ /**
+ * Returns the problem factory to be used during evaluation.
+ */
+ protected IProblemFactory getProblemFactory() throws JavaModelException {
+ return ProblemFactory.getProblemFactory(Locale.getDefault());
+ }
+
+ /**
+ * @see org.eclipse.jdt.core.eval.IEvaluationContext#getProject
+ */
+ public IJavaProject getProject() {
+ return this.project;
+ }
+
+ /**
+ * Handles an install exception by throwing a Java Model exception.
+ */
+ protected void handleInstallException(InstallException e)
+ throws JavaModelException {
+ throw new JavaModelException(
+ new JavaModelStatus(IJavaModelStatusConstants.EVALUATION_ERROR, e.toString()));
+ }
+
+ /**
+ * @see org.eclipse.jdt.core.eval.IEvaluationContext#newVariable
+ */
+ public IGlobalVariable newVariable(
+ String typeName,
+ String name,
+ String initializer) {
+ GlobalVariable newVar =
+ this.context.newVariable(
+ typeName.toCharArray(),
+ name.toCharArray(),
+ (initializer == null) ? null : initializer.toCharArray());
+ return new GlobalVariableWrapper(newVar);
+ }
+
+ /**
+ * @see org.eclipse.jdt.core.eval.IEvaluationContext#setImports
+ */
+ public void setImports(String[] imports) {
+ int length = imports.length;
+ char[][] result = new char[length][];
+ for (int i = 0; i < length; i++) {
+ result[i] = imports[i].toCharArray();
+ }
+ this.context.setImports(result);
+ }
+
+ /**
+ * @see org.eclipse.jdt.core.eval.IEvaluationContext#setPackageName
+ */
+ public void setPackageName(String packageName) {
+ this.context.setPackageName(packageName.toCharArray());
+ }
+
+ /**
+ * @see IEvaluationContext#validateImports
+ */
+ public void validateImports(ICodeSnippetRequestor requestor)
+ throws JavaModelException {
+ checkBuilderState();
+ this.context.evaluateImports(
+ getBuildNameEnvironment(),
+ getInfrastructureEvaluationRequestor(requestor),
+ getProblemFactory());
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/GlobalVariableWrapper.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/GlobalVariableWrapper.java
new file mode 100644
index 0000000000..7384c8dd4b
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/GlobalVariableWrapper.java
@@ -0,0 +1,49 @@
+package org.eclipse.jdt.internal.core.eval;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.core.eval.*;
+
+import org.eclipse.jdt.internal.eval.GlobalVariable;
+
+/**
+ * A wrapper around the infrastructure global variable.
+ */
+class GlobalVariableWrapper implements IGlobalVariable {
+ GlobalVariable variable;
+ /**
+ * Creates a new wrapper around the given infrastructure global variable.
+ */
+ GlobalVariableWrapper(GlobalVariable variable) {
+ this.variable = variable;
+ }
+
+ /**
+ * @see org.eclipse.jdt.core.eval.IGlobalVariable#getInitializer
+ */
+ public String getInitializer() {
+ char[] initializer = this.variable.getInitializer();
+ if (initializer != null) {
+ return new String(initializer);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * @see org.eclipse.jdt.core.eval.IGlobalVariable#getName
+ */
+ public String getName() {
+ return new String(this.variable.getName());
+ }
+
+ /**
+ * @see org.eclipse.jdt.core.eval.IGlobalVariable#getTypeName
+ */
+ public String getTypeName() {
+ return new String(this.variable.getTypeName());
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/RequestorWrapper.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/RequestorWrapper.java
new file mode 100644
index 0000000000..5f80400b6e
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/RequestorWrapper.java
@@ -0,0 +1,76 @@
+package org.eclipse.jdt.internal.core.eval;
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.ClassFile;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.ResourcesPlugin;
+
+import org.eclipse.jdt.internal.compiler.IProblem;
+
+import org.eclipse.jdt.core.eval.ICodeSnippetRequestor;
+import org.eclipse.jdt.internal.eval.IRequestor;
+
+import org.eclipse.jdt.core.IJavaModelMarker;
+
+public class RequestorWrapper implements IRequestor {
+ ICodeSnippetRequestor requestor;
+ public RequestorWrapper(ICodeSnippetRequestor requestor) {
+ this.requestor = requestor;
+ }
+
+ /**
+ * @see ICodeSnippetRequestor
+ */
+ public boolean acceptClassFiles(
+ ClassFile[] classFiles,
+ char[] codeSnippetClassName) {
+ int length = classFiles.length;
+ byte[][] classFileBytes = new byte[length][];
+ String[][] compoundNames = new String[length][];
+ for (int i = 0; i < length; i++) {
+ ClassFile classFile = classFiles[i];
+ classFileBytes[i] = classFile.getBytes();
+ char[][] classFileCompundName = classFile.getCompoundName();
+ int length2 = classFileCompundName.length;
+ String[] compoundName = new String[length2];
+ for (int j = 0; j < length2; j++) {
+ compoundName[j] = new String(classFileCompundName[j]);
+ }
+ compoundNames[i] = compoundName;
+ }
+ return this.requestor.acceptClassFiles(
+ classFileBytes,
+ compoundNames,
+ codeSnippetClassName == null ? null : new String(codeSnippetClassName));
+ }
+
+ /**
+ * @see ICodeSnippetRequestor
+ */
+ public void acceptProblem(
+ IProblem problem,
+ char[] fragmentSource,
+ int fragmentKind) {
+ try {
+ IMarker marker =
+ ResourcesPlugin.getWorkspace().getRoot().createMarker(
+ IJavaModelMarker.TRANSIENT_PROBLEM);
+ marker.setAttribute(IJavaModelMarker.ID, problem.getID());
+ marker.setAttribute(IMarker.CHAR_START, problem.getSourceStart());
+ marker.setAttribute(IMarker.CHAR_END, problem.getSourceEnd() + 1);
+ marker.setAttribute(IMarker.LINE_NUMBER, problem.getSourceLineNumber());
+ //marker.setAttribute(IMarker.LOCATION, "#" + problem.getSourceLineNumber());
+ marker.setAttribute(IMarker.MESSAGE, problem.getMessage());
+ marker.setAttribute(
+ IMarker.SEVERITY,
+ (problem.isWarning() ? IMarker.SEVERITY_WARNING : IMarker.SEVERITY_ERROR));
+ this.requestor.acceptProblem(marker, new String(fragmentSource), fragmentKind);
+ } catch (CoreException e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBinaryType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBinaryType.java
new file mode 100644
index 0000000000..3dd3bee3af
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBinaryType.java
@@ -0,0 +1,230 @@
+package org.eclipse.jdt.internal.core.hierarchy;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
+
+public class HierarchyBinaryType implements IBinaryType {
+ private int modifiers;
+ private boolean isClass;
+ private char[] name;
+ private char[] enclosingTypeName;
+ private char[] superclass;
+ private char[][] superInterfaces = NoInterface;
+ public HierarchyBinaryType(
+ int modifiers,
+ char[] qualification,
+ char[] typeName,
+ char[] enclosingTypeName,
+ char classOrInterface) {
+
+ this.modifiers = modifiers;
+ this.isClass = classOrInterface == IIndexConstants.CLASS_SUFFIX;
+ this.name = CharOperation.concat(qualification, typeName, '/');
+ if (enclosingTypeName == null) {
+ this.name = CharOperation.concat(qualification, typeName, '/');
+ } else {
+ this.name =
+ CharOperation.concat(qualification, '/', enclosingTypeName, '$', typeName);
+ //rebuild A$B name
+ this.enclosingTypeName =
+ CharOperation.concat(qualification, enclosingTypeName, '/');
+ CharOperation.replace(this.enclosingTypeName, '.', '/');
+ }
+ CharOperation.replace(this.name, '.', '/');
+ }
+
+ /**
+ * Answer the resolved name of the enclosing type in the
+ * class file format as specified in section 4.2 of the Java 2 VM spec
+ * or null if the receiver is a top level type.
+ *
+ * For example, java.lang.String is java/lang/String.
+ */
+ public char[] getEnclosingTypeName() {
+ return this.enclosingTypeName;
+ }
+
+ /**
+ * Answer the receiver's fields or null if the array is empty.
+ */
+ public IBinaryField[] getFields() {
+ return null;
+ }
+
+ /**
+ * Answer the file name which defines the type.
+ *
+ * The path part (optional) must be separated from the actual
+ * file proper name by a java.io.File.separator.
+ *
+ * The proper file name includes the suffix extension (e.g. ".java")
+ *
+ * e.g. "c:/com/ibm/compiler/java/api/Compiler.java"
+ */
+ public char[] getFileName() {
+ return null;
+ }
+
+ /**
+ * Answer the resolved names of the receiver's interfaces in the
+ * class file format as specified in section 4.2 of the Java 2 VM spec
+ * or null if the array is empty.
+ *
+ * For example, java.lang.String is java/lang/String.
+ */
+ public char[][] getInterfaceNames() {
+ return superInterfaces;
+ }
+
+ /**
+ * Answer the receiver's nested types or null if the array is empty.
+ *
+ * This nested type info is extracted from the inner class attributes.
+ * Ask the name environment to find a member type using its compound name.
+ */
+ public IBinaryNestedType[] getMemberTypes() {
+ return null;
+ }
+
+ /**
+ * Answer the receiver's methods or null if the array is empty.
+ */
+ public IBinaryMethod[] getMethods() {
+ return null;
+ }
+
+ /**
+ * Answer an int whose bits are set according the access constants
+ * defined by the VM spec.
+ */
+ public int getModifiers() {
+ return modifiers;
+ }
+
+ /**
+ * Answer the resolved name of the type in the
+ * class file format as specified in section 4.2 of the Java 2 VM spec.
+ *
+ * For example, java.lang.String is java/lang/String.
+ */
+ public char[] getName() {
+ return name;
+ }
+
+ /**
+ * Answer the resolved name of the receiver's superclass in the
+ * class file format as specified in section 4.2 of the Java 2 VM spec
+ * or null if it does not have one.
+ *
+ * For example, java.lang.String is java/lang/String.
+ */
+ public char[] getSuperclassName() {
+ return superclass;
+ }
+
+ /**
+ * Answer whether the receiver contains the resolved binary form
+ * or the unresolved source form of the type.
+ */
+ public boolean isBinaryType() {
+ return true;
+ }
+
+ /**
+ * isClass method comment.
+ */
+ public boolean isClass() {
+ return isClass;
+ }
+
+ /**
+ * isInterface method comment.
+ */
+ public boolean isInterface() {
+ return !isClass;
+ }
+
+ public void recordSuperType(
+ char[] superTypeName,
+ char[] superQualification,
+ char superClassOrInterface) {
+
+ // index encoding of p.A$B was B/p.A$, rebuild the proper name
+ if (superQualification != null) {
+ int length = superQualification.length;
+ if (superQualification[length - 1] == '$') {
+ char[] enclosingSuperName = CharOperation.lastSegment(superQualification, '.');
+ superTypeName = CharOperation.concat(enclosingSuperName, superTypeName);
+ superQualification =
+ CharOperation.subarray(
+ superQualification,
+ 0,
+ length - enclosingSuperName.length - 1);
+ }
+ }
+
+ if (superClassOrInterface == IIndexConstants.CLASS_SUFFIX) {
+ // interfaces are indexed as having superclass references to Object by default,
+ // this is an artifact used for being able to query them only.
+ if (!this.isClass)
+ return;
+ char[] encodedName =
+ CharOperation.concat(superQualification, superTypeName, '/');
+ CharOperation.replace(encodedName, '.', '/');
+ this.superclass = encodedName;
+ } else {
+ char[] encodedName =
+ CharOperation.concat(superQualification, superTypeName, '/');
+ CharOperation.replace(encodedName, '.', '/');
+ if (this.superInterfaces == NoInterface) {
+ this.superInterfaces = new char[][] { encodedName };
+ } else {
+ int length = this.superInterfaces.length;
+ System.arraycopy(
+ this.superInterfaces,
+ 0,
+ this.superInterfaces = new char[length + 1][],
+ 0,
+ length);
+ this.superInterfaces[length] = encodedName;
+ }
+ }
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ if (this.modifiers == IConstants.AccPublic) {
+ buffer.append("public ");
+ }
+ if (this.isClass()) {
+ buffer.append("class ");
+ } else {
+ buffer.append("interface ");
+ }
+ if (this.name != null) {
+ buffer.append(this.name);
+ }
+ if (this.superclass != null) {
+ buffer.append("\n extends ");
+ buffer.append(this.superclass);
+ }
+ int length;
+ if (this.superInterfaces != null
+ && (length = this.superInterfaces.length) != 0) {
+ buffer.append("\n implements ");
+ for (int i = 0; i < length; i++) {
+ buffer.append(this.superInterfaces[i]);
+ if (i != length - 1) {
+ buffer.append(", ");
+ }
+ }
+ }
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBuilder.java
new file mode 100644
index 0000000000..398c269975
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBuilder.java
@@ -0,0 +1,204 @@
+package org.eclipse.jdt.internal.core.hierarchy;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+
+import org.eclipse.jdt.internal.compiler.HierarchyResolver;
+import org.eclipse.jdt.internal.compiler.IHierarchyRequestor;
+import org.eclipse.jdt.internal.compiler.env.IBinaryType;
+import org.eclipse.jdt.internal.compiler.env.IGenericType;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.core.*;
+
+import java.util.Hashtable;
+import java.util.Vector;
+
+public abstract class HierarchyBuilder implements IHierarchyRequestor {
+ /**
+ * The hierarchy being built.
+ */
+ protected TypeHierarchy hierarchy;
+
+ /**
+ * The name environment used by the HierarchyResolver
+ */
+ protected SearchableEnvironment searchableEnvironment;
+
+ /**
+ * @see INameLookup
+ */
+ protected INameLookup nameLookup;
+
+ /**
+ * The resolver used to resolve type hierarchies
+ * @see HierarchyResolver
+ */
+ protected HierarchyResolver hierarchyResolver;
+
+ /**
+ * A temporary cache of infos to handles to speed info
+ * to handle translation - it only contains the entries
+ * for the types in the region (i.e. no supertypes outside
+ * the region).
+ */
+ protected Hashtable infoToHandle;
+ public HierarchyBuilder(TypeHierarchy hierarchy) throws JavaModelException {
+ this.hierarchy = hierarchy;
+ JavaProject project = (JavaProject) hierarchy.javaProject();
+ this.searchableEnvironment =
+ (SearchableEnvironment) project.getSearchableNameEnvironment();
+ this.nameLookup = project.getNameLookup();
+ this.hierarchyResolver =
+ new HierarchyResolver(this.searchableEnvironment, this, new ProblemFactory());
+ this.infoToHandle = new Hashtable(5);
+ }
+
+ public abstract void build(boolean computeSubtypes)
+ throws JavaModelException, CoreException;
+ /**
+ * Configure this type hierarchy by computing the supertypes only.
+ */
+ protected void buildSupertypes() {
+ IType focusType = this.getType();
+ if (focusType == null)
+ return;
+
+ // get generic type from focus type
+ IGenericType type;
+ try {
+ type = (IGenericType) ((JavaElement) focusType).getRawInfo();
+ } catch (JavaModelException e) {
+ // if the focus type is not present, or if cannot get workbench path
+ // we cannot create the hierarchy
+ return;
+ }
+
+ // resolve
+ this.searchableEnvironment.unitToLookInside =
+ (CompilationUnit) focusType.getCompilationUnit();
+ this.hierarchyResolver.resolve(type);
+ this.searchableEnvironment.unitToLookInside = null;
+
+ // Add focus if not already in (case of a type with no explicit super type)
+ if (!this.hierarchy.contains(focusType)) {
+ this.hierarchy.addRootClass(focusType);
+ }
+ }
+
+ /**
+ * @see IHierarchyRequestor
+ */
+ public void connect(
+ IGenericType suppliedType,
+ IGenericType superclass,
+ IGenericType[] superinterfaces) {
+
+ this.worked(1);
+
+ // convert all infos to handles
+ IType typeHandle = getHandle(suppliedType);
+
+ /*
+ * Temporary workaround for 1G2O5WK: ITPJCORE:WINNT - NullPointerException when selecting "Show in Type Hierarchy" for a inner class
+ */
+ if (typeHandle == null)
+ return;
+
+ IType superHandle = null;
+ if (superclass != null) {
+ superHandle = getHandle(superclass);
+ }
+ IType[] interfaceHandles = null;
+ if (superinterfaces != null && superinterfaces.length > 0) {
+ interfaceHandles = new IType[superinterfaces.length];
+ for (int i = 0; i < interfaceHandles.length; i++) {
+ interfaceHandles[i] = getHandle(superinterfaces[i]);
+ }
+ }
+
+ // now do the caching
+ if (suppliedType.isClass()) {
+ if (superHandle == null) {
+ this.hierarchy.addRootClass(typeHandle);
+ } else {
+ this.hierarchy.cacheSuperclass(typeHandle, superHandle);
+ }
+ } else {
+ this.hierarchy.addInterface(typeHandle);
+ }
+
+ if (interfaceHandles == null) {
+ interfaceHandles = this.hierarchy.fgEmpty;
+ }
+ this.hierarchy.cacheSuperInterfaces(typeHandle, interfaceHandles);
+ }
+
+ /**
+ * Returns a handle for the given generic type or null if not found.
+ */
+ protected IType getHandle(IGenericType genericType) {
+ if (genericType.isBinaryType()) {
+ IClassFile classFile = (IClassFile) this.infoToHandle.get(genericType);
+ // if it's null, it's from outside the region, so do lookup
+ if (classFile == null) {
+ IType handle = lookupBinaryHandle((IBinaryType) genericType);
+ if (handle == null)
+ return null;
+ // case of an anonymous type (see 1G2O5WK: ITPJCORE:WINNT - NullPointerException when selecting "Show in Type Hierarchy" for a inner class)
+
+ // optimization: remember the handle for next call (case of java.io.Serializable that a lot of classes implement)
+ this.infoToHandle.put(genericType, handle.getParent());
+ return handle;
+ } else {
+ try {
+ return classFile.getType();
+ } catch (JavaModelException e) {
+ return null;
+ }
+ }
+ } else
+ if (genericType instanceof SourceTypeElementInfo) {
+ return ((SourceTypeElementInfo) genericType).getHandle();
+ } else
+ return null;
+ }
+
+ protected IType getType() {
+ return this.hierarchy.getType();
+ }
+
+ /**
+ * Looks up and returns a handle for the given binary info.
+ */
+ protected IType lookupBinaryHandle(IBinaryType typeInfo) {
+ int flag;
+ String qualifiedName;
+ if (typeInfo.isClass()) {
+ flag = this.nameLookup.ACCEPT_CLASSES;
+ } else {
+ flag = this.nameLookup.ACCEPT_INTERFACES;
+ }
+ char[] bName = typeInfo.getName();
+ qualifiedName = new String(ClassFile.translatedName(bName));
+ return this.nameLookup.findType(qualifiedName, false, flag);
+ }
+
+ protected void worked(int work) {
+ IProgressMonitor progressMonitor = this.hierarchy.fProgressMonitor;
+ if (progressMonitor != null) {
+ if (progressMonitor.isCanceled()) {
+ throw new OperationCanceledException();
+ } else {
+ progressMonitor.worked(work);
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java
new file mode 100644
index 0000000000..c306256693
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java
@@ -0,0 +1,557 @@
+package org.eclipse.jdt.internal.core.hierarchy;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.search.*;
+import java.util.*;
+
+import org.eclipse.jdt.internal.core.search.matching.SuperTypeReferencePattern;
+import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
+import org.eclipse.jdt.internal.core.search.matching.SearchPattern;
+import org.eclipse.jdt.internal.compiler.HierarchyType;
+import org.eclipse.jdt.internal.compiler.HierarchyResolver;
+import org.eclipse.jdt.internal.core.search.*;
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+import org.eclipse.jdt.internal.compiler.env.IGenericType;
+import org.eclipse.jdt.internal.core.search.indexing.AbstractIndexer;
+import org.eclipse.jdt.internal.core.*;
+import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+
+public class IndexBasedHierarchyBuilder extends HierarchyBuilder {
+ /**
+ * A temporary cache of compilation units to handles to speed info
+ * to handle translation - it only contains the entries
+ * for the types in the region (i.e. no supertypes outside
+ * the region).
+ */
+ protected Hashtable cuToHandle;
+
+ /**
+ * The scope this hierarchy builder should restrain results to.
+ */
+ protected IJavaSearchScope scope;
+
+ /**
+ * Cache used to record binaries recreated from index matches
+ */
+ protected Hashtable binariesFromIndexMatches;
+
+ /**
+ * Collection used to queue subtype index queries
+ */
+ private static class Queue {
+ public char[][] names = new char[10][];
+ public int start = 0;
+ public int end = -1;
+ public void add(char[] name) {
+ if (++this.end == this.names.length) {
+ this.end -= this.start;
+ System.arraycopy(
+ this.names,
+ this.start,
+ this.names = new char[this.end * 2][],
+ 0,
+ this.end);
+ this.start = 0;
+ }
+ this.names[this.end] = name;
+ }
+ public char[] retrieve() {
+ if (this.start > this.end)
+ return null; // none
+
+ char[] name = this.names[this.start++];
+ if (this.start > this.end) {
+ this.start = 0;
+ this.end = -1;
+ }
+ return name;
+ }
+ public String toString() {
+ StringBuffer buffer = new StringBuffer("Queue:\n");
+ for (int i = this.start; i <= this.end; i++) {
+ buffer.append(names[i]).append('\n');
+ }
+ return buffer.toString();
+ }
+ }
+
+ public IndexBasedHierarchyBuilder(
+ TypeHierarchy hierarchy,
+ IJavaSearchScope scope)
+ throws JavaModelException {
+ super(hierarchy);
+ this.cuToHandle = new Hashtable(5);
+ this.binariesFromIndexMatches = new Hashtable(10);
+ this.scope = scope;
+ }
+
+ /**
+ * Add the type info from the given hierarchy binary type to the given list of infos.
+ */
+ private void addInfoFromBinaryIndexMatch(
+ Openable handle,
+ HierarchyBinaryType binaryType,
+ Vector infos)
+ throws JavaModelException {
+ infos.addElement(binaryType);
+ this.infoToHandle.put(binaryType, handle);
+ }
+
+ /**
+ * Add the type info from the given class file to the given list of infos.
+ */
+ private void addInfoFromOpenClassFile(ClassFile classFile, Vector infos)
+ throws JavaModelException {
+ IType type = classFile.getType();
+ IGenericType info = (IGenericType) ((BinaryType) type).getRawInfo();
+ infos.addElement(info);
+ this.infoToHandle.put(info, classFile);
+ }
+
+ /**
+ * Add the type info from the given CU to the given list of infos.
+ */
+ private void addInfoFromOpenCU(CompilationUnit cu, Vector infos)
+ throws JavaModelException {
+ IType[] types = cu.getTypes();
+ for (int j = 0; j < types.length; j++) {
+ SourceType type = (SourceType) types[j];
+ this.addInfoFromOpenSourceType(type, infos);
+ }
+ }
+
+ /**
+ * Add the type info from the given CU to the given list of infos.
+ */
+ private void addInfoFromOpenSourceType(SourceType type, Vector infos)
+ throws JavaModelException {
+ IGenericType info = (IGenericType) type.getRawInfo();
+ infos.addElement(info);
+ this.infoToHandle.put(info, type);
+ IType[] members = type.getTypes();
+ for (int i = 0; i < members.length; i++) {
+ this.addInfoFromOpenSourceType((SourceType) members[i], infos);
+ }
+ }
+
+ public void build(boolean computeSubtypes)
+ throws JavaModelException, CoreException {
+ if (computeSubtypes) {
+ String[] allPossibleSubtypes = this.determinePossibleSubTypes();
+ if (allPossibleSubtypes != null) {
+ this.hierarchy.initialize(allPossibleSubtypes.length);
+ buildFromPotentialSubtypes(allPossibleSubtypes);
+ }
+ } else {
+ this.hierarchy.initialize(1);
+ this.buildSupertypes();
+ }
+ }
+
+ private void buildForProject(JavaProject project, Vector infos, Vector units)
+ throws JavaModelException {
+ IType focusType = this.getType();
+ if (focusType != null && focusType.getJavaProject().equals(project)) {
+ // add focus type
+ try {
+ infos.addElement(((JavaElement) focusType).getRawInfo());
+ } catch (JavaModelException e) {
+ // if the focus type is not present, or if cannot get workbench path
+ // we cannot create the hierarchy
+ return;
+ }
+ }
+
+ // copy vectors into arrays
+ IGenericType[] genericTypes;
+ int infosSize = infos.size();
+ if (infosSize > 0) {
+ genericTypes = new IGenericType[infosSize];
+ infos.copyInto(genericTypes);
+ } else {
+ genericTypes = new IGenericType[0];
+ }
+ ICompilationUnit[] compilationUnits;
+ int unitsSize = units.size();
+ if (unitsSize > 0) {
+ compilationUnits = new ICompilationUnit[unitsSize];
+ units.copyInto(compilationUnits);
+ } else {
+ compilationUnits = new ICompilationUnit[0];
+ }
+
+ // resolve
+ if (infosSize > 0 || unitsSize > 0) {
+ this.searchableEnvironment =
+ (SearchableEnvironment) project.getSearchableNameEnvironment();
+ if (focusType != null && focusType.getJavaProject().equals(project)) {
+ this.searchableEnvironment.unitToLookInside =
+ (CompilationUnit) focusType.getCompilationUnit();
+ }
+ this.nameLookup = project.getNameLookup();
+ this.hierarchyResolver =
+ new HierarchyResolver(this.searchableEnvironment, this, new ProblemFactory());
+ this.hierarchyResolver.resolve(genericTypes, compilationUnits);
+ if (focusType != null && focusType.getJavaProject().equals(project)) {
+ this.searchableEnvironment.unitToLookInside = null;
+ }
+ }
+ }
+
+ /**
+ * Configure this type hierarchy based on the given potential subtypes.
+ */
+ private void buildFromPotentialSubtypes(String[] allPotentialSubTypes) {
+ // sort by projects
+ /*
+ * NOTE: To workaround pb with hierarchy resolver that requests top
+ * level types in the process of caching an enclosing type, this needs to
+ * be sorted in reverse alphabetical order so that top level types are cached
+ * before their inner types.
+ */
+ Util.sortReverseOrder(allPotentialSubTypes);
+
+ Vector infos = new Vector();
+ Vector units = new Vector();
+
+ IType focusType = this.getType();
+
+ // create element infos for subtypes
+ JavaModelManager manager = JavaModelManager.getJavaModelManager();
+ IWorkspace workspace = focusType.getJavaProject().getProject().getWorkspace();
+ HandleFactory factory = new HandleFactory(workspace.getRoot(), manager);
+ IJavaProject currentProject = null;
+ for (int i = 0, length = allPotentialSubTypes.length; i < length; i++) {
+ try {
+ String resourcePath = allPotentialSubTypes[i];
+ Openable handle = factory.createOpenable(resourcePath);
+ if (handle == null)
+ continue; // match is outside classpath
+ IJavaProject project = handle.getJavaProject();
+ if (currentProject == null) {
+ currentProject = project;
+ infos = new Vector(5);
+ units = new Vector(5);
+ } else
+ if (!currentProject.equals(project)) {
+ this.buildForProject((JavaProject) currentProject, infos, units);
+ currentProject = project;
+ infos = new Vector(5);
+ units = new Vector(5);
+ }
+ if (handle.isOpen()) {
+ // reuse the info from the java model cache
+ if (handle instanceof CompilationUnit) {
+ this.addInfoFromOpenCU((CompilationUnit) handle, infos);
+ } else
+ if (handle instanceof ClassFile) {
+ this.addInfoFromOpenClassFile((ClassFile) handle, infos);
+ }
+ } else {
+ HierarchyBinaryType binaryType =
+ (HierarchyBinaryType) binariesFromIndexMatches.get(resourcePath);
+ if (binaryType != null) {
+ this.addInfoFromBinaryIndexMatch(handle, binaryType, infos);
+ } else {
+ // create a temporary info
+ IJavaElement pkg = handle.getParent();
+ PackageFragmentRoot root = (PackageFragmentRoot) pkg.getParent();
+ if (root.isArchive()) {
+ // class file in a jar
+ this.createInfoFromClassFileInJar(handle, infos);
+ } else {
+ // file in a directory
+ IPath path = new Path(resourcePath);
+ IFile file = workspace.getRoot().getFile(path);
+ String osPath = file.getLocation().toOSString();
+ if (handle instanceof CompilationUnit) {
+ // compilation unit in a directory
+ this.createCompilationUnitFromPath(handle, osPath, units);
+ } else
+ if (handle instanceof ClassFile) {
+ // class file in a directory
+ this.createInfoFromClassFile(handle, osPath, infos);
+ }
+ }
+ }
+ }
+ worked(1);
+ } catch (JavaModelException e) {
+ continue;
+ }
+ }
+ try {
+ if (currentProject == null)
+ currentProject = focusType.getJavaProject(); // case of no potential subtypes
+ this.buildForProject((JavaProject) currentProject, infos, units);
+ } catch (JavaModelException e) {
+ }
+
+ // Add focus if not already in (case of a type with no explicit super type)
+ if (!this.hierarchy.contains(focusType)) {
+ this.hierarchy.addRootClass(focusType);
+ }
+ }
+
+ /**
+ * Create an ICompilationUnit info from the given compilation unit on disk and
+ * adds it to the given list of units.
+ */
+ private void createCompilationUnitFromPath(
+ Openable handle,
+ String osPath,
+ Vector units)
+ throws JavaModelException {
+ BasicCompilationUnit unit = new BasicCompilationUnit(null, osPath);
+ units.addElement(unit);
+ this.cuToHandle.put(unit, handle);
+ }
+
+ /**
+ * Creates the type info from the given class file on disk and
+ * adds it to the given list of infos.
+ */
+ private void createInfoFromClassFile(
+ Openable handle,
+ String osPath,
+ Vector infos)
+ throws JavaModelException {
+ IGenericType info = null;
+ try {
+ info = org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader.read(osPath);
+ } catch (org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException e) {
+ e.printStackTrace();
+ return;
+ } catch (java.io.IOException e) {
+ e.printStackTrace();
+ return;
+ }
+ infos.addElement(info);
+ this.infoToHandle.put(info, handle);
+ }
+
+ /**
+ * Create a type info from the given class file in a jar and adds it to the given list of infos.
+ */
+ private void createInfoFromClassFileInJar(Openable classFile, Vector infos)
+ throws JavaModelException {
+ IJavaElement pkg = classFile.getParent();
+ String classFilePath =
+ pkg.getElementName().replace('.', '/') + "/" + classFile.getElementName();
+ IGenericType info = null;
+ java.util.zip.ZipFile zipFile = null;
+ try {
+ zipFile = ((JarPackageFragmentRoot) pkg.getParent()).getJar();
+ info =
+ org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader.read(
+ zipFile,
+ classFilePath);
+ } catch (org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException e) {
+ e.printStackTrace();
+ return;
+ } catch (java.io.IOException e) {
+ e.printStackTrace();
+ return;
+ } catch (CoreException e) {
+ e.printStackTrace();
+ return;
+ } finally {
+ if (zipFile != null) {
+ try {
+ zipFile.close();
+ } catch (java.io.IOException e) {
+ // ignore
+ }
+ }
+ }
+ infos.addElement(info);
+ this.infoToHandle.put(info, classFile);
+ }
+
+ /**
+ * Returns all of the possible subtypes of this type hierarchy.
+ * Returns null if they could not be determine.
+ */
+ private String[] determinePossibleSubTypes()
+ throws JavaModelException, CoreException {
+
+ class PathCollector implements IPathRequestor {
+ Hashtable paths = new Hashtable(10);
+ public void acceptPath(String path) {
+ paths.put(path, path);
+ }
+ }
+ PathCollector collector = new PathCollector();
+ IProject project = this.hierarchy.javaProject().getProject();
+
+ searchAllPossibleSubTypes(
+ project.getWorkspace(),
+ this.getType(),
+ this.scope,
+ this.binariesFromIndexMatches,
+ collector,
+ IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
+ this.hierarchy.fProgressMonitor);
+
+ Hashtable paths = collector.paths;
+ int length = paths.size();
+ String[] result = new String[length];
+ int count = 0;
+ for (Enumeration elements = paths.elements(); elements.hasMoreElements();) {
+ result[count++] = (String) elements.nextElement();
+ }
+ return result;
+ }
+
+ /**
+ * Returns a handle for the given generic type or null if not found.
+ */
+ protected IType getHandle(IGenericType genericType) {
+ if (genericType instanceof HierarchyType) {
+ IType type = (IType) this.infoToHandle.get(genericType);
+ if (type == null) {
+ HierarchyType hierarchyType = (HierarchyType) genericType;
+ CompilationUnit unit =
+ (CompilationUnit) this.cuToHandle.get(hierarchyType.originatingUnit);
+
+ // collect enclosing type names
+ Vector enclosingTypeNames = new Vector();
+ HierarchyType enclosingType = hierarchyType;
+ do {
+ enclosingTypeNames.addElement(enclosingType.name);
+ enclosingType = enclosingType.enclosingType;
+ } while (enclosingType != null);
+ int length = enclosingTypeNames.size();
+ char[][] simpleTypeNames = new char[length][];
+ enclosingTypeNames.copyInto(simpleTypeNames);
+
+ // build handle
+ type = unit.getType(new String(simpleTypeNames[length - 1]));
+ for (int i = length - 2; i >= 0; i--) {
+ type = type.getType(new String(simpleTypeNames[i]));
+ }
+ this.infoToHandle.put(genericType, type);
+ }
+ return type;
+ } else
+ return super.getHandle(genericType);
+ }
+
+ /**
+ * Find the set of candidate subtypes of a given type.
+ *
+ * The requestor is notified of super type references (with actual path of
+ * its occurrence) for all types which are potentially involved inside a particular
+ * hierarchy.
+ * The match locator is not used here to narrow down the results, the type hierarchy
+ * resolver is rather used to compute the whole hierarchy at once.
+ */
+
+ public static void searchAllPossibleSubTypes(
+ IWorkspace workbench,
+ IType type,
+ IJavaSearchScope scope,
+ final Hashtable binariesFromIndexMatches,
+ final IPathRequestor pathRequestor,
+ int waitingPolicy,
+ // WaitUntilReadyToSearch | ForceImmediateSearch | CancelIfNotReadyToSearch
+ IProgressMonitor progressMonitor) throws JavaModelException, CoreException {
+
+ /* embed constructs inside arrays so as to pass them to (inner) collector */
+ final Queue awaitings = new Queue();
+ final HashtableOfObject foundSuperNames = new HashtableOfObject(5);
+
+ IndexManager indexManager =
+ ((JavaModelManager) JavaModelManager.getJavaModelManager()).getIndexManager();
+ if (indexManager == null)
+ return;
+
+ /* use a special collector to collect paths and queue new subtype names */
+ IIndexSearchRequestor searchRequestor = new IndexSearchAdapter() {
+ public void acceptSuperTypeReference(
+ String resourcePath,
+ char[] qualification,
+ char[] typeName,
+ char[] enclosingTypeName,
+ char classOrInterface,
+ char[] superQualification,
+ char[] superTypeName,
+ char superClassOrInterface,
+ int modifiers) {
+ pathRequestor.acceptPath(resourcePath);
+ if (resourcePath.endsWith("class")) {
+ HierarchyBinaryType binaryType =
+ (HierarchyBinaryType) binariesFromIndexMatches.get(resourcePath);
+ if (binaryType == null) {
+ binaryType =
+ new HierarchyBinaryType(
+ modifiers,
+ qualification,
+ typeName,
+ enclosingTypeName,
+ classOrInterface);
+ binariesFromIndexMatches.put(resourcePath, binaryType);
+ }
+ binaryType.recordSuperType(
+ superTypeName,
+ superQualification,
+ superClassOrInterface);
+ }
+ if (!foundSuperNames.containsKey(typeName)) {
+ foundSuperNames.put(typeName, typeName);
+ awaitings.add(typeName);
+ }
+ }
+ };
+
+ SuperTypeReferencePattern pattern =
+ new SuperTypeReferencePattern(
+ null,
+ null,
+ IJavaSearchConstants.EXACT_MATCH,
+ IJavaSearchConstants.CASE_SENSITIVE);
+ SubTypeSearchJob job =
+ new SubTypeSearchJob(
+ pattern,
+ scope,
+ type,
+ IInfoConstants.PathInfo,
+ searchRequestor,
+ indexManager,
+ progressMonitor);
+
+ /* iterate all queued names */
+ awaitings.add(type.getElementName().toCharArray());
+ while (awaitings.start <= awaitings.end) {
+ if (progressMonitor != null && progressMonitor.isCanceled())
+ return;
+
+ char[] currentTypeName = awaitings.retrieve();
+
+ /* all subclasses of OBJECT are actually all types */
+ if (CharOperation.equals(currentTypeName, AbstractIndexer.OBJECT)) {
+ currentTypeName = null;
+ }
+ /* search all index references to a given supertype */
+ pattern.superSimpleName = currentTypeName;
+ indexManager.performConcurrentJob(job, waitingPolicy, progressMonitor);
+ /* in case, we search all subtypes, no need to search further */
+ if (currentTypeName == null)
+ break;
+ }
+ /* close all cached index inputs */
+ job.closeAll();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/RegionBasedHierarchyBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/RegionBasedHierarchyBuilder.java
new file mode 100644
index 0000000000..ca1bc34c92
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/RegionBasedHierarchyBuilder.java
@@ -0,0 +1,213 @@
+package org.eclipse.jdt.internal.core.hierarchy;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.jdt.internal.compiler.env.IGenericType;
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.core.*;
+
+import java.util.Hashtable;
+import java.util.Vector;
+
+public class RegionBasedHierarchyBuilder extends HierarchyBuilder {
+ public RegionBasedHierarchyBuilder(TypeHierarchy hierarchy)
+ throws JavaModelException {
+ super(hierarchy);
+ }
+
+ public void build(boolean computeSubtypes) {
+ if (this.hierarchy.fType == null || computeSubtypes) {
+ Vector allTypesInRegion = determineTypesInRegion();
+ this.hierarchy.initialize(allTypesInRegion.size());
+ createTypeHierarchyBasedOnRegion(allTypesInRegion);
+ } else {
+ this.hierarchy.initialize(1);
+ this.buildSupertypes();
+ }
+ }
+
+ /**
+ * Configure this type hierarchy that is based on a region.
+ */
+ private void createTypeHierarchyBasedOnRegion(Vector allTypesInRegion) {
+ int size = allTypesInRegion.size();
+ if (size != 0) {
+ this.infoToHandle = new Hashtable(size);
+ }
+ Vector temp = new Vector(size);
+ types : for (int i = 0; i < size; i++) {
+ try {
+ IType type = (IType) allTypesInRegion.elementAt(i);
+ IGenericType info = (IGenericType) ((JavaElement) type).getRawInfo();
+ temp.addElement(info);
+ if (info.isBinaryType()) {
+ this.infoToHandle.put(info, type.getParent());
+ }
+ worked(1);
+ } catch (JavaModelException npe) {
+ continue types;
+ }
+ }
+
+ size = temp.size();
+ if (size > 0) {
+ IGenericType[] genericTypes = new IGenericType[size];
+ temp.copyInto(genericTypes);
+ IType focusType = this.getType();
+ if (focusType != null) {
+ this.searchableEnvironment.unitToLookInside =
+ (CompilationUnit) focusType.getCompilationUnit();
+ }
+ this.hierarchyResolver.resolve(genericTypes);
+ if (focusType != null) {
+ this.searchableEnvironment.unitToLookInside = null;
+ }
+
+ }
+ }
+
+ /**
+ * Returns all of the types defined in the region of this type hierarchy.
+ */
+ private Vector determineTypesInRegion() {
+
+ Vector types = new Vector();
+ IJavaElement[] roots =
+ ((RegionBasedTypeHierarchy) this.hierarchy).fRegion.getElements();
+ for (int i = 0; i < roots.length; i++) {
+ try {
+ IJavaElement root = roots[i];
+ switch (root.getElementType()) {
+ case IJavaElement.JAVA_PROJECT :
+ injectAllTypesForJavaProject((IJavaProject) root, types);
+ break;
+ case IJavaElement.PACKAGE_FRAGMENT_ROOT :
+ injectAllTypesForPackageFragmentRoot((IPackageFragmentRoot) root, types);
+ break;
+ case IJavaElement.PACKAGE_FRAGMENT :
+ injectAllTypesForPackageFragment((IPackageFragment) root, types);
+ break;
+ case IJavaElement.CLASS_FILE :
+ types.addElement(((IClassFile) root).getType());
+ break;
+ case IJavaElement.COMPILATION_UNIT :
+ IType[] cuTypes = ((ICompilationUnit) root).getAllTypes();
+ for (int j = 0; j < cuTypes.length; j++) {
+ types.addElement(cuTypes[j]);
+ }
+ break;
+ case IJavaElement.TYPE :
+ types.addElement(root);
+ break;
+ default :
+ break;
+ }
+ } catch (JavaModelException npe) {
+ // just continue
+ }
+ }
+ return types;
+ }
+
+ /**
+ * Adds all of the types defined within this java project to the
+ * vector.
+ */
+ private void injectAllTypesForJavaProject(IJavaProject project, Vector types) {
+ try {
+ IPackageFragmentRoot[] devPathRoots =
+ ((JavaProject) project).getPackageFragmentRoots();
+ if (devPathRoots == null) {
+ return;
+ }
+ for (int j = 0; j < devPathRoots.length; j++) {
+ IPackageFragmentRoot root = devPathRoots[j];
+ injectAllTypesForPackageFragmentRoot(root, types);
+ }
+ } catch (JavaModelException e) {
+ }
+ }
+
+ /**
+ * Adds all of the types defined within this package fragment to the
+ * vector.
+ */
+ private void injectAllTypesForPackageFragment(
+ IPackageFragment packFrag,
+ Vector types) {
+ try {
+ IPackageFragmentRoot root = (IPackageFragmentRoot) packFrag.getParent();
+ int kind = root.getKind();
+ if (kind != 0) {
+ boolean isSourcePackageFragment = (kind == IPackageFragmentRoot.K_SOURCE);
+ if (isSourcePackageFragment) {
+ ICompilationUnit[] typeContainers = packFrag.getCompilationUnits();
+ injectAllTypesForTypeContainers(typeContainers, types);
+ } else {
+ IClassFile[] typeContainers = packFrag.getClassFiles();
+ injectAllTypesForTypeContainers(typeContainers, types);
+ }
+ }
+ } catch (JavaModelException npe) {
+ }
+ }
+
+ /**
+ * Adds all of the types defined within this package fragment root to the
+ * vector.
+ */
+ private void injectAllTypesForPackageFragmentRoot(
+ IPackageFragmentRoot root,
+ Vector types) {
+ try {
+ IJavaElement[] packFrags = root.getChildren();
+ for (int k = 0; k < packFrags.length; k++) {
+ IPackageFragment packFrag = (IPackageFragment) packFrags[k];
+ injectAllTypesForPackageFragment(packFrag, types);
+ }
+ } catch (JavaModelException npe) {
+ return;
+ }
+ }
+
+ /**
+ * Adds all of the types defined within the type containers (IClassFile).
+ */
+ private void injectAllTypesForTypeContainers(
+ IClassFile[] containers,
+ Vector types) {
+ try {
+ for (int i = 0; i < containers.length; i++) {
+ IClassFile cf = containers[i];
+ types.addElement(cf.getType());
+ this.worked(1);
+ }
+ } catch (JavaModelException npe) {
+ }
+ }
+
+ /**
+ * Adds all of the types defined within the type containers (ICompilationUnit).
+ */
+ private void injectAllTypesForTypeContainers(
+ ICompilationUnit[] containers,
+ Vector types) {
+ try {
+ for (int i = 0; i < containers.length; i++) {
+ ICompilationUnit cu = containers[i];
+ IType[] cuTypes = cu.getAllTypes();
+ for (int j = 0; j < cuTypes.length; j++) {
+ types.addElement(cuTypes[j]);
+ }
+ this.worked(1);
+ }
+ } catch (JavaModelException npe) {
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/RegionBasedTypeHierarchy.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/RegionBasedTypeHierarchy.java
new file mode 100644
index 0000000000..a79c4ade3b
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/RegionBasedTypeHierarchy.java
@@ -0,0 +1,118 @@
+package org.eclipse.jdt.internal.core.hierarchy;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.core.IRegion;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IJavaElementDelta;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.IOpenable;
+import org.eclipse.jdt.internal.core.Openable;
+import org.eclipse.jdt.internal.core.JavaElement;
+import org.eclipse.jdt.internal.core.Region;
+import org.eclipse.jdt.internal.core.CompilationUnit;
+
+public class RegionBasedTypeHierarchy extends TypeHierarchy {
+ /**
+ * The region of types for which to build the hierarchy
+ */
+ protected IRegion fRegion;
+
+ /**
+ * The Java Project in which the hierarchy is being built - this
+ * provides the context (i.e. classpath and namelookup rules)
+ */
+ protected IJavaProject fProject;
+ /**
+ * Creates a TypeHierarchy on the types in the specified region,
+ * using the given project for a name lookup contenxt. If a specific
+ * type is also specified, the type hierarchy is pruned to only
+ * contain the branch including the specified type.
+ */
+ public RegionBasedTypeHierarchy(
+ IRegion region,
+ IJavaProject project,
+ IType type,
+ boolean computeSubtypes)
+ throws JavaModelException {
+ super(type, null, computeSubtypes);
+ fRegion = region;
+ fProject = project;
+ }
+
+ /**
+ * Activates this hierarchy for change listeners
+ */
+ protected void activate() {
+ super.activate();
+ IJavaElement[] roots = fRegion.getElements();
+ for (int i = 0; i < roots.length; i++) {
+ IJavaElement root = roots[i];
+ if (root instanceof IOpenable) {
+ this.files.put(root, root);
+ } else {
+ Openable o = (Openable) ((JavaElement) root).getOpenableParent();
+ if (o != null) {
+ this.files.put(o, o);
+ }
+ }
+ checkCanceled();
+ }
+ }
+
+ /**
+ * Compute this type hierarchy.
+ */
+ protected void compute() throws JavaModelException, CoreException {
+ HierarchyBuilder builder = new RegionBasedHierarchyBuilder(this);
+ builder.build(this.computeSubtypes);
+ }
+
+ protected void destroy() {
+ fRegion = new Region();
+ super.destroy();
+ }
+
+ protected boolean isAffectedByType(
+ IJavaElementDelta delta,
+ IJavaElement element) {
+ // ignore changes to working copies
+ if (element instanceof CompilationUnit
+ && ((CompilationUnit) element).isWorkingCopy()) {
+ return false;
+ }
+
+ // if no focus, hierarchy is affected if the element is part of the region
+ if (fType == null) {
+ return fRegion.contains(element);
+ } else {
+ return super.isAffectedByType(delta, element);
+ }
+ }
+
+ /**
+ * Returns the java project this hierarchy was created in.
+ */
+ public IJavaProject javaProject() {
+ return fProject;
+ }
+
+ protected void pruneTypeHierarchy(IType type, IProgressMonitor monitor)
+ throws JavaModelException {
+ // there is no pruning to do if the hierarchy was created for the single type
+ IJavaElement[] roots = fRegion.getElements();
+ if (roots.length == 1 && roots[0].equals(type)) {
+ return;
+ }
+
+ super.pruneTypeHierarchy(type, monitor);
+ }
+
+}
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
new file mode 100644
index 0000000000..3d51b1ab2c
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java
@@ -0,0 +1,1297 @@
+package org.eclipse.jdt.internal.core.hierarchy;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.core.ElementChangedEvent;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IElementChangedListener;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaElementDelta;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.ITypeHierarchy;
+import org.eclipse.jdt.core.ITypeHierarchyChangedListener;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.*;
+import org.eclipse.jdt.internal.core.search.*;
+
+import java.util.*;
+import java.util.zip.ZipFile;
+
+/**
+ * @see ITypeHierarchy
+ */
+public class TypeHierarchy implements ITypeHierarchy, IElementChangedListener {
+ /**
+ * The type the hierarchy was specifically computed for,
+ * possibly null.
+ */
+ protected IType fType;
+
+ protected Hashtable fClassToSuperclass;
+ protected Hashtable fTypeToSuperInterfaces;
+ protected Hashtable fTypeToSubtypes;
+ protected TypeVector fRootClasses = new TypeVector();
+ protected Vector fInterfaces = new Vector(10);
+
+ protected static final IType[] fgEmpty = new IType[0];
+
+ /**
+ * The progress monitor to report work completed too.
+ */
+ protected IProgressMonitor fProgressMonitor = null;
+
+ /**
+ * Change listeners - null if no one is listening.
+ */
+ protected Vector fChangeListeners = null;
+
+ /**
+ * A set of the compilation units and class
+ * files that are considered in this hierarchy. Null if
+ * not activated.
+ */
+ protected Hashtable files = null;
+
+ /**
+ * A region describing the packages considered by this
+ * hierarchy. Null if not activated.
+ */
+ protected Region fPackageRegion = null;
+
+ /**
+ * A region describing the package fragment roots considered by this
+ * hierarchy. Null if not activated.
+ */
+ protected Region fRootRegion = null;
+
+ /**
+ * A region describing the projects considered by this
+ * hierarchy. Null if not activated.
+ */
+ protected Region fProjectRegion = null;
+
+ /**
+ * A boolean indicating if this hierarchy is actively tracking changes
+ * in the Java Model.
+ */
+ protected boolean fIsActivated = false;
+
+ /**
+ * A boolean indicating if the hierarchy exists
+ *
+ * fix for 1FW67PA
+ */
+ protected boolean fExists = true;
+
+ /**
+ * Whether this hierarchy should contains subtypes.
+ */
+ protected boolean computeSubtypes;
+
+ /**
+ * The scope this hierarchy should restrain itsef in.
+ */
+ IJavaSearchScope scope;
+
+ /**
+ * Creates a TypeHierarchy on the given type.
+ */
+ public TypeHierarchy(
+ IType type,
+ IJavaSearchScope scope,
+ boolean computeSubtypes)
+ throws JavaModelException {
+ fType = type;
+ this.computeSubtypes = computeSubtypes;
+ this.scope = scope;
+ }
+
+ /**
+ * Activates this hierarchy for change listeners
+ */
+ protected void activate() {
+
+ // determine my file, package, root, & project regions.
+ this.files = new Hashtable(5);
+ fProjectRegion = new Region();
+ fPackageRegion = new Region();
+ fRootRegion = new Region();
+ IType[] types = getAllTypes();
+ for (int i = 0; i < types.length; i++) {
+ IType type = types[i];
+ Openable o = (Openable) ((JavaElement) type).getOpenableParent();
+ if (o != null) {
+ this.files.put(o, o);
+ }
+ IPackageFragment pkg = type.getPackageFragment();
+ fPackageRegion.add(pkg);
+ fRootRegion.add(pkg.getParent());
+ IJavaProject project = type.getJavaProject();
+ if (project != null) {
+ fProjectRegion.add(project);
+ }
+ checkCanceled();
+ }
+ JavaModelManager.getJavaModelManager().addElementChangedListener(this);
+ fIsActivated = true;
+ }
+
+ /**
+ * Adds all of the elements in the collection to the vector if the
+ * element is not already in the vector.
+ */
+ private void addAllCheckingDuplicates(Vector vector, IType[] collection) {
+ for (int i = 0; i < collection.length; i++) {
+ IType element = collection[i];
+ if (!vector.contains(element)) {
+ vector.addElement(element);
+ }
+ }
+ }
+
+ /**
+ * Adds the type to the collection of interfaces.
+ */
+ protected void addInterface(IType type) {
+ fInterfaces.addElement(type);
+ }
+
+ /**
+ * Adds the type to the collection of root classes
+ * if the classes is not already present in the collection.
+ */
+ protected void addRootClass(IType type) {
+ if (fRootClasses.contains(type))
+ return;
+ fRootClasses.add(type);
+ }
+
+ /**
+ * Adds the given subtype to the type.
+ */
+ protected void addSubtype(IType type, IType subtype) {
+ TypeVector subtypes = (TypeVector) fTypeToSubtypes.get(type);
+ if (subtypes == null) {
+ subtypes = new TypeVector();
+ fTypeToSubtypes.put(type, subtypes);
+ }
+ if (!subtypes.contains(subtype)) {
+ subtypes.add(subtype);
+ }
+ }
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public void addTypeHierarchyChangedListener(ITypeHierarchyChangedListener listener) {
+ if (fChangeListeners == null) {
+ fChangeListeners = new Vector();
+ // fix for 1FW67PA
+ if (fExists) {
+ activate();
+ }
+ }
+ // add listener only if it is not already present
+ if (fChangeListeners.indexOf(listener) == -1) {
+ fChangeListeners.addElement(listener);
+ }
+ }
+
+ /**
+ * Caches the handle of the superclass for the specified type.
+ * As a side effect cache this type as a subtype of the superclass.
+ */
+ protected void cacheSuperclass(IType type, IType superclass) {
+ if (superclass != null) {
+ fClassToSuperclass.put(type, superclass);
+ addSubtype(superclass, type);
+ }
+ }
+
+ /**
+ * Caches all of the superinterfaces that are specified for the
+ * type.
+ */
+ protected void cacheSuperInterfaces(IType type, IType[] superinterfaces) {
+ fTypeToSuperInterfaces.put(type, superinterfaces);
+ for (int i = 0; i < superinterfaces.length; i++) {
+ IType superinterface = superinterfaces[i];
+ if (superinterface != null) {
+ addSubtype(superinterface, type);
+ }
+ }
+ }
+
+ /**
+ * Checks with the progress monitor to see whether the creation of the type hierarchy
+ * should be canceled. Should be regularly called
+ * so that the user can cancel.
+ *
+ * @exception OperationCanceledException if cancelling the operation has been requested
+ * @see IProgressMonitor#isCanceled
+ */
+ protected void checkCanceled() {
+ if (fProgressMonitor != null && fProgressMonitor.isCanceled()) {
+ throw new OperationCanceledException();
+ }
+ }
+
+ /**
+ * Compute this type hierarchy.
+ */
+ protected void compute() throws JavaModelException, CoreException {
+ if (JavaModelManager.ENABLE_INDEXING && fType != null) {
+ HierarchyBuilder builder = new IndexBasedHierarchyBuilder(this, this.scope);
+ builder.build(this.computeSubtypes);
+ } // else a RegionBasedTypeHierarchy should be used
+ }
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public boolean contains(IType type) {
+ // classes
+ if (fClassToSuperclass.get(type) != null) {
+ return true;
+ }
+
+ // root classes
+ if (fRootClasses.contains(type))
+ return true;
+
+ // interfaces
+ for (Enumeration enum = fInterfaces.elements(); enum.hasMoreElements();) {
+ if (enum.nextElement().equals(type)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Deactivates this hierarchy for change listeners
+ */
+ protected void deactivate() {
+ JavaModelManager.getJavaModelManager().removeElementChangedListener(this);
+ this.files = null;
+ fPackageRegion = null;
+ fRootRegion = null;
+ fProjectRegion = null;
+ fChangeListeners = null;
+ fIsActivated = false;
+ }
+
+ /**
+ * Empties this hierarchy.
+ *
+ * fix for 1FW67PA
+ */
+ protected void destroy() {
+ fExists = false;
+ fClassToSuperclass = new Hashtable(1);
+ this.files = new Hashtable(5);
+ fInterfaces = new Vector(0);
+ fPackageRegion = new Region();
+ fProjectRegion = new Region();
+ fRootClasses = new TypeVector();
+ fRootRegion = new Region();
+ fTypeToSubtypes = new Hashtable(1);
+ fTypeToSuperInterfaces = new Hashtable(1);
+ JavaModelManager.getJavaModelManager().removeElementChangedListener(this);
+ }
+
+ /**
+ * Determines if the change effects this hierarchy, and fires
+ * change notification if required.
+ */
+ public void elementChanged(ElementChangedEvent event) {
+ // fix for 1FW67PA
+ if (fExists) {
+ if (exists()) {
+ if (isAffected(event.getDelta())) {
+ fireChange();
+ }
+ } else {
+ destroy();
+ fireChange();
+ }
+ }
+
+ }
+
+ /**
+ * @see ITypeHierarchy
+ *
+ * fix for 1FW67PA
+ */
+ public boolean exists() {
+ if (fExists) {
+ fExists =
+ (fType == null || (fType != null && fType.exists()))
+ && this.javaProject().exists();
+ if (!fExists) {
+ destroy();
+ }
+ }
+ return fExists;
+ }
+
+ /**
+ * Notifies listeners that this hierarchy has changed and needs
+ * refreshing. Note that listeners can be removed as we iterate
+ * through the list.
+ */
+ protected void fireChange() {
+ if (fChangeListeners == null) {
+ return;
+ }
+ Vector listeners = (Vector) fChangeListeners.clone();
+ for (int i = 0; i < listeners.size(); i++) {
+ ITypeHierarchyChangedListener listener =
+ (ITypeHierarchyChangedListener) listeners.elementAt(i);
+ // ensure the listener is still a listener
+ if (fChangeListeners != null && fChangeListeners.indexOf(listener) >= 0) {
+ listener.typeHierarchyChanged(this);
+ }
+ }
+ }
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public IType[] getAllClasses() {
+ Enumeration keys = fClassToSuperclass.keys();
+ TypeVector classes = fRootClasses.copy();
+ while (keys.hasMoreElements()) {
+ classes.add((IType) keys.nextElement());
+ }
+ return classes.elements();
+ }
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public IType[] getAllInterfaces() {
+ IType[] collection = new IType[fInterfaces.size()];
+ fInterfaces.copyInto(collection);
+ return collection;
+ }
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public IType[] getAllSubtypes(IType type) {
+ return getAllSubtypesForType(type);
+ }
+
+ /**
+ * @see getAllSubtypes(IType)
+ */
+ private IType[] getAllSubtypesForType(IType type) {
+ Vector subTypes = new Vector();
+ getAllSubtypesForType0(type, subTypes);
+ IType[] subClasses = new IType[subTypes.size()];
+ subTypes.copyInto(subClasses);
+ return subClasses;
+ }
+
+ /**
+ */
+ private void getAllSubtypesForType0(IType type, Vector subs) {
+ IType[] subTypes = getSubtypesForType(type);
+ if (subTypes.length != 0) {
+ for (int i = 0; i < subTypes.length; i++) {
+ IType subType = subTypes[i];
+ subs.addElement(subType);
+ getAllSubtypesForType0(subType, subs);
+ }
+ }
+ }
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public IType[] getAllSuperclasses(IType type) {
+ IType superclass = getSuperclass(type);
+ TypeVector supers = new TypeVector();
+ while (superclass != null) {
+ supers.add(superclass);
+ superclass = getSuperclass(superclass);
+ }
+ return supers.elements();
+ }
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public IType[] getAllSuperInterfaces(IType type) {
+ Vector supers = new Vector();
+ if (fTypeToSuperInterfaces.get(type) == null) {
+ return fgEmpty;
+ }
+ getAllSuperInterfaces0(type, supers);
+ IType[] superinterfaces = new IType[supers.size()];
+ supers.copyInto(superinterfaces);
+ return superinterfaces;
+ }
+
+ private void getAllSuperInterfaces0(IType type, Vector supers) {
+ IType[] superinterfaces = (IType[]) fTypeToSuperInterfaces.get(type);
+ if (superinterfaces != null && superinterfaces.length != 0) {
+ addAllCheckingDuplicates(supers, superinterfaces);
+ for (int i = 0; i < superinterfaces.length; i++) {
+ getAllSuperInterfaces0(superinterfaces[i], supers);
+ }
+ }
+ IType superclass = (IType) fClassToSuperclass.get(type);
+ if (superclass != null) {
+ getAllSuperInterfaces0(superclass, supers);
+ }
+ }
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public IType[] getAllSupertypes(IType type) {
+ Vector supers = new Vector();
+ if (fTypeToSuperInterfaces.get(type) == null) {
+ return fgEmpty;
+ }
+ getAllSupertypes0(type, supers);
+ IType[] supertypes = new IType[supers.size()];
+ supers.copyInto(supertypes);
+ return supertypes;
+ }
+
+ private void getAllSupertypes0(IType type, Vector supers) {
+ IType[] superinterfaces = (IType[]) fTypeToSuperInterfaces.get(type);
+ if (superinterfaces != null && superinterfaces.length != 0) {
+ addAllCheckingDuplicates(supers, superinterfaces);
+ for (int i = 0; i < superinterfaces.length; i++) {
+ getAllSuperInterfaces0(superinterfaces[i], supers);
+ }
+ }
+ IType superclass = (IType) fClassToSuperclass.get(type);
+ if (superclass != null) {
+ supers.addElement(superclass);
+ getAllSupertypes0(superclass, supers);
+ }
+ }
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public IType[] getAllTypes() {
+ IType[] classes = getAllClasses();
+ int classesLength = classes.length;
+ IType[] interfaces = getAllInterfaces();
+ int interfacesLength = interfaces.length;
+ IType[] all = new IType[classesLength + interfacesLength];
+ System.arraycopy(classes, 0, all, 0, classesLength);
+ System.arraycopy(interfaces, 0, all, classesLength, interfacesLength);
+ return all;
+ }
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public IType[] getExtendingInterfaces(IType type) {
+ try {
+ if (type.isClass()) {
+ return new IType[] {
+ };
+ }
+ } catch (JavaModelException npe) {
+ return new IType[] {
+ };
+ }
+ return getExtendingInterfaces0(type);
+ }
+
+ /**
+ * Assumes that the type is an interface
+ * @see getExtendingInterfaces
+ */
+ private IType[] getExtendingInterfaces0(IType interfce) {
+ Enumeration keys = fTypeToSuperInterfaces.keys();
+ Vector xers = new Vector();
+ while (keys.hasMoreElements()) {
+ IType type = (IType) keys.nextElement();
+ try {
+ if (type.isClass()) {
+ continue;
+ }
+ } catch (JavaModelException npe) {
+ continue;
+ }
+ IType[] interfaces = (IType[]) fTypeToSuperInterfaces.get(type);
+ if (interfaces != null) {
+ for (int i = 0; i < interfaces.length; i++) {
+ IType iFace = interfaces[i];
+ if (iFace.equals(interfce)) {
+ xers.addElement(type);
+ }
+ }
+ }
+ }
+ IType[] extenders = new IType[xers.size()];
+ xers.copyInto(extenders);
+ return extenders;
+ }
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public IType[] getImplementingClasses(IType type) {
+ try {
+ if (type.isClass()) {
+ return fgEmpty;
+ }
+ } catch (JavaModelException npe) {
+ return fgEmpty;
+ }
+ return getImplementingClasses0(type);
+ }
+
+ /**
+ * Assumes that the type is an interface
+ * @see getImplementingClasses
+ */
+ private IType[] getImplementingClasses0(IType interfce) {
+ Enumeration keys = fTypeToSuperInterfaces.keys();
+ Vector iMenters = new Vector();
+ while (keys.hasMoreElements()) {
+ IType type = (IType) keys.nextElement();
+ try {
+ if (type.isInterface()) {
+ continue;
+ }
+ } catch (JavaModelException npe) {
+ continue;
+ }
+ IType[] interfaces = (IType[]) fTypeToSuperInterfaces.get(type);
+ for (int i = 0; i < interfaces.length; i++) {
+ IType iFace = interfaces[i];
+ if (iFace.equals(interfce)) {
+ iMenters.addElement(type);
+ }
+ }
+ }
+ IType[] implementers = new IType[iMenters.size()];
+ iMenters.copyInto(implementers);
+ return implementers;
+ }
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public IType[] getRootClasses() {
+ return fRootClasses.elements();
+ }
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public IType[] getRootInterfaces() {
+ IType[] allInterfaces = getAllInterfaces();
+ IType[] roots = new IType[allInterfaces.length];
+ int rootNumber = 0;
+ for (int i = 0; i < allInterfaces.length; i++) {
+ IType[] superInterfaces = getSuperInterfaces(allInterfaces[i]);
+ if (superInterfaces == null || superInterfaces.length == 0) {
+ roots[rootNumber++] = allInterfaces[i];
+ }
+ }
+ IType[] result = new IType[rootNumber];
+ if (result.length > 0) {
+ System.arraycopy(roots, 0, result, 0, rootNumber);
+ }
+ return result;
+ }
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public IType[] getSubclasses(IType type) {
+ try {
+ if (type.isInterface()) {
+ return fgEmpty;
+ }
+ } catch (JavaModelException npe) {
+ return new IType[] {
+ };
+ }
+ TypeVector vector = (TypeVector) fTypeToSubtypes.get(type);
+ if (vector == null)
+ return fgEmpty;
+ else
+ return vector.elements();
+ }
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public IType[] getSubtypes(IType type) {
+ return getSubtypesForType(type);
+ }
+
+ /**
+ * Returns an array of subtypes for the given type - will never return null.
+ */
+ private IType[] getSubtypesForType(IType type) {
+ TypeVector vector = (TypeVector) fTypeToSubtypes.get(type);
+ if (vector == null)
+ return fgEmpty;
+ else
+ return vector.elements();
+ }
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public IType getSuperclass(IType type) {
+ try {
+ if (type.isInterface()) {
+ return null;
+ }
+ return (IType) fClassToSuperclass.get(type);
+
+ } catch (JavaModelException npe) {
+ return null;
+ }
+ }
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public IType[] getSuperInterfaces(IType type) {
+ IType[] interfaces = (IType[]) fTypeToSuperInterfaces.get(type);
+ if (interfaces == null) {
+ return fgEmpty;
+ }
+ return interfaces;
+ }
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public IType[] getSupertypes(IType type) {
+ IType superclass = getSuperclass(type);
+ if (superclass == null) {
+ return getSuperInterfaces(type);
+ } else {
+ TypeVector superTypes = new TypeVector(getSuperInterfaces(type));
+ superTypes.add(superclass);
+ return superTypes.elements();
+ }
+ }
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public IType getType() {
+ return fType;
+ }
+
+ /**
+ * Adds the new elements to a new array that contains all of the elements of the old array.
+ * Returns the new array.
+ */
+ protected IType[] growAndAddToArray(IType[] array, IType[] additions) {
+ if (array == null || array.length == 0) {
+ return additions;
+ }
+ IType[] old = array;
+ array = new IType[old.length + additions.length];
+ System.arraycopy(old, 0, array, 0, old.length);
+ System.arraycopy(additions, 0, array, old.length, additions.length);
+ return array;
+ }
+
+ /**
+ * Adds the new element to a new array that contains all of the elements of the old array.
+ * Returns the new array.
+ */
+ protected IType[] growAndAddToArray(IType[] array, IType addition) {
+ if (array == null || array.length == 0) {
+ return new IType[] { addition };
+ }
+ IType[] old = array;
+ array = new IType[old.length + 1];
+ System.arraycopy(old, 0, array, 0, old.length);
+ array[old.length] = addition;
+ return array;
+ }
+
+ /**
+ * Returns whether one of the subtypes in this hierarchy has the given simple name
+ * or this type has the given simple name.
+ */
+ private boolean hasSubtypeNamed(String simpleName) {
+ if (fType.getElementName().equals(simpleName)) {
+ return true;
+ }
+ IType[] types = this.getAllSubtypes(fType);
+ for (int i = 0, length = types.length; i < length; i++) {
+ if (types[i].getElementName().equals(simpleName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether the given delta (a compilation unit delta or a class file delta)
+ * indicates that one of the supertypes has changed or one of the imports has changed.
+ */
+ private boolean hasSuperTypeOrImportChange(IJavaElementDelta delta) {
+ IJavaElementDelta[] children = delta.getAffectedChildren();
+ for (int i = 0, length = children.length; i < length; i++) {
+ IJavaElementDelta child = children[i];
+ if ((child.getFlags() & IJavaElementDelta.F_SUPER_TYPES) > 0) {
+ return true;
+ }
+ if (child.getElement() instanceof ImportContainer) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether one of the types in this hierarchy has the given simple name.
+ */
+ private boolean hasTypeNamed(String simpleName) {
+ IType[] types = this.getAllTypes();
+ for (int i = 0, length = types.length; i < length; i++) {
+ if (types[i].getElementName().equals(simpleName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether the given delta (a compilation unit delta or a class file delta)
+ * indicates that one of its types has a visibility change.
+ */
+ private boolean hasVisibilityChange(IJavaElementDelta delta) {
+ IJavaElementDelta[] children = delta.getAffectedChildren();
+ for (int i = 0, length = children.length; i < length; i++) {
+ IJavaElementDelta child = children[i];
+ if ((child.getFlags() & IJavaElementDelta.F_MODIFIERS) > 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether the simple name of a supertype of the given type is
+ * the simple name of one of the types in this hierarchy.
+ */
+ private boolean includesSupertypeOf(IType type) {
+ IType[] supertypes = getSupertypes(type);
+ for (int i = 0, length = supertypes.length; i < length; i++) {
+ if (hasTypeNamed(supertypes[i].getElementName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Initializes this hierarchy's internal tables with the given size.
+ */
+ protected void initialize(int size) {
+ if (size < 10) {
+ size = 10;
+ }
+ int smallSize = (size / 2);
+ fClassToSuperclass = new Hashtable(size);
+ fTypeToSubtypes = new Hashtable(smallSize);
+ fTypeToSuperInterfaces = new Hashtable(smallSize);
+ }
+
+ /**
+ * Returns true if this hierarchy is actively tracking changes
+ * in the Java Model.
+ */
+ protected boolean isActivated() {
+ return fIsActivated;
+ }
+
+ /**
+ * Returns true if the given delta could change this type hierarchy
+ */
+ private boolean isAffected(IJavaElementDelta delta) {
+ IJavaElement element = delta.getElement();
+ switch (element.getElementType()) {
+ case IJavaElement.JAVA_MODEL :
+ return isAffectedByJavaModel(delta, element);
+ case IJavaElement.JAVA_PROJECT :
+ return isAffectedByJavaProject(delta, element);
+ case IJavaElement.PACKAGE_FRAGMENT_ROOT :
+ return isAffectedByPackageFragmentRoot(delta, element);
+ case IJavaElement.PACKAGE_FRAGMENT :
+ return isAffectedByPackageFragment(delta, element);
+ case IJavaElement.CLASS_FILE :
+ case IJavaElement.COMPILATION_UNIT :
+ return isAffectedByType(delta, element);
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if any of the children of a project, package
+ * fragment root, or package fragment have changed in a way that
+ * effects this type hierarchy.
+ */
+ private boolean isAffectedByChildren(IJavaElementDelta delta) {
+ if ((delta.getFlags() & IJavaElementDelta.F_CHILDREN) > 0) {
+ IJavaElementDelta[] children = delta.getAffectedChildren();
+ for (int i = 0; i < children.length; i++) {
+ if (isAffected(children[i])) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the given java model delta could affect this type hierarchy
+ */
+ private boolean isAffectedByJavaModel(
+ IJavaElementDelta delta,
+ IJavaElement element) {
+ switch (delta.getKind()) {
+ case IJavaElementDelta.ADDED :
+ case IJavaElementDelta.REMOVED :
+ return element.equals(this.javaProject().getJavaModel());
+ case IJavaElementDelta.CHANGED :
+ return isAffectedByChildren(delta);
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the given java project delta could affect this type hierarchy
+ */
+ private boolean isAffectedByJavaProject(
+ IJavaElementDelta delta,
+ IJavaElement element) {
+ switch (delta.getKind()) {
+ case IJavaElementDelta.ADDED :
+ try {
+ // if the added project is on the classpath, then the hierarchy has changed
+ IClasspathEntry[] classpath = this.javaProject().getResolvedClasspath(true);
+ for (int i = 0; i < classpath.length; i++) {
+ if (classpath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT
+ && classpath[i].getPath().equals(element.getUnderlyingResource().getFullPath())) {
+ return true;
+ }
+ }
+ return false;
+ } catch (JavaModelException e) {
+ return false;
+ }
+ case IJavaElementDelta.REMOVED :
+ // removed project - if it contains packages we are interested in
+ // then the type hierarchy has changed
+ IJavaElement[] pkgs = fPackageRegion.getElements();
+ for (int i = 0; i < pkgs.length; i++) {
+ IJavaProject project = pkgs[i].getJavaProject();
+ if (project != null && project.equals(element)) {
+ return true;
+ }
+ }
+ return false;
+ case IJavaElementDelta.CHANGED :
+ return isAffectedByChildren(delta);
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the given package fragment delta could affect this type hierarchy
+ */
+ private boolean isAffectedByPackageFragment(
+ IJavaElementDelta delta,
+ IJavaElement element) {
+ switch (delta.getKind()) {
+ case IJavaElementDelta.ADDED :
+ // if the package fragment is in the projects being considered, this could
+ // introduce new types, changing the hierarchy
+ return fProjectRegion.contains(element);
+ case IJavaElementDelta.REMOVED :
+ // is a change if the package fragment contains types in this hierarchy
+ return packageRegionContainsSamePackageFragment(element);
+ case IJavaElementDelta.CHANGED :
+ // look at the files in the package fragment
+ return isAffectedByChildren(delta);
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the given package fragment root delta could affect this type hierarchy
+ */
+ private boolean isAffectedByPackageFragmentRoot(
+ IJavaElementDelta delta,
+ IJavaElement element) {
+ switch (delta.getKind()) {
+ case IJavaElementDelta.ADDED :
+ return fProjectRegion.contains(element);
+ case IJavaElementDelta.REMOVED :
+ case IJavaElementDelta.CHANGED :
+ if ((delta.getFlags() & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) > 0
+ || (delta.getFlags() & IJavaElementDelta.F_CONTENT) > 0) {
+ // 1. removed from classpath - if it contains packages we are interested in
+ // the the type hierarchy has changed
+ // 2. content of a jar changed - if it contains packages we are interested in
+ // the the type hierarchy has changed
+ IJavaElement[] pkgs = fPackageRegion.getElements();
+ for (int i = 0; i < pkgs.length; i++) {
+ if (pkgs[i].getParent().equals(element)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+ return isAffectedByChildren(delta);
+ }
+
+ /**
+ * Returns true if the given type delta (a compilation unit delta or a class file delta)
+ * could affect this type hierarchy.
+ *
+ * The rules are:
+ * - if the delta is an added type X, then the hierarchy is changed
+ * . if one of the types in this hierarchy has a supertype whose simple name is the
+ * simple name of X
+ * . if the simple name of a supertype of X is the simple name of one of
+ * the subtypes in this hierarchy (X will be added as one of the subtypes)
+ * - if the delta is a changed type X, then the hierarchy is changed
+ * . if the visibility of X has changed and if one of the types in this hierarchy has a
+ * supertype whose simple name is the simple name of X
+ * . if one of the supertypes of X has changed or one of the imports has changed,
+ * and if the simple name of a supertype of X is the simple name of one of
+ * the types in this hierarchy
+ * - if the delta is a removed type X, then the hierarchy is changed
+ * . if the given element is part of this hierarchy (note we cannot acces the types
+ * because the element has been removed)
+ */
+ protected boolean isAffectedByType(
+ IJavaElementDelta delta,
+ IJavaElement element) {
+ // ignore changes to working copies
+ if (element instanceof CompilationUnit
+ && ((CompilationUnit) element).isWorkingCopy()) {
+ return false;
+ }
+
+ int kind = delta.getKind();
+ if (kind == IJavaElementDelta.REMOVED) {
+ return this.files.get(element) != null;
+ } else {
+ IType[] types = null;
+ try {
+ types =
+ (element instanceof CompilationUnit)
+ ? ((CompilationUnit) element).getAllTypes()
+ : new IType[] {((org.eclipse.jdt.internal.core.ClassFile) element).getType()};
+ } catch (JavaModelException e) {
+ e.printStackTrace();
+ return false;
+ }
+ if (kind == IJavaElementDelta.ADDED) {
+ for (int i = 0, length = types.length; i < length; i++) {
+ IType type = types[i];
+ if (typeHasSupertype(type) || subtypesIncludeSupertypeOf(type)) {
+ return true;
+ }
+ }
+ } else { // kind == IJavaElementDelta.CHANGED :
+ boolean hasSupertypeChange = hasSuperTypeOrImportChange(delta);
+ boolean hasVisibilityChange = hasVisibilityChange(delta);
+ for (int i = 0, length = types.length; i < length; i++) {
+ IType type = types[i];
+ if ((hasVisibilityChange && typeHasSupertype(type))
+ || (hasSupertypeChange && includesSupertypeOf(type))) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the java project this hierarchy was created in.
+ */
+ public IJavaProject javaProject() {
+ return fType.getJavaProject();
+ }
+
+ /**
+ * Returns <code>true</code> if an equivalent package fragment is included in the package
+ * region. Package fragments are equivalent if they both have the same name.
+ */
+ protected boolean packageRegionContainsSamePackageFragment(IJavaElement element) {
+ IJavaElement[] pkgs = fPackageRegion.getElements();
+ for (int i = 0; i < pkgs.length; i++) {
+ if (pkgs[i].getElementName().equals(element.getElementName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Prunes this type hierarchy to only contain the branch to the given type,
+ * and its subtree. Pruning is only done for classes.
+ */
+ protected void pruneTypeHierarchy(IType type, IProgressMonitor monitor)
+ throws JavaModelException {
+ if (type.isClass()) {
+ IType[] supers = getAllSuperclasses(type);
+
+ if (supers.length == 0) {
+ // nothing to prune if this is a root - unless there are other roots
+ return;
+ }
+
+ IType[] branch = new IType[supers.length + 1];
+ System.arraycopy(supers, 0, branch, 1, supers.length);
+ branch[0] = type;
+ // Branch is a list from the root to our type
+ // Walk the branch pruning all other subtrees
+ for (int i = branch.length - 1; i > 0; i--) {
+ IType[] subtrees = getSubtypes(branch[i]);
+ for (int j = 0; j < subtrees.length; j++) {
+ if (!subtrees[j].equals(branch[i - 1])) {
+ removeType(subtrees[j]);
+ }
+ this.worked(1);
+ }
+ fTypeToSubtypes.put(branch[i], new TypeVector(branch[i - 1]));
+ }
+ }
+ }
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public void refresh(IProgressMonitor monitor) throws JavaModelException {
+ try {
+ boolean reactivate = isActivated();
+ Vector listeners = fChangeListeners;
+ if (reactivate) {
+ deactivate();
+ }
+ fProgressMonitor = monitor;
+ if (monitor != null) {
+ monitor.beginTask("Creating type hierarchy...", IProgressMonitor.UNKNOWN);
+ }
+ compute();
+ if (fType != null) {
+ //prune the hierarchy tree to only include branch and subtree for the type
+ pruneTypeHierarchy(fType, monitor);
+ }
+ if (reactivate) {
+ activate();
+ fChangeListeners = listeners;
+ }
+ if (monitor != null) {
+ monitor.done();
+ }
+ fProgressMonitor = null;
+ } catch (JavaModelException e) {
+ fProgressMonitor = null;
+ throw e;
+ } catch (CoreException e) {
+ fProgressMonitor = null;
+ throw new JavaModelException(e);
+ } catch (OperationCanceledException oce) {
+ refreshCancelled(oce);
+ }
+ }
+
+ /**
+ * The refresh of this type hierarchy has been cancelled.
+ * Cleanup the state of this now invalid type hierarchy.
+ */
+ protected void refreshCancelled(OperationCanceledException oce)
+ throws JavaModelException {
+ destroy();
+ fProgressMonitor = null;
+ throw oce;
+ }
+
+ /**
+ * Removes all the subtypes of the given type from the type hierarchy,
+ * and removes its superclass entry.
+ */
+ protected void removeType(IType type) throws JavaModelException {
+ IType[] subtypes = getSubtypes(type);
+ fTypeToSubtypes.remove(type);
+ fClassToSuperclass.remove(type);
+ if (subtypes != null) {
+ for (int i = 0; i < subtypes.length; i++) {
+ removeType(subtypes[i]);
+ }
+ }
+ }
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public void removeTypeHierarchyChangedListener(ITypeHierarchyChangedListener listener) {
+ if (fChangeListeners == null) {
+ return;
+ }
+ fChangeListeners.removeElement(listener);
+ if (fChangeListeners.isEmpty()) {
+ deactivate();
+ }
+ }
+
+ /**
+ * Returns whether the simple name of a supertype of the given type is
+ * the simple name of one of the subtypes in this hierarchy or the
+ * simple name of this type.
+ */
+ private boolean subtypesIncludeSupertypeOf(IType type) {
+ // look for superclass
+ String superclassName = null;
+ try {
+ superclassName = type.getSuperclassName();
+ } catch (JavaModelException e) {
+ e.printStackTrace();
+ return false;
+ }
+ if (superclassName == null) {
+ superclassName = "Object";
+ }
+ int dot = -1;
+ String simpleSuper =
+ (dot = superclassName.lastIndexOf('.')) > -1
+ ? superclassName.substring(dot + 1)
+ : superclassName;
+ if (hasSubtypeNamed(simpleSuper)) {
+ return true;
+ }
+
+ // look for super interfaces
+ String[] interfaceNames = null;
+ try {
+ interfaceNames = type.getSuperInterfaceNames();
+ } catch (JavaModelException e) {
+ e.printStackTrace();
+ return false;
+ }
+ for (int i = 0, length = interfaceNames.length; i < length; i++) {
+ dot = -1;
+ String interfaceName = interfaceNames[i];
+ String simpleInterface =
+ (dot = interfaceName.lastIndexOf('.')) > -1
+ ? interfaceName.substring(dot)
+ : interfaceName;
+ if (hasSubtypeNamed(simpleInterface)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @see ITypeHierarchy
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("Focus: ");
+ buffer.append(fType == null ? "<NONE>" : fType.getFullyQualifiedName());
+ buffer.append("\n");
+ if (exists()) {
+ if (fType != null) {
+ buffer.append("Super types:\n");
+ toString(buffer, fType, 1, true);
+ buffer.append("Sub types:\n");
+ toString(buffer, fType, 1, false);
+ } else {
+ buffer.append("Sub types of root classes:\n");
+ IType[] roots = getRootClasses();
+ for (int i = 0; i < roots.length; i++) {
+ toString(buffer, roots[i], 1, false);
+ }
+ }
+ } else {
+ buffer.append("(Hierarchy became stale)");
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Append a String to the given buffer representing the hierarchy for the type,
+ * beginning with the specified indentation level.
+ * If ascendant, shows the super types, otherwise show the sub types.
+ */
+ private void toString(
+ StringBuffer buffer,
+ IType type,
+ int indent,
+ boolean ascendant) {
+ for (int i = 0; i < indent; i++) {
+ buffer.append(" ");
+ }
+ buffer.append(type.getFullyQualifiedName());
+ buffer.append('\n');
+
+ IType[] types = ascendant ? getSupertypes(type) : getSubtypes(type);
+ for (int i = 0; i < types.length; i++) {
+ toString(buffer, types[i], indent + 1, ascendant);
+ }
+
+ }
+
+ /**
+ * Returns whether one of the types in this hierarchy has a supertype whose simple
+ * name is the simple name of the given type.
+ */
+ private boolean typeHasSupertype(IType type) {
+ String simpleName = type.getElementName();
+ Enumeration enum = fClassToSuperclass.elements();
+ while (enum.hasMoreElements()) {
+ IType superType = (IType) enum.nextElement();
+ if (superType.getElementName().equals(simpleName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @see IProgressMonitor
+ */
+ protected void worked(int work) {
+ if (fProgressMonitor != null) {
+ fProgressMonitor.worked(work);
+ checkCanceled();
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/AbstractDOMBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/AbstractDOMBuilder.java
new file mode 100644
index 0000000000..0d4683b32f
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/AbstractDOMBuilder.java
@@ -0,0 +1,228 @@
+package org.eclipse.jdt.internal.core.jdom;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+import org.eclipse.jdt.core.jdom.*;
+import org.eclipse.jdt.internal.core.util.ReferenceInfoAdapter;
+
+import java.util.Stack;
+
+/**
+ * An abstract DOM builder that contains shared functionality of DOMBuilder and SimpleDOMBuilder.
+ */
+public class AbstractDOMBuilder
+ extends ReferenceInfoAdapter
+ implements ILineStartFinder {
+ /**
+ * Set to true when an error is encounterd while
+ * fuzzy parsing
+ */
+ protected boolean fAbort;
+
+ /**
+ * True when a compilation unit is being constructed.
+ * False when any other type of document fragment is
+ * being constructed.
+ */
+ protected boolean fBuildingCU = false;
+
+ /**
+ * True when a compilation unit or type is being
+ * constructed. False when any other type of document
+ * fragment is being constructed.
+ */
+ protected boolean fBuildingType = false;
+
+ /**
+ * The String on which the JDOM is being created.
+ */
+ protected char[] fDocument = null;
+
+ /**
+ * The source positions of all of the line separators in the document.
+ */
+ protected int[] fLineStartPositions = new int[] { 0 };
+
+ /**
+ * A stack of enclosing scopes used when constructing
+ * a compilation unit or type. The top of the stack
+ * is the document fragment that children are added to.
+ */
+ protected Stack fStack = null;
+
+ /**
+ * The number of fields constructed in the current
+ * document. This is used when building a single
+ * field document fragment, since the DOMBuilder only
+ * accepts documents with one field declaration.
+ */
+ protected int fFieldCount;
+
+ /**
+ * The current node being constructed.
+ */
+ protected DOMNode fNode;
+ /**
+ * AbstractDOMBuilder constructor.
+ */
+ public AbstractDOMBuilder() {
+ super();
+ }
+
+ /**
+ * Accepts the line separator table and converts it into a line start table.
+ *
+ * <p>A line separator might corresponds to several characters in the source.
+ *
+ * @see IDocumentElementRequestor#acceptLineSeparatorPositions
+ */
+ public void acceptLineSeparatorPositions(int[] positions) {
+ if (positions != null) {
+ int length = positions.length;
+ if (length > 0) {
+ fLineStartPositions = new int[length + 1];
+ fLineStartPositions[0] = 0;
+ int documentLength = fDocument.length;
+ for (int i = 0; i < length; i++) {
+ int iPlusOne = i + 1;
+ int positionPlusOne = positions[i] + 1;
+ if (positionPlusOne < documentLength) {
+ if (iPlusOne < length) {
+ // more separators
+ fLineStartPositions[iPlusOne] = positionPlusOne;
+ } else {
+ // no more separators
+ if (fDocument[positionPlusOne] == '\n') {
+ fLineStartPositions[iPlusOne] = positionPlusOne + 1;
+ } else {
+ fLineStartPositions[iPlusOne] = positionPlusOne;
+ }
+ }
+ } else {
+ fLineStartPositions[iPlusOne] = positionPlusOne;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Does nothing.
+ */
+ public void acceptProblem(IProblem problem) {
+ }
+
+ /**
+ * Adds the given node to the current enclosing scope, building the JDOM
+ * tree. Nodes are only added to an enclosing scope when a compilation unit or type
+ * is being built (since those are the only nodes that have children).
+ *
+ * <p>NOTE: nodes are added to the JDOM via the method #basicAddChild such that
+ * the nodes in the newly created JDOM are not fragmented.
+ */
+ protected void addChild(IDOMNode child) {
+ if (fStack.size() > 0) {
+ DOMNode parent = (DOMNode) fStack.peek();
+ if (fBuildingCU || fBuildingType) {
+ parent.basicAddChild(child);
+ }
+ }
+ }
+
+ /**
+ * @see IDOMFactory#createCompilationUnit(String)
+ */
+ public IDOMCompilationUnit createCompilationUnit(
+ char[] contents,
+ char[] name) {
+ return createCompilationUnit(new CompilationUnit(contents, name));
+ }
+
+ /**
+ * @see IDOMFactory#createCompilationUnit(String)
+ */
+ public IDOMCompilationUnit createCompilationUnit(ICompilationUnit compilationUnit) {
+ if (fAbort) {
+ return null;
+ }
+ fNode.normalize(this);
+ return (IDOMCompilationUnit) fNode;
+ }
+
+ /**
+ * @see IDocumentElementRequestor#enterClass
+ */
+ public void enterCompilationUnit() {
+ if (fBuildingCU) {
+ IDOMCompilationUnit cu =
+ new DOMCompilationUnit(fDocument, new int[] { 0, fDocument.length - 1 });
+ fStack.push(cu);
+ }
+ }
+
+ /**
+ * Finishes the configuration of the compilation unit DOM object which
+ * was created by a previous enterCompilationUnit call.
+ *
+ * @see IDocumentElementRequestor#exitCompilationUnit
+ */
+ public void exitCompilationUnit(int declarationEnd) {
+ DOMCompilationUnit cu = (DOMCompilationUnit) fStack.pop();
+ cu.setSourceRangeEnd(declarationEnd);
+ fNode = cu;
+ }
+
+ /**
+ * Finishes the configuration of the class and interface DOM objects.
+ *
+ * @param bodyEnd - a source position corresponding to the closing bracket of the class
+ * @param declarationEnd - a source position corresponding to the end of the class
+ * declaration. This can include whitespace and comments following the closing bracket.
+ */
+ protected void exitType(int bodyEnd, int declarationEnd) {
+ DOMType type = (DOMType) fStack.pop();
+ type.setSourceRangeEnd(declarationEnd);
+ type.setCloseBodyRangeStart(bodyEnd);
+ type.setCloseBodyRangeEnd(bodyEnd);
+ fNode = type;
+ }
+
+ /**
+ * @see ILineSeparatorFinder
+ */
+ public int getLineStart(int position) {
+ int lineSeparatorCount = fLineStartPositions.length;
+ // reverse traversal intentional.
+ for (int i = lineSeparatorCount - 1; i >= 0; i--) {
+ if (fLineStartPositions[i] <= position)
+ return fLineStartPositions[i];
+ }
+ return 0;
+ }
+
+ /**
+ * Initializes the builder to create a document fragment.
+ *
+ * @param sourceCode - the document containing the source code to be analyzed
+ * @param buildingCompilationUnit - true if a the document is being analyzed to
+ * create a compilation unit, otherwise false
+ * @param buildingType - true if the document is being analyzed to create a
+ * type or compilation unit
+ */
+ protected void initializeBuild(
+ char[] sourceCode,
+ boolean buildingCompilationUnit,
+ boolean buildingType) {
+ fBuildingCU = buildingCompilationUnit;
+ fBuildingType = buildingType;
+ fStack = new Stack();
+ fDocument = sourceCode;
+ fFieldCount = 0;
+ fAbort = false;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/CompilationUnit.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/CompilationUnit.java
new file mode 100644
index 0000000000..3b968fc434
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/CompilationUnit.java
@@ -0,0 +1,52 @@
+package org.eclipse.jdt.internal.core.jdom;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.*;
+
+import java.io.*;
+
+/**
+ * Implements a very simple version of the ICompilationUnit
+ *
+ * <p>Please do not use outside of jdom.
+ */
+public class CompilationUnit implements ICompilationUnit {
+ protected char[] fContents;
+ protected char[] fFileName;
+ protected char[] fMainTypeName;
+ public CompilationUnit(char[] contents, char[] filename) {
+ fContents = contents;
+ fFileName = filename;
+
+ String file = new String(filename);
+ int start = file.lastIndexOf("/") + 1;
+ if (start == 0 || start < file.lastIndexOf("\\"))
+ start = file.lastIndexOf("\\") + 1;
+
+ int end = file.lastIndexOf(".");
+ if (end == -1)
+ end = file.length();
+
+ fMainTypeName = file.substring(start, end).toCharArray();
+ }
+
+ public char[] getContents() {
+ return fContents;
+ }
+
+ public char[] getFileName() {
+ return fFileName;
+ }
+
+ public char[] getMainTypeName() {
+ return fMainTypeName;
+ }
+
+ public String toString() {
+ return "CompilationUnit[" + new String(fFileName) + "]";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMBuilder.java
new file mode 100644
index 0000000000..18414cb1f0
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMBuilder.java
@@ -0,0 +1,889 @@
+package org.eclipse.jdt.internal.core.jdom;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+import org.eclipse.jdt.core.jdom.*;
+import org.eclipse.jdt.internal.core.util.*;
+
+import java.lang.reflect.Modifier;
+import java.util.Enumeration;
+import java.util.Stack;
+import java.util.Vector;
+
+/**
+ * The DOMBuilder constructs each type of JDOM document fragment,
+ * for the DOMFactory. The DOMBuilder has been separated from the
+ * DOMFactory to hide the implmentation of node creation and the
+ * public Requestor API methods.
+ *
+ */
+
+public class DOMBuilder
+ extends AbstractDOMBuilder
+ implements IDocumentElementRequestor {
+
+ /**
+ * True when parsing a single member - ignore any problems
+ * encountered after the member.
+ */
+ protected boolean fBuildingSingleMember = false;
+
+ /**
+ * True when the single member being built has been
+ * exited.
+ */
+ protected boolean fFinishedSingleMember = false;
+
+ /**
+ * Collection of multiple fields in one declaration
+ */
+ protected Vector fFields;
+
+ /**
+ * Creates a new DOMBuilder
+ */
+ public DOMBuilder() {
+ }
+
+ /**
+ * @see IDocumentElementRequestor.acceptImport(...);
+ */
+ public void acceptImport(
+ int declarationStart,
+ int declarationEnd,
+ int[] javaDocPositions,
+ char[] name,
+ int nameStart,
+ boolean onDemand) {
+ int[] sourceRange = { declarationStart, declarationEnd };
+ int[] nameRange = { nameStart, declarationEnd - 1 };
+
+ /* See 1FVII1P */
+ String importName =
+ CharArrayOps.substring(
+ fDocument,
+ nameRange[0],
+ nameRange[1] + 1 - nameRange[0]);
+
+ fNode = new DOMImport(fDocument, sourceRange, importName, nameRange, onDemand);
+ addChild(fNode);
+ if (fBuildingSingleMember) {
+ fFinishedSingleMember = true;
+ }
+ }
+
+ /**
+ * @see IDocumentElementRequestor.acceptInitializer(...);
+ */
+ public void acceptInitializer(
+ int declarationStart,
+ int declarationEnd,
+ int[] javaDocPositions,
+ int modifiers,
+ int modifiersStart,
+ int bodyStart,
+ int bodyEnd) {
+ int[] sourceRange = { declarationStart, declarationEnd };
+ int[] commentRange = { -1, -1 };
+ if (javaDocPositions != null) {
+ int length = javaDocPositions.length;
+ commentRange[0] = javaDocPositions[length - 2];
+ commentRange[1] = javaDocPositions[length - 1];
+ }
+
+ int[] modifiersRange = { -1, -1 };
+ if (modifiersStart > declarationStart) {
+ modifiersRange[0] = modifiersStart;
+ modifiersRange[1] = bodyStart - 1;
+ }
+ fNode =
+ new DOMInitializer(
+ fDocument,
+ sourceRange,
+ commentRange,
+ modifiers,
+ modifiersRange,
+ bodyStart);
+ addChild(fNode);
+ if (fBuildingSingleMember) {
+ fFinishedSingleMember = true;
+ }
+ }
+
+ /**
+ * @see IDocumentElementRequestor.acceptPackage(...);
+ */
+ public void acceptPackage(
+ int declarationStart,
+ int declarationEnd,
+ int[] javaDocPositions,
+ char[] name,
+ int nameStartPosition) {
+ int[] sourceRange = { declarationStart, declarationEnd };
+ int[] nameRange = { nameStartPosition, declarationEnd - 1 };
+ fNode =
+ new DOMPackage(
+ fDocument,
+ sourceRange,
+ CharArrayOps.charToString(name),
+ nameRange);
+ addChild(fNode);
+ if (fBuildingSingleMember) {
+ fFinishedSingleMember = true;
+ }
+ }
+
+ /**
+ * Sets the abort flag to true. The parser has encountered an error
+ * in the current document. If we are only building a single member, and
+ * we are done with the member - don't worry about the error.
+ *
+ * @see IDocumentElementRequestor
+ */
+ public void acceptProblem(IProblem problem) {
+ if (fBuildingSingleMember && fFinishedSingleMember) {
+ return;
+ }
+ fAbort = true;
+ }
+
+ /**
+ * Adds the given node to the current enclosing scope, building the JDOM
+ * tree. Nodes are only added to an enclosing scope when a compilation unit or type
+ * is being built (since those are the only nodes that have children).
+ *
+ * <p>NOTE: nodes are added to the JDOM via the method #basicAddChild such that
+ * the nodes in the newly created JDOM are not fragmented.
+ */
+ protected void addChild(IDOMNode child) {
+ super.addChild(child);
+ if (fStack.isEmpty() && fFields != null) {
+ fFields.addElement(child);
+ }
+ }
+
+ /**
+ * @see IDOMFactory#createCompilationUnit()
+ */
+ public IDOMCompilationUnit createCompilationUnit() {
+ return new DOMCompilationUnit();
+ }
+
+ /**
+ * @see IDOMFactory#createCompilationUnit(String)
+ */
+ public IDOMCompilationUnit createCompilationUnit(ICompilationUnit compilationUnit) {
+ initializeBuild(compilationUnit.getContents(), true, true, false);
+ getParser().parseCompilationUnit(compilationUnit);
+ return super.createCompilationUnit(compilationUnit);
+ }
+
+ /**
+ * @see IDOMFactory#createField(char[])
+ */
+ public IDOMField createField(char[] sourceCode) {
+ initializeBuild(sourceCode, false, false, true);
+ getParser().parseField(sourceCode);
+ if (fAbort) {
+ return null;
+ }
+
+ // we only accept field declarations with one field
+ if (fFieldCount > 1) {
+ return null;
+ }
+
+ fNode.normalize(this);
+ return (IDOMField) fNode;
+ }
+
+ /**
+ *
+ */
+ public IDOMField[] createFields(char[] sourceCode) {
+ initializeBuild(sourceCode, false, false, false);
+ fFields = new Vector();
+ getParser().parseField(sourceCode);
+ if (fAbort) {
+ return null;
+ }
+
+ IDOMField[] fields = new IDOMField[fFields.size()];
+ fFields.copyInto(fields);
+ for (int i = 0; i < fields.length; i++) {
+ DOMNode node = (DOMNode) fields[i];
+ if (i < (fields.length - 1)) {
+ DOMNode next = (DOMNode) fields[i + 1];
+ node.fNextNode = next;
+ next.fPreviousNode = node;
+ }
+ ((DOMNode) fields[i]).normalize(this);
+ }
+ return fields;
+ }
+
+ /**
+ * @see IDOMFactory#createImport()
+ */
+ public IDOMImport createImport() {
+ return new DOMImport();
+ }
+
+ /**
+ * @see IDOMFactory#createImport(char[])
+ */
+ public IDOMImport createImport(char[] sourceCode) {
+ initializeBuild(sourceCode, false, false, true);
+ getParser().parseImport(sourceCode);
+ if (fAbort || fNode == null) {
+ return null;
+ }
+ fNode.normalize(this);
+ return (IDOMImport) fNode;
+ }
+
+ /**
+ * Creates an INITIALIZER document fragment from the given source.
+ *
+ * @see IDOMFactory#createInitializer(char[])
+ */
+ public IDOMInitializer createInitializer(char[] sourceCode) {
+ initializeBuild(sourceCode, false, false, true);
+ getParser().parseInitializer(sourceCode);
+ if (fAbort || fNode == null || !(fNode instanceof IDOMInitializer)) {
+ return null;
+ }
+ fNode.normalize(this);
+ return (IDOMInitializer) fNode;
+ }
+
+ /**
+ * @see IDOMFactory#createMethod(char[])
+ */
+ public IDOMMethod createMethod(char[] sourceCode) {
+ initializeBuild(sourceCode, false, false, true);
+ getParser().parseMethod(sourceCode);
+ if (fAbort) {
+ return null;
+ }
+ fNode.normalize(this);
+ return (IDOMMethod) fNode;
+ }
+
+ /**
+ * @see IDOMFactory#createPackage()
+ */
+ public IDOMPackage createPackage() {
+ return new DOMPackage();
+ }
+
+ /**
+ * @see IDOMFactory#createPackage(char[])
+ */
+ public IDOMPackage createPackage(char[] sourceCode) {
+ initializeBuild(sourceCode, false, false, true);
+ getParser().parsePackage(sourceCode);
+ if (fAbort || fNode == null) {
+ return null;
+ }
+ fNode.normalize(this);
+ return (IDOMPackage) fNode;
+ }
+
+ /**
+ * @see IDOMFactory#createType(char[])
+ */
+ public IDOMType createType(char[] sourceCode) {
+ initializeBuild(sourceCode, false, true, false);
+ getParser().parseType(sourceCode);
+ if (fAbort) {
+ return null;
+ }
+ fNode.normalize(this);
+ return (IDOMType) fNode;
+ }
+
+ /**
+ * Creates a new DOMMethod and inizializes.
+ *
+ * @param declarationStart - a source position corresponding to the first character
+ * of this constructor declaration
+ * @param modifiers - the modifiers for this constructor converted to a flag
+ * @param modifiersStart - a source position corresponding to the first character of the
+ * textual modifiers
+ * @param returnType - the name of the return type
+ * @param returnTypeStart - a source position corresponding to the first character
+ * of the return type
+ * @param returnTypeEnd - a source position corresponding to the last character
+ * of the return type
+ * @param returnTypeDimensionCount - the array dimension count as supplied on the
+ * return type, i.e. public int[] foo() {}
+ * @param name - the name of this constructor
+ * @param nameStart - a source position corresponding to the first character of the name
+ * @param nameEnd - a source position corresponding to the last character of the name
+ * @param parameterTypes - a list of parameter type names
+ * @param parameterTypeStarts - a list of source positions corresponding to the
+ * first character of each parameter type name
+ * @param parameterTypeEnds - a list of source positions corresponding to the
+ * last character of each parameter type name
+ * @param parameterNames - a list of the names of the parameters
+ * @param parametersEnd - a source position corresponding to the last character of the
+ * parameter list
+ * @extendedReturnTypeDimensionCount - the array dimension count as supplied on the
+ * end of the parameter list, i.e. public int foo()[] {}
+ * @extendedReturnTypeDimensionEnd - a source position corresponding to the last character
+ * of the extended return type dimension
+ * @param exceptionTypes - a list of the exception types
+ * @param exceptionTypeStarts - a list of source positions corresponding to the first
+ * character of the respective exception types
+ * @param exceptionTypeEnds - a list of source positions corresponding to the last
+ * character of the respective exception types
+ * @param bodyStart - a source position corresponding to the start of this
+ * constructor's body
+ */
+ protected void enterAbstractMethod(
+ int declarationStart,
+ int[] javaDocPositions,
+ int modifiers,
+ int modifiersStart,
+ char[] returnType,
+ int returnTypeStart,
+ int returnTypeEnd,
+ int returnTypeDimensionCount,
+ char[] name,
+ int nameStart,
+ int nameEnd,
+ char[][] parameterTypes,
+ int[] parameterTypeStarts,
+ int[] parameterTypeEnds,
+ char[][] parameterNames,
+ int[] parameterNameStarts,
+ int[] parameterNameEnds,
+ int parametersEnd,
+ int extendedReturnTypeDimensionCount,
+ int extendedReturnTypeDimensionEnd,
+ char[][] exceptionTypes,
+ int[] exceptionTypeStarts,
+ int[] exceptionTypeEnds,
+ int bodyStart,
+ boolean isConstructor) {
+ int[] sourceRange = { declarationStart, -1 }; // will be fixed up on exit
+ int[] nameRange = { nameStart, nameEnd };
+ int[] commentRange = { -1, -1 };
+ if (javaDocPositions != null) {
+ int length = javaDocPositions.length;
+ commentRange[0] = javaDocPositions[0];
+ commentRange[1] = javaDocPositions[length - 1];
+ }
+ int[] modifiersRange = { -1, -1 };
+ if (modifiersStart > -1) {
+ modifiersRange[0] = modifiersStart;
+ if (isConstructor) {
+ modifiersRange[1] = nameStart - 1;
+ } else {
+ modifiersRange[1] = returnTypeStart - 1;
+ }
+ }
+ int[] returnTypeRange = null;
+
+ if (extendedReturnTypeDimensionCount > 0)
+ returnTypeRange =
+ new int[] {
+ returnTypeStart,
+ returnTypeEnd,
+ parametersEnd + 1,
+ extendedReturnTypeDimensionEnd };
+ else
+ returnTypeRange = new int[] { returnTypeStart, returnTypeEnd };
+ int[] parameterRange = { nameEnd + 1, parametersEnd };
+ int[] exceptionRange = { -1, -1 };
+ if (exceptionTypes != null && exceptionTypes.length > 0) {
+ int exceptionCount = exceptionTypes.length;
+ exceptionRange[0] = exceptionTypeStarts[0];
+ exceptionRange[1] = exceptionTypeEnds[exceptionCount - 1];
+ }
+ int[] bodyRange = null;
+ if (exceptionRange[1] > -1) {
+ bodyRange = new int[] { exceptionRange[1] + 1, -1 };
+ // will be fixed up on exit
+ } else {
+ bodyRange = new int[] { parametersEnd + 1, -1 };
+ }
+ fNode =
+ new DOMMethod(
+ fDocument,
+ sourceRange,
+ CharArrayOps.charToString(name),
+ nameRange,
+ commentRange,
+ modifiers,
+ modifiersRange,
+ isConstructor,
+ CharArrayOps.charToString(returnType),
+ returnTypeRange,
+ CharArrayOps.charcharToString(parameterTypes),
+ CharArrayOps.charcharToString(parameterNames),
+ parameterRange,
+ CharArrayOps.charcharToString(exceptionTypes),
+ exceptionRange,
+ bodyRange);
+ addChild(fNode);
+ fStack.push(fNode);
+ }
+
+ /**
+ * @see IDocumentElementRequestor.enterClass(...);
+ */
+ public void enterClass(
+ int declarationStart,
+ int[] javaDocPositions,
+ int modifiers,
+ int modifiersStart,
+ int keywordStart,
+ char[] name,
+ int nameStart,
+ int nameEnd,
+ char[] superclass,
+ int superclassStart,
+ int superclassEnd,
+ char[][] superinterfaces,
+ int[] superinterfaceStarts,
+ int[] superinterfaceEnds,
+ int bodyStart) {
+
+ enterType(
+ declarationStart,
+ javaDocPositions,
+ modifiers,
+ modifiersStart,
+ keywordStart,
+ name,
+ nameStart,
+ nameEnd,
+ superclass,
+ superclassStart,
+ superclassEnd,
+ superinterfaces,
+ superinterfaceStarts,
+ superinterfaceEnds,
+ bodyStart,
+ true);
+ }
+
+ /**
+ * @see IDocumentElementRequestor.enterConstructor(...);
+ */
+ public void enterConstructor(
+ int declarationStart,
+ int[] javaDocPositions,
+ int modifiers,
+ int modifiersStart,
+ char[] name,
+ int nameStart,
+ int nameEnd,
+ char[][] parameterTypes,
+ int[] parameterTypeStarts,
+ int[] parameterTypeEnds,
+ char[][] parameterNames,
+ int[] parameterNameStarts,
+ int[] parameterNameEnds,
+ int parametersEnd,
+ char[][] exceptionTypes,
+ int[] exceptionTypeStarts,
+ int[] exceptionTypeEnds,
+ int bodyStart) {
+
+ /* see 1FVIIQZ */
+ String nameString = new String(fDocument, nameStart, nameEnd - nameStart);
+ int openParenPosition = nameString.indexOf('(');
+ if (openParenPosition > -1)
+ nameEnd = nameStart + openParenPosition - 1;
+
+ enterAbstractMethod(
+ declarationStart,
+ javaDocPositions,
+ modifiers,
+ modifiersStart,
+ null,
+ -1,
+ -1,
+ 0,
+ name,
+ nameStart,
+ nameEnd,
+ parameterTypes,
+ parameterTypeStarts,
+ parameterTypeEnds,
+ parameterNames,
+ parameterNameStarts,
+ parameterNameEnds,
+ parametersEnd,
+ 0,
+ -1,
+ exceptionTypes,
+ exceptionTypeStarts,
+ exceptionTypeEnds,
+ bodyStart,
+ true);
+ }
+
+ /**
+ * @see IDocumentElementRequestor.enterField(...);
+ */
+ public void enterField(
+ int declarationStart,
+ int[] javaDocPositions,
+ int modifiers,
+ int modifiersStart,
+ char[] type,
+ int typeStart,
+ int typeEnd,
+ int typeDimensionCount,
+ char[] name,
+ int nameStart,
+ int nameEnd,
+ int extendedTypeDimensionCount,
+ int extendedTypeDimensionEnd) {
+ int[] sourceRange =
+ {
+ declarationStart,
+ (extendedTypeDimensionEnd > nameEnd) ? extendedTypeDimensionEnd : nameEnd };
+ int[] nameRange = { nameStart, nameEnd };
+ int[] commentRange = { -1, -1 };
+ if (javaDocPositions != null) {
+ int length = javaDocPositions.length;
+ commentRange[0] = javaDocPositions[0];
+ commentRange[1] = javaDocPositions[length - 1];
+ }
+ int[] modifiersRange = { -1, -1 };
+ if (modifiersStart > -1) {
+ modifiersRange[0] = modifiersStart;
+ modifiersRange[1] = typeStart - 1;
+ }
+ int[] typeRange = { typeStart, typeEnd };
+ boolean hasInitializer = false; // fixed on exitField
+ int[] initializerRange = { -1, -1 }; // fixed on exitField
+ boolean isVariableDeclarator = false;
+ if (fNode instanceof DOMField) {
+ DOMField field = (DOMField) fNode;
+ if (field.fTypeRange[0] == typeStart)
+ isVariableDeclarator = true;
+ }
+ fNode =
+ new DOMField(
+ fDocument,
+ sourceRange,
+ CharArrayOps.charToString(name),
+ nameRange,
+ commentRange,
+ modifiers,
+ modifiersRange,
+ typeRange,
+ CharArrayOps.charToString(type),
+ hasInitializer,
+ initializerRange,
+ isVariableDeclarator);
+ addChild(fNode);
+ fStack.push(fNode);
+ }
+
+ /**
+ * @see IDocumentElementRequestor.enterInterface(...);
+ */
+ public void enterInterface(
+ int declarationStart,
+ int[] javaDocPositions,
+ int modifiers,
+ int modifiersStart,
+ int keywordStart,
+ char[] name,
+ int nameStart,
+ int nameEnd,
+ char[][] superinterfaces,
+ int[] superinterfaceStarts,
+ int[] superinterfaceEnds,
+ int bodyStart) {
+
+ enterType(
+ declarationStart,
+ javaDocPositions,
+ modifiers,
+ modifiersStart,
+ keywordStart,
+ name,
+ nameStart,
+ nameEnd,
+ null,
+ -1,
+ -1,
+ superinterfaces,
+ superinterfaceStarts,
+ superinterfaceEnds,
+ bodyStart,
+ false);
+ }
+
+ /**
+ * @see IDocumentElementRequestor.enterMethod(...);
+ */
+ public void enterMethod(
+ int declarationStart,
+ int[] javaDocPositions,
+ int modifiers,
+ int modifiersStart,
+ char[] returnType,
+ int returnTypeStart,
+ int returnTypeEnd,
+ int returnTypeDimensionCount,
+ char[] name,
+ int nameStart,
+ int nameEnd,
+ char[][] parameterTypes,
+ int[] parameterTypeStarts,
+ int[] parameterTypeEnds,
+ char[][] parameterNames,
+ int[] parameterNameStarts,
+ int[] parameterNameEnds,
+ int parametersEnd,
+ int extendedReturnTypeDimensionCount,
+ int extendedReturnTypeDimensionEnd,
+ char[][] exceptionTypes,
+ int[] exceptionTypeStarts,
+ int[] exceptionTypeEnds,
+ int bodyStart) {
+ enterAbstractMethod(
+ declarationStart,
+ javaDocPositions,
+ modifiers,
+ modifiersStart,
+ returnType,
+ returnTypeStart,
+ returnTypeEnd,
+ returnTypeDimensionCount,
+ name,
+ nameStart,
+ nameEnd,
+ parameterTypes,
+ parameterTypeStarts,
+ parameterTypeEnds,
+ parameterNames,
+ parameterNameStarts,
+ parameterNameEnds,
+ parametersEnd,
+ extendedReturnTypeDimensionCount,
+ extendedReturnTypeDimensionEnd,
+ exceptionTypes,
+ exceptionTypeStarts,
+ exceptionTypeEnds,
+ bodyStart,
+ false);
+ }
+
+ /**
+ * @see IDocumentElementRequestor.enterType(...);
+ */
+ protected void enterType(
+ int declarationStart,
+ int[] javaDocPositions,
+ int modifiers,
+ int modifiersStart,
+ int keywordStart,
+ char[] name,
+ int nameStart,
+ int nameEnd,
+ char[] superclass,
+ int superclassStart,
+ int superclassEnd,
+ char[][] superinterfaces,
+ int[] superinterfaceStarts,
+ int[] superinterfaceEnds,
+ int bodyStart,
+ boolean isClass) {
+ if (fBuildingType) {
+ int[] sourceRange = { declarationStart, -1 }; // will be fixed in the exit
+ int[] commentRange = { -1, -1 };
+ if (javaDocPositions != null) {
+ int length = javaDocPositions.length;
+ commentRange[0] = javaDocPositions[0];
+ commentRange[1] = javaDocPositions[length - 1];
+ }
+ int[] modifiersRange = { -1, -1 };
+ if (modifiersStart > -1) {
+ modifiersRange[0] = modifiersStart;
+ modifiersRange[1] = (modifiersStart > -1) ? keywordStart - 1 : -1;
+ }
+ int[] typeKeywordRange = { keywordStart, nameStart - 1 };
+ int[] nameRange = new int[] { nameStart, nameEnd };
+ int[] extendsKeywordRange = { -1, -1 };
+ int[] superclassRange = { -1, -1 };
+ int[] implementsKeywordRange = { -1, -1 };
+ int[] interfacesRange = { -1, -1 };
+ if (isClass) {
+ if (superclass != null) {
+ extendsKeywordRange[0] = nameEnd + 1;
+ extendsKeywordRange[1] = superclassStart - 1;
+ superclassRange[0] = superclassStart;
+ superclassRange[1] = bodyStart - 1;
+ }
+ if (superinterfaces != null && superinterfaces.length > 0) {
+ superclassRange[1] = superclassEnd;
+ if (superclassEnd > -1) {
+ implementsKeywordRange[0] = superclassEnd + 1;
+ } else {
+ implementsKeywordRange[0] = nameEnd + 1;
+ }
+ implementsKeywordRange[1] = superinterfaceStarts[0] - 1;
+ interfacesRange[0] = superinterfaceStarts[0];
+ interfacesRange[1] = bodyStart - 1;
+ }
+ } else {
+ if (superinterfaces != null && superinterfaces.length > 0) {
+ extendsKeywordRange[0] = nameEnd + 1;
+ extendsKeywordRange[1] = superinterfaceStarts[0] - 1;
+ interfacesRange[0] = superinterfaceStarts[0];
+ interfacesRange[1] = bodyStart - 1;
+ }
+ }
+ int[] openBodyRange = { bodyStart, -1 }; // fixed by setTypeRanges(DOMNode)
+ int[] closeBodyRange = { -1, -1 }; // will be fixed in exit
+ fNode =
+ new DOMType(
+ fDocument,
+ sourceRange,
+ new String(name),
+ nameRange,
+ commentRange,
+ modifiers,
+ modifiersRange,
+ typeKeywordRange,
+ superclassRange,
+ extendsKeywordRange,
+ CharArrayOps.charcharToString(superinterfaces),
+ interfacesRange,
+ implementsKeywordRange,
+ openBodyRange,
+ closeBodyRange,
+ isClass);
+ addChild(fNode);
+ fStack.push(fNode);
+ }
+ }
+
+ /**
+ * Finishes the configuration of the constructors and methods.
+ *
+ * @param bodyEnd - a source position corresponding to the closing bracket of the method
+ * @param declarationEnd - a source position corresponding to the end of the method
+ * declaration. This can include whitespace and comments following the closing bracket.
+ */
+ protected void exitAbstractMethod(int bodyEnd, int declarationEnd) {
+ DOMMethod method = (DOMMethod) fStack.pop();
+ method.setSourceRangeEnd(declarationEnd);
+ method.setBodyRangeEnd(bodyEnd + 1);
+ fNode = method;
+ if (fBuildingSingleMember) {
+ fFinishedSingleMember = true;
+ }
+ }
+
+ /**
+ * Finishes the configuration of the class DOM object which
+ * was created by a previous enterClass call.
+ *
+ * @see IDocumentElementRequestor.exitClass(...);
+ */
+ public void exitClass(int bodyEnd, int declarationEnd) {
+ exitType(bodyEnd, declarationEnd);
+ }
+
+ /**
+ * Finishes the configuration of the method DOM object which
+ * was created by a previous enterConstructor call.
+ *
+ * @see IDocumentElementRequestor.exitConstructor(...);
+ */
+ public void exitConstructor(int bodyEnd, int declarationEnd) {
+ exitAbstractMethod(bodyEnd, declarationEnd);
+ }
+
+ /**
+ * Finishes the configuration of the field DOM object which
+ * was created by a previous enterField call.
+ *
+ * @see IDocumentElementRequestor.exitField(...);
+ */
+ public void exitField(int bodyEnd, int declarationEnd) {
+ DOMField field = (DOMField) fStack.pop();
+ if (field.getEndPosition() < declarationEnd) {
+ field.setSourceRangeEnd(declarationEnd);
+ int nameEnd = field.fNameRange[1];
+ if (nameEnd < bodyEnd) {
+ /* see 1FVIIV8 - obtain initializer range */
+ String initializer = new String(fDocument, nameEnd + 1, bodyEnd - nameEnd);
+ int index = initializer.indexOf('=');
+ if (index > -1) {
+ field.setHasInitializer(true);
+ field.setInitializerRange(nameEnd + index + 2, bodyEnd);
+ }
+ }
+ }
+ fFieldCount++;
+ fNode = field;
+ if (fBuildingSingleMember) {
+ fFinishedSingleMember = true;
+ }
+ }
+
+ /**
+ * Finishes the configuration of the interface DOM object which
+ * was created by a previous enterInterface call.
+ *
+ * @see IDocumentElementRequestor.exitInterface(...);
+ */
+ public void exitInterface(int bodyEnd, int declarationEnd) {
+ exitType(bodyEnd, declarationEnd);
+ }
+
+ /**
+ * Finishes the configuration of the method DOM object which
+ * was created by a previous enterMethod call.
+ *
+ * @see IDocumentElementRequestor.exitMethod(...);
+ */
+ public void exitMethod(int bodyEnd, int declarationEnd) {
+ exitAbstractMethod(bodyEnd, declarationEnd);
+ }
+
+ /**
+ * Creates a new parser.
+ */
+ protected DocumentElementParser getParser() {
+ return new DocumentElementParser(this, new NullProblemFactory());
+ }
+
+ /**
+ * Initializes the builder to create a document fragment.
+ *
+ * @param sourceCode - the document containing the source code to be analyzed
+ * @param buildingCompilationUnit - true if a the document is being analyzed to
+ * create a compilation unit, otherwise false
+ * @param buildingType - true if the document is being analyzed to create a
+ * type or compilation unit
+ * @param singleMember - true if building a single member
+ */
+ protected void initializeBuild(
+ char[] sourceCode,
+ boolean buildingCompilationUnit,
+ boolean buildingType,
+ boolean singleMember) {
+ super.initializeBuild(sourceCode, buildingCompilationUnit, buildingType);
+ fBuildingSingleMember = singleMember;
+ fFinishedSingleMember = false;
+
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMCompilationUnit.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMCompilationUnit.java
new file mode 100644
index 0000000000..2c66a4c5be
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMCompilationUnit.java
@@ -0,0 +1,198 @@
+package org.eclipse.jdt.internal.core.jdom;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.Flags;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.jdom.*;
+import org.eclipse.jdt.internal.core.util.*;
+
+import java.util.Vector;
+
+/**
+ * DOMCompilation unit provides an implementation of IDOMCompilationUnit.
+ *
+ * @see IDOMCompilationUnit
+ * @see DOMNode
+ */
+class DOMCompilationUnit extends DOMNode implements IDOMCompilationUnit {
+
+ /**
+ * The comment and/or whitespace preceding the
+ * first document fragment in this compilation
+ * unit.
+ */
+ protected String fHeader;
+ /**
+ * Creates a new empty COMPILATION_UNIT document fragment.
+ */
+ DOMCompilationUnit() {
+ fHeader = "";
+ }
+
+ /**
+ * Creates a new COMPILATION_UNIT on the given range of the document.
+ *
+ * @param document - the document containing this node's original contents
+ * @param sourceRange - a two element array of integers describing the
+ * entire inclusive source range of this node within its document.
+ * A compilation unit's source range is the entire document - i.e.
+ * the first integer is zero, and the second integer is the position
+ * of the last character in the document.
+ */
+ DOMCompilationUnit(char[] document, int[] sourceRange) {
+ super(document, sourceRange, null, new int[] { -1, -1 });
+ fHeader = "";
+ }
+
+ /**
+ * @see DOMNode#appendContents(CharArrayBuffer)
+ */
+ protected void appendFragmentedContents(CharArrayBuffer buffer) {
+ buffer.append(getHeader());
+ appendContentsOfChildren(buffer);
+ }
+
+ /**
+ * @see IDOMNode#canHaveChildren()
+ */
+ public boolean canHaveChildren() {
+ return true;
+ }
+
+ /**
+ * @see IDOMCompilationUnit#getHeader()
+ */
+ public String getHeader() {
+ return fHeader;
+ }
+
+ /**
+ * @see IDOMNode#getJavaElement
+ */
+ public IJavaElement getJavaElement(IJavaElement parent)
+ throws IllegalArgumentException {
+ if (parent.getElementType() == IJavaElement.PACKAGE_FRAGMENT) {
+ return ((IPackageFragment) parent).getCompilationUnit(getName());
+ } else {
+ throw new IllegalArgumentException("Illegal parent argument");
+ }
+ }
+
+ /**
+ * @see IDOMCompilationUnit#getName()
+ */
+ public String getName() {
+ IDOMType topLevelType = null;
+ IDOMType firstType = null;
+ IDOMNode child = fFirstChild;
+ while (child != null) {
+ if (child.getNodeType() == IDOMNode.TYPE) {
+ IDOMType type = (IDOMType) child;
+ if (firstType == null) {
+ firstType = type;
+ }
+ if (Flags.isPublic(type.getFlags())) {
+ topLevelType = type;
+ break;
+ }
+ }
+ child = child.getNextNode();
+ }
+ if (topLevelType == null) {
+ topLevelType = firstType;
+ }
+ if (topLevelType != null) {
+ return topLevelType.getName() + ".java";
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * @see IDOMNode#getNodeType()
+ */
+ public int getNodeType() {
+ return IDOMNode.COMPILATION_UNIT;
+ }
+
+ /**
+ * Sets the header
+ */
+ protected void initalizeHeader() {
+ DOMNode child = (DOMNode) getFirstChild();
+ if (child != null) {
+ int childStart = child.getStartPosition();
+ if (childStart > 1) {
+ setHeader(CharArrayOps.substring(fDocument, 0, childStart));
+ }
+ }
+ }
+
+ /**
+ * @see IDOMNode#isAllowableChild(IDOMNode)
+ */
+ public boolean isAllowableChild(IDOMNode node) {
+ if (node != null) {
+ int type = node.getNodeType();
+ return type == IDOMNode.PACKAGE
+ || type == IDOMNode.IMPORT
+ || type == IDOMNode.TYPE;
+ } else {
+ return false;
+ }
+
+ }
+
+ /**
+ * @see DOMNode
+ */
+ protected DOMNode newDOMNode() {
+ return new DOMCompilationUnit();
+ }
+
+ /**
+ * Normalizes this <code>DOMNode</code>'s source positions to include whitespace preceeding
+ * the node on the line on which the node starts, and all whitespace after the node up to
+ * the next node's start
+ */
+ void normalize(ILineStartFinder finder) {
+ super.normalize(finder);
+ initalizeHeader();
+ }
+
+ /**
+ * @see IDOMCompilationUnit@setHeader(String)
+ */
+ public void setHeader(String comment) {
+ fHeader = comment;
+ fragment();
+ }
+
+ /**
+ * @see IDOMCompilationUnit#setName(String)
+ */
+ public void setName(String name) {
+ }
+
+ /**
+ * @see DOMNode#shareContents(DOMNode)
+ */
+ protected void shareContents(DOMNode node) {
+ super.shareContents(node);
+ fHeader = ((DOMCompilationUnit) node).fHeader;
+ }
+
+ /**
+ * @see IDOMNode#toString()
+ */
+ public String toString() {
+ return "COMPILATION_UNIT: " + getName();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMField.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMField.java
new file mode 100644
index 0000000000..22a94e68a5
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMField.java
@@ -0,0 +1,709 @@
+package org.eclipse.jdt.internal.core.jdom;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.Flags;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.jdom.*;
+import org.eclipse.jdt.internal.core.JavaModelManager;
+import org.eclipse.jdt.internal.core.util.*;
+
+import java.util.Enumeration;
+
+/**
+ * DOMField provides an implementation of IDOMField.
+ *
+ * @see IDOMField
+ * @see DOMNode
+ */
+class DOMField extends DOMMember implements IDOMField {
+
+ /**
+ * Contains the type of the field when the type
+ * has been altered from the contents in the
+ * document, otherwise <code>null</code>.
+ */
+ protected String fType;
+
+ /**
+ * The original inclusive source range of the
+ * field's type in the document.
+ */
+ protected int[] fTypeRange;
+
+ /**
+ * The contents of the initializer when the
+ * initializer has been altered from the
+ * original state in the document, otherwise
+ * <code>null</code>.
+ */
+ protected String fInitializer;
+
+ /**
+ * The original inclusive source range of the
+ * initializer in the document.
+ */
+ protected int[] fInitializerRange;
+
+ /**
+ * Constructs an empty field node.
+ */
+ DOMField() {
+ }
+
+ /**
+ * Creates a new detailed FIELD document fragment on the given range of the document.
+ *
+ * @param document - the document containing this node's original contents
+ * @param sourceRange - a two element array of integers describing the
+ * entire inclusive source range of this node within its document.
+ * Contents start on and include the character at the first position.
+ * Contents end on and include the character at the last position.
+ * An array of -1's indicates this node's contents do not exist
+ * in the document.
+ * @param name - the identifier portion of the name of this field,
+ * corresponding to VariableDeclaratorId (JLS 8.3).
+ * @param nameRange - a two element array of integers describing the
+ * entire inclusive source range of this node's name within its document,
+ * including any array qualifiers that might follow the name.
+ * @param commentRange - a two element array describing the comments that precede
+ * the member declaration. The first matches the start of this node's
+ * sourceRange, and the second is the new-line or first non-whitespace
+ * character following the last comment. If no comments are present,
+ * this array contains two -1's.
+ * @param flags - an integer representing the modifiers for this member. The
+ * integer can be analyzed with org.eclipse.jdt.core.Flags
+ * @param modifierRange - a two element array describing the location of
+ * modifiers for this member within its source range. The first integer
+ * is the first character of the first modifier for this member, and
+ * the second integer is the last whitespace character preceeding the
+ * next part of this member declaration. If there are no modifiers present
+ * in this node's source code (i.e. default protection), this array
+ * contains two -1's.
+ * @param typeRange- a two element array describing the location of the
+ * typeName in the document - the positions of the first and last characters
+ * of the typeName.
+ * @param type - the type of the field, in normalized form, as defined in
+ * Type in Field Declaration (JLS 8.3)
+ * @param hasInitializer - true if this field declaration includes an initializer,
+ * otherwise false
+ * @param initRange - a two element array describing the location of the initializer
+ * in the declaration. The first integer is the position of the character
+ * following the equals sign, and the position of the last character is the last
+ * in the initializer. If this field has no initializer, this array contains
+ * two -1's.
+ * @param isVariableDeclarator - true if the field is a seconday variable declarator
+ * for a previous field declaration.
+ */
+ DOMField(
+ char[] document,
+ int[] sourceRange,
+ String name,
+ int[] nameRange,
+ int[] commentRange,
+ int flags,
+ int[] modifierRange,
+ int[] typeRange,
+ String type,
+ boolean hasInitializer,
+ int[] initRange,
+ boolean isVariableDeclarator) {
+ super(
+ document,
+ sourceRange,
+ name,
+ nameRange,
+ commentRange,
+ flags,
+ modifierRange);
+
+ fType = type;
+ fTypeRange = typeRange;
+ setHasInitializer(hasInitializer);
+ fInitializerRange = initRange;
+ setIsVariableDeclarator(isVariableDeclarator);
+ setMask(MASK_DETAILED_SOURCE_INDEXES, true);
+
+ }
+
+ /**
+ * Creates a new simple FIELD document fragment on the given range of the document.
+ *
+ * @param document - the document containing this node's original contents
+ * @param sourceRange - a two element array of integers describing the
+ * entire inclusive source range of this node within its document.
+ * Contents start on and include the character at the first position.
+ * Contents end on and include the character at the last position.
+ * An array of -1's indicates this node's contents do not exist
+ * in the document.
+ * @param name - the identifier portion of the name of this field,
+ * corresponding to VariableDeclaratorId (JLS 8.3).
+ * @param nameRange - a two element array of integers describing the
+ * entire inclusive source range of this node's name within its document,
+ * including any array qualifiers that might follow the name.
+ * @param flags - an integer representing the modifiers for this member. The
+ * integer can be analyzed with org.eclipse.jdt.core.Flags
+ * @param type - the type of the field, in normalized form, as defined in
+ * Type in Field Declaration (JLS 8.3)
+ * @param isVariableDeclarator - true if the field is a seconday variable declarator
+ * for a previous field declaration.
+ */
+ DOMField(
+ char[] document,
+ int[] sourceRange,
+ String name,
+ int[] nameRange,
+ int flags,
+ String type,
+ boolean isVariableDeclarator) {
+ this(
+ document,
+ sourceRange,
+ name,
+ nameRange,
+ new int[] { -1, -1 },
+ flags,
+ new int[] { -1, -1 },
+ new int[] { -1, -1 },
+ type,
+ false,
+ new int[] { -1, -1 },
+ isVariableDeclarator);
+ setMask(MASK_DETAILED_SOURCE_INDEXES, false);
+ }
+
+ /**
+ * Appends this member's body contents to the given CharArrayBuffer.
+ * Body contents include the member body and any trailing whitespace.
+ *
+ * <p>A field does not have a body.
+ *
+ * @see DOMMember#appendMemberBodyContents(CharArrayBuffer)
+ */
+ protected void appendMemberBodyContents(CharArrayBuffer buffer) {
+ }
+
+ /**
+ * @see DOMMember#appendMemberDeclarationContents(CharArrayBuffer)
+ */
+ protected void appendMemberDeclarationContents(CharArrayBuffer buffer) {
+
+ if (isVariableDeclarator()) {
+ buffer.append(fDocument, fSourceRange[0], fNameRange[0] - fSourceRange[0]);
+ } else {
+ buffer.append(getTypeContents()).append(
+ fDocument,
+ fTypeRange[1] + 1,
+ fNameRange[0] - fTypeRange[1] - 1);
+ }
+
+ buffer.append(getNameContents());
+ if (hasInitializer()) {
+ if (fInitializerRange[0] < 0) {
+ buffer.append("=").append(fInitializer).append(
+ fDocument,
+ fNameRange[1] + 1,
+ fSourceRange[1] - fNameRange[1]);
+ } else {
+ buffer
+ .append(fDocument, fNameRange[1] + 1, fInitializerRange[0] - fNameRange[1] - 1)
+ .append(getInitializer())
+ .append(
+ fDocument,
+ fInitializerRange[1] + 1,
+ fSourceRange[1] - fInitializerRange[1]);
+ }
+ } else {
+ if (fInitializerRange[0] < 0) {
+ buffer.append(fDocument, fNameRange[1] + 1, fSourceRange[1] - fNameRange[1]);
+ } else {
+ buffer.append(
+ fDocument,
+ fInitializerRange[1] + 1,
+ fSourceRange[1] - fInitializerRange[1]);
+ }
+ }
+
+ }
+
+ /**
+ * Appends this member's header contents to the given CharArrayBuffer.
+ * Header contents include any preceding comments and modifiers.
+ *
+ * <p>If this field is a secondary variable declarator, there is no header.
+ *
+ * @see DOMMember#appendMemberHeaderFragment(CharArrayBuffer)
+ */
+ protected void appendMemberHeaderFragment(CharArrayBuffer buffer) {
+
+ if (isVariableDeclarator()) {
+ return;
+ } else {
+ super.appendMemberHeaderFragment(buffer);
+ }
+
+ }
+
+ /**
+ * @see DOMMember#appendSimpleContents(CharArrayBuffer)
+ */
+ protected void appendSimpleContents(CharArrayBuffer buffer) {
+ // append eveything before my name
+ buffer.append(fDocument, fSourceRange[0], fNameRange[0] - fSourceRange[0]);
+ // append my name
+ buffer.append(fName);
+ // append everything after my name
+ buffer.append(fDocument, fNameRange[1] + 1, fSourceRange[1] - fNameRange[1]);
+ }
+
+ /**
+ * Generates detailed source indexes for this node if possible.
+ *
+ * @exception DOMException if unable to generate detailed source indexes
+ * for this node
+ */
+ protected void becomeDetailed() throws DOMException {
+ if (!isDetailed()) {
+ if (isVariableDeclarator() || hasMultipleVariableDeclarators()) {
+ DOMNode first = getFirstFieldDeclaration();
+ DOMNode last = getLastFieldDeclaration();
+ DOMNode node = first;
+ String source = first.getContents();
+ while (node != last) {
+ node = node.fNextNode;
+ source += node.getContents();
+ }
+ DOMBuilder builder = new DOMBuilder();
+ IDOMField[] details = builder.createFields(source.toCharArray());
+ if (details.length == 0) {
+ throw new DOMException("Unable to generate detailed source indexes.");
+ } else {
+ node = this;
+ for (int i = 0; i < details.length; i++) {
+ node.shareContents((DOMNode) details[i]);
+ node = node.fNextNode;
+ }
+ }
+ } else {
+ super.becomeDetailed();
+ }
+
+ }
+ }
+
+ /**
+ * @see IDOMNode#clone()
+ */
+ public Object clone() {
+ if (isVariableDeclarator() || hasMultipleVariableDeclarators()) {
+ return getFactory().createField(
+ new String(getSingleVariableDeclaratorContents()));
+ } else {
+ return super.clone();
+ }
+ }
+
+ /**
+ * Expands all variable declarators in this field declaration into
+ * stand-alone field declarations.
+ */
+ protected void expand() {
+ if (isVariableDeclarator() || hasMultipleVariableDeclarators()) {
+ Enumeration siblings = new SiblingEnumeration(getFirstFieldDeclaration());
+ DOMField field = (DOMField) siblings.nextElement();
+ DOMNode next = field.fNextNode;
+ while (siblings.hasMoreElements()
+ && (next instanceof DOMField)
+ && (((DOMField) next).isVariableDeclarator())) {
+ field.localizeContents();
+ if (field.fParent != null) {
+ field.fParent.fragment();
+ }
+ field = (DOMField) siblings.nextElement();
+ next = field.fNextNode;
+ }
+ field.localizeContents();
+ }
+ }
+
+ /**
+ * @see DOMNode#getDetailedNode()
+ */
+ protected DOMNode getDetailedNode() {
+ if (isVariableDeclarator() || hasMultipleVariableDeclarators()) {
+ return (DOMNode) getFactory().createField(
+ new String(getSingleVariableDeclaratorContents()));
+ } else {
+ return (DOMNode) getFactory().createField(getContents());
+ }
+ }
+
+ /**
+ * Returns the first field document fragment that defines
+ * the type for this variable declarator.
+ */
+ protected DOMField getFirstFieldDeclaration() {
+ if (isVariableDeclarator()) {
+ return ((DOMField) fPreviousNode).getFirstFieldDeclaration();
+ } else {
+ return this;
+ }
+ }
+
+ /**
+ * @see IDOMField#getInitializer()
+ */
+ public String getInitializer() {
+ becomeDetailed();
+ if (hasInitializer()) {
+ if (fInitializer != null) {
+ return fInitializer;
+ } else {
+ return CharArrayOps.substring(
+ fDocument,
+ fInitializerRange[0],
+ fInitializerRange[1] + 1 - fInitializerRange[0]);
+ }
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * @see IDOMNode#getJavaElement
+ */
+ public IJavaElement getJavaElement(IJavaElement parent)
+ throws IllegalArgumentException {
+ if (parent.getElementType() == IJavaElement.TYPE) {
+ return ((IType) parent).getField(getName());
+ } else {
+ throw new IllegalArgumentException("Illegal parent argument");
+ }
+ }
+
+ /**
+ * Returns the last field document fragment in this muli-declarator statement.
+ */
+ protected DOMField getLastFieldDeclaration() {
+ DOMField field = this;
+ while (field.isVariableDeclarator()
+ || field.hasMultipleVariableDeclarators()) {
+ if (field.fNextNode instanceof DOMField
+ && ((DOMField) field.fNextNode).isVariableDeclarator()) {
+ field = (DOMField) field.fNextNode;
+ } else {
+ break;
+ }
+ }
+ return field;
+ }
+
+ /**
+ * @see DOMMember#getMemberDeclarationStartPosition()
+ */
+ protected int getMemberDeclarationStartPosition() {
+ return fTypeRange[0];
+ }
+
+ /**
+ * @see IDOMNode#getNodeType()
+ */
+ public int getNodeType() {
+ return IDOMNode.FIELD;
+ }
+
+ /**
+ * Returns a String representing this field declaration as a field
+ * declaration with one variable declarator.
+ */
+ protected char[] getSingleVariableDeclaratorContents() {
+
+ CharArrayBuffer buffer = new CharArrayBuffer();
+ DOMField first = getFirstFieldDeclaration();
+ if (first.isDetailed()) {
+ first.appendMemberHeaderFragment(buffer);
+ buffer.append(getType());
+ if (isVariableDeclarator()) {
+ buffer.append(" ");
+ } else {
+ buffer.append(fDocument, fTypeRange[1] + 1, fNameRange[0] - fTypeRange[1] - 1);
+ }
+ } else {
+ buffer.append(
+ first.fDocument,
+ first.fSourceRange[0],
+ first.fNameRange[0] - first.fSourceRange[0]);
+ }
+
+ buffer.append(getName());
+ if (hasInitializer()) {
+ if (fInitializerRange[0] < 0) {
+ buffer.append("=").append(fInitializer).append(';').append(
+ JavaModelManager.LINE_SEPARATOR);
+ } else {
+ buffer
+ .append(fDocument, fNameRange[1] + 1, fInitializerRange[0] - fNameRange[1] - 1)
+ .append(getInitializer())
+ .append(';')
+ .append(JavaModelManager.LINE_SEPARATOR);
+ }
+ } else {
+ buffer.append(';').append(JavaModelManager.LINE_SEPARATOR);
+ }
+ return buffer.getContents();
+ }
+
+ /**
+ * @see IDOMField#getType()
+ */
+ public String getType() {
+ return fType;
+ }
+
+ /**
+ * Returns the souce code to be used for this
+ * field's type.
+ */
+ protected char[] getTypeContents() {
+ if (isTypeAltered()) {
+ return fType.toCharArray();
+ } else {
+ return CharArrayOps.subarray(
+ fDocument,
+ fTypeRange[0],
+ fTypeRange[1] + 1 - fTypeRange[0]);
+ }
+ }
+
+ /**
+ * Returns true if this field has an initializer expression,
+ * otherwise false.
+ */
+ protected boolean hasInitializer() {
+ return getMask(MASK_FIELD_HAS_INITIALIZER);
+ }
+
+ /**
+ * Returns true is this field declarations has more than one
+ * variable declarator, otherwise false;
+ */
+ protected boolean hasMultipleVariableDeclarators() {
+ return fNextNode != null
+ && (fNextNode instanceof DOMField)
+ && ((DOMField) fNextNode).isVariableDeclarator();
+ }
+
+ /**
+ * Inserts the given un-parented node as a sibling of this node, immediately before
+ * this node. Once inserted, the sibling is only dependent on this document fragment.
+ *
+ * <p>When a sibling is inserted before a variable declarator, it must first
+ * be expanded.
+ *
+ * @see IDOMNode#insertSibling(IDOMNode)
+ */
+ public void insertSibling(IDOMNode sibling)
+ throws IllegalArgumentException, DOMException {
+ if (isVariableDeclarator()) {
+ expand();
+ }
+ super.insertSibling(sibling);
+ }
+
+ /**
+ * Returns true if this field's type has been altered
+ * from the original document contents.
+ */
+ protected boolean isTypeAltered() {
+ return getMask(MASK_FIELD_TYPE_ALTERED);
+ }
+
+ /**
+ * Returns true if this field is declared as a secondary variable
+ * declarator for a previous field declaration.
+ */
+ protected boolean isVariableDeclarator() {
+ return getMask(MASK_FIELD_IS_VARIABLE_DECLARATOR);
+ }
+
+ /**
+ * @see DOMNode
+ */
+ protected DOMNode newDOMNode() {
+ return new DOMField();
+ }
+
+ /**
+ * Normalizes this <code>DOMNode</code>'s end position.
+ */
+ void normalizeEndPosition(ILineStartFinder finder, DOMNode next) {
+ if (next == null) {
+ // this node's end position includes all of the characters up
+ // to the end of the enclosing node
+ DOMNode parent = (DOMNode) getParent();
+ if (parent == null || parent instanceof DOMCompilationUnit) {
+ setSourceRangeEnd(fDocument.length - 1);
+ } else {
+ // parent is a type
+ setSourceRangeEnd(((DOMType) parent).getCloseBodyPosition() - 1);
+ }
+ } else {
+ // this node's end position is just before the start of the next node
+ // unless the next node is a field that is declared along with this one
+ next.normalizeStartPosition(getEndPosition(), finder);
+ if (next instanceof DOMField) {
+ DOMField field = (DOMField) next;
+ if (field.isVariableDeclarator() && fTypeRange[0] == field.fTypeRange[0])
+ return;
+ }
+ setSourceRangeEnd(next.getStartPosition() - 1);
+ }
+ }
+
+ /**
+ * Normalizes this <code>DOMNode</code>'s start position.
+ */
+ void normalizeStartPosition(int endPosition, ILineStartFinder finder) {
+ if (isVariableDeclarator()) {
+ // start position is end of last element
+ setStartPosition(fPreviousNode.getEndPosition() + 1);
+ } else {
+ super.normalizeStartPosition(endPosition, finder);
+ }
+ }
+
+ /**
+ * Offsets all the source indexes in this node by the given amount.
+ */
+ protected void offset(int offset) {
+ super.offset(offset);
+ offsetRange(fInitializerRange, offset);
+ offsetRange(fTypeRange, offset);
+ }
+
+ /**
+ * Separates this node from its parent and siblings, maintaining any ties that
+ * this node has to the underlying document fragment.
+ *
+ * <p>When a field with multiple declarators is removed, its declaration
+ * must first be expanded.
+ *
+ * @see IDOMNode#remove()
+ */
+ public void remove() {
+ expand();
+ super.remove();
+ }
+
+ /**
+ * @see IDOMMember#setComment(String)
+ */
+ public void setComment(String comment) {
+ expand();
+ super.setComment(comment);
+ }
+
+ /**
+ * @see IDOMMember#setFlags(int)
+ */
+ public void setFlags(int flags) {
+ expand();
+ super.setFlags(flags);
+ }
+
+ /**
+ * Sets the state of this field declaration as having
+ * an initializer expression.
+ */
+ protected void setHasInitializer(boolean hasInitializer) {
+ setMask(MASK_FIELD_HAS_INITIALIZER, hasInitializer);
+ }
+
+ /**
+ * @see IDOMField#setInitializer(char[])
+ */
+ public void setInitializer(String initializer) {
+ becomeDetailed();
+ fragment();
+ setHasInitializer(initializer != null);
+ fInitializer = initializer;
+ }
+
+ /**
+ * Sets the initializer range.
+ */
+ void setInitializerRange(int start, int end) {
+ fInitializerRange[0] = start;
+ fInitializerRange[1] = end;
+ }
+
+ /**
+ * Sets the state of this field declaration as being a
+ * secondary variable declarator for a previous field
+ * declaration.
+ */
+ protected void setIsVariableDeclarator(boolean isVariableDeclarator) {
+ setMask(MASK_FIELD_IS_VARIABLE_DECLARATOR, isVariableDeclarator);
+ }
+
+ /**
+ * @see IDOMField#setName(char[])
+ */
+ public void setName(String name) throws IllegalArgumentException {
+ if (name == null) {
+ throw new IllegalArgumentException("illegal to set name to null");
+ } else {
+ super.setName(name);
+ setTypeAltered(true);
+ }
+ }
+
+ /**
+ * @see IDOMField#setType(char[])
+ */
+ public void setType(String typeName) throws IllegalArgumentException {
+ if (typeName == null) {
+ throw new IllegalArgumentException("Illegal to set field type to null");
+ }
+ becomeDetailed();
+ expand();
+ fragment();
+ setTypeAltered(true);
+ setNameAltered(true);
+ fType = typeName;
+ }
+
+ /**
+ * Sets the state of this field declaration as having
+ * the field type altered from the original document.
+ */
+ protected void setTypeAltered(boolean typeAltered) {
+ setMask(MASK_FIELD_TYPE_ALTERED, typeAltered);
+ }
+
+ /**
+ * @see DOMNode#shareContents(DOMNode)
+ */
+ protected void shareContents(DOMNode node) {
+ super.shareContents(node);
+ DOMField field = (DOMField) node;
+ fInitializer = field.fInitializer;
+ fInitializerRange = rangeCopy(field.fInitializerRange);
+ fType = field.fType;
+ fTypeRange = rangeCopy(field.fTypeRange);
+ }
+
+ /**
+ * @see IDOMNode#toString()
+ */
+ public String toString() {
+ return "FIELD: " + getName();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMImport.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMImport.java
new file mode 100644
index 0000000000..4af1551aa8
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMImport.java
@@ -0,0 +1,170 @@
+package org.eclipse.jdt.internal.core.jdom;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.Flags;
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.jdom.*;
+import org.eclipse.jdt.internal.core.JavaModelManager;
+import org.eclipse.jdt.internal.core.util.*;
+
+/**
+ * DOMImport provides an implementation of IDOMImport.
+ *
+ * @see IDOMImport
+ * @see DOMNode
+ */
+class DOMImport extends DOMNode implements IDOMImport {
+ /**
+ * Indicates if this import is an on demand type import
+ */
+ protected boolean fOnDemand;
+ /**
+ * Creates a new empty IMPORT node.
+ */
+ DOMImport() {
+ fName = "java.lang.*";
+ setMask(MASK_DETAILED_SOURCE_INDEXES, true);
+ }
+
+ /**
+ * Creates a new detailed IMPORT document fragment on the given range of the document.
+ *
+ * @param document - the document containing this node's original contents
+ * @param sourceRange - a two element array of integers describing the
+ * entire inclusive source range of this node within its document.
+ * Contents start on and include the character at the first position.
+ * Contents end on and include the character at the last position.
+ * An array of -1's indicates this node's contents do not exist
+ * in the document.
+ * @param name - the identifier portion of the name of this node, or
+ * <code>null</code> if this node does not have a name
+ * @param nameRange - a two element array of integers describing the
+ * entire inclusive source range of this node's name within its document,
+ * including any array qualifiers that might immediately follow the name
+ * or -1's if this node does not have a name.
+ * @param onDemand - indicates if this import is an on demand style import
+ */
+ DOMImport(
+ char[] document,
+ int[] sourceRange,
+ String name,
+ int[] nameRange,
+ boolean onDemand) {
+ super(document, sourceRange, name, nameRange);
+ fOnDemand = onDemand;
+ setMask(MASK_DETAILED_SOURCE_INDEXES, true);
+ }
+
+ /**
+ * Creates a new simple IMPORT document fragment on the given range of the document.
+ *
+ * @param document - the document containing this node's original contents
+ * @param sourceRange - a two element array of integers describing the
+ * entire inclusive source range of this node within its document.
+ * Contents start on and include the character at the first position.
+ * Contents end on and include the character at the last position.
+ * An array of -1's indicates this node's contents do not exist
+ * in the document.
+ * @param name - the identifier portion of the name of this node, or
+ * <code>null</code> if this node does not have a name
+ * @param onDemand - indicates if this import is an on demand style import
+ */
+ DOMImport(char[] document, int[] sourceRange, String name, boolean onDemand) {
+ this(document, sourceRange, name, new int[] { -1, -1 }, onDemand);
+ fOnDemand = onDemand;
+ setMask(MASK_DETAILED_SOURCE_INDEXES, false);
+ }
+
+ /**
+ * @see DOMNode#appendFragmentedContents(CharArrayBuffer)
+ */
+ protected void appendFragmentedContents(CharArrayBuffer buffer) {
+ if (fNameRange[0] < 0) {
+ buffer.append("import ").append(fName).append(';').append(
+ JavaModelManager.LINE_SEPARATOR);
+ } else {
+ buffer.append(fDocument, fSourceRange[0], fNameRange[0] - fSourceRange[0]);
+ //buffer.append(fDocument, fNameRange[0], fNameRange[1] - fNameRange[0] + 1);
+ buffer.append(fName);
+ buffer.append(fDocument, fNameRange[1] + 1, fSourceRange[1] - fNameRange[1]);
+ }
+ }
+
+ /**
+ * @see IDOMNode#getContents()
+ */
+ public String getContents() {
+ if (fName == null) {
+ return null;
+ } else {
+ return super.getContents();
+ }
+ }
+
+ /**
+ * @see DOMNode#getDetailedNode()
+ */
+ protected DOMNode getDetailedNode() {
+ return (DOMNode) getFactory().createImport(getContents());
+ }
+
+ /**
+ * @see IDOMNode#getJavaElement
+ */
+ public IJavaElement getJavaElement(IJavaElement parent)
+ throws IllegalArgumentException {
+ if (parent.getElementType() == IJavaElement.COMPILATION_UNIT) {
+ return ((ICompilationUnit) parent).getImport(getName());
+ } else {
+ throw new IllegalArgumentException("Illegal parent argument");
+ }
+ }
+
+ /**
+ * @see IDOMNode#getNodeType()
+ */
+ public int getNodeType() {
+ return IDOMNode.IMPORT;
+ }
+
+ /**
+ * @see IDOMImport#isOnDemand()
+ */
+ public boolean isOnDemand() {
+ return fOnDemand;
+ }
+
+ /**
+ * @see DOMNode
+ */
+ protected DOMNode newDOMNode() {
+ return new DOMImport();
+ }
+
+ /**
+ * @see IDOMNode#setName(char[])
+ */
+ public void setName(String name) {
+ if (name == null) {
+ throw new IllegalArgumentException("illegal to set name to null");
+ }
+ becomeDetailed();
+ super.setName(name);
+ fOnDemand = name.endsWith(".*");
+ }
+
+ /**
+ * @see IDOMNode#toString()
+ */
+ public String toString() {
+ return "IMPORT: " + getName();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMInitializer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMInitializer.java
new file mode 100644
index 0000000000..d365b28ec8
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMInitializer.java
@@ -0,0 +1,270 @@
+package org.eclipse.jdt.internal.core.jdom;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.Flags;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.jdom.*;
+import org.eclipse.jdt.internal.core.JavaModelManager;
+import org.eclipse.jdt.internal.core.util.*;
+import org.w3c.dom.DOMImplementation;
+
+/**
+ * DOMInitializer provides an implementation of IDOMInitializer.
+ *
+ * @see IDOMInitializer
+ * @see DOMNode
+ */
+class DOMInitializer extends DOMMember implements IDOMInitializer {
+
+ /**
+ * The contents of the initializer's body when the
+ * body has been altered from the contents in the
+ * document, otherwise <code>null</code>.
+ */
+ protected String fBody;
+
+ /**
+ * The original inclusive source range of the
+ * body in the document.
+ */
+ protected int[] fBodyRange;
+
+ /**
+ * Constructs an empty initializer node.
+ */
+ DOMInitializer() {
+
+ }
+
+ /**
+ * Creates a new detailed INITIALIZER document fragment on the given range of the document.
+ *
+ * @param document - the document containing this node's original contents
+ * @param sourceRange - a two element array of integers describing the
+ * entire inclusive source range of this node within its document.
+ * Contents start on and include the character at the first position.
+ * Contents end on and include the character at the last position.
+ * An array of -1's indicates this node's contents do not exist
+ * in the document.
+ * @param commentRange - a two element array describing the comments that precede
+ * the member declaration. The first matches the start of this node's
+ * sourceRange, and the second is the new-line or first non-whitespace
+ * character following the last comment. If no comments are present,
+ * this array contains two -1's.
+ * @param flags - an integer representing the modifiers for this member. The
+ * integer can be analyzed with org.eclipse.jdt.core.Flags
+ * @param modifierRange - a two element array describing the location of
+ * modifiers for this member within its source range. The first integer
+ * is the first character of the first modifier for this member, and
+ * the second integer is the last whitespace character preceeding the
+ * next part of this member declaration. If there are no modifiers present
+ * in this node's source code (i.e. default protection), this array
+ * contains two -1's.
+ * @param bodyStartPosition - the position of the open brace of the body
+ * of this initialzer.
+ */
+ DOMInitializer(
+ char[] document,
+ int[] sourceRange,
+ int[] commentRange,
+ int flags,
+ int[] modifierRange,
+ int bodyStartPosition) {
+ super(
+ document,
+ sourceRange,
+ null,
+ new int[] { -1, -1 },
+ commentRange,
+ flags,
+ modifierRange);
+ fBodyRange = new int[2];
+ fBodyRange[0] = bodyStartPosition;
+ fBodyRange[1] = sourceRange[1];
+ setHasBody(true);
+ setMask(MASK_DETAILED_SOURCE_INDEXES, true);
+ }
+
+ /**
+ * Creates a new simple INITIALIZER document fragment on the given range of the document.
+ *
+ * @param document - the document containing this node's original contents
+ * @param sourceRange - a two element array of integers describing the
+ * entire inclusive source range of this node within its document.
+ * Contents start on and include the character at the first position.
+ * Contents end on and include the character at the last position.
+ * An array of -1's indicates this node's contents do not exist
+ * in the document.
+ * @param flags - an integer representing the modifiers for this member. The
+ * integer can be analyzed with org.eclipse.jdt.core.Flags
+ */
+ DOMInitializer(char[] document, int[] sourceRange, int flags) {
+ this(
+ document,
+ sourceRange,
+ new int[] { -1, -1 },
+ flags,
+ new int[] { -1, -1 },
+ -1);
+ setMask(MASK_DETAILED_SOURCE_INDEXES, false);
+
+ }
+
+ /**
+ * @see DOMMember#appendMemberBodyContents(CharArrayBuffer)
+ */
+ protected void appendMemberBodyContents(CharArrayBuffer buffer) {
+ if (hasBody()) {
+ buffer.append(getBody()).append(
+ fDocument,
+ fBodyRange[1] + 1,
+ fSourceRange[1] - fBodyRange[1]);
+ } else {
+ buffer.append("{}").append(JavaModelManager.LINE_SEPARATOR);
+ }
+ }
+
+ /**
+ * @see DOMMember#appendMemberDeclarationContents(CharArrayBuffer)
+ */
+ protected void appendMemberDeclarationContents(CharArrayBuffer buffer) {
+ }
+
+ /**
+ * @see DOMNode#appendSimpleContents(CharArrayBuffer)
+ */
+ protected void appendSimpleContents(CharArrayBuffer buffer) {
+ // append eveything before my name
+ buffer.append(fDocument, fSourceRange[0], fNameRange[0] - fSourceRange[0]);
+ // append my name
+ buffer.append(fName);
+ // append everything after my name
+ buffer.append(fDocument, fNameRange[1] + 1, fSourceRange[1] - fNameRange[1]);
+ }
+
+ /**
+ * @see IDOMInitializer#getBody()
+ */
+ public String getBody() {
+ becomeDetailed();
+ if (hasBody()) {
+ if (fBody != null) {
+ return fBody;
+ } else {
+ return CharArrayOps.substring(
+ fDocument,
+ fBodyRange[0],
+ fBodyRange[1] + 1 - fBodyRange[0]);
+ }
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * @see DOMNode#getDetailedNode()
+ */
+ protected DOMNode getDetailedNode() {
+ return (DOMNode) getFactory().createInitializer(getContents());
+ }
+
+ /**
+ * @see IDOMNode#getJavaElement
+ */
+ public IJavaElement getJavaElement(IJavaElement parent)
+ throws IllegalArgumentException {
+ if (parent.getElementType() == IJavaElement.TYPE) {
+ int count = 1;
+ IDOMNode previousNode = getPreviousNode();
+ while (previousNode != null) {
+ if (previousNode instanceof DOMInitializer) {
+ count++;
+ }
+ previousNode = previousNode.getPreviousNode();
+ }
+ return ((IType) parent).getInitializer(count);
+ } else {
+ throw new IllegalArgumentException("Illegal parent argument");
+ }
+ }
+
+ /**
+ * @see DOMMember#getMemberDeclarationStartPosition()
+ */
+ protected int getMemberDeclarationStartPosition() {
+ return fBodyRange[0];
+ }
+
+ /**
+ * @see IDOMNode#getNodeType()
+ */
+ public int getNodeType() {
+ return IDOMNode.INITIALIZER;
+ }
+
+ /**
+ * @see IDOMNode#isSigantureEqual(IDOMNode).
+ *
+ * <p>This method always answers false since an initializer
+ * does not have a signature.
+ */
+ public boolean isSignatureEqual(IDOMNode node) {
+ return false;
+ }
+
+ /**
+ * @see DOMNode
+ */
+ protected DOMNode newDOMNode() {
+ return new DOMInitializer();
+ }
+
+ /**
+ * Offsets all the source indexes in this node by the given amount.
+ */
+ protected void offset(int offset) {
+ super.offset(offset);
+ offsetRange(fBodyRange, offset);
+ }
+
+ /**
+ * @see IDOMInitializer#setBody(char[])
+ */
+ public void setBody(String body) {
+ becomeDetailed();
+ fBody = body;
+ setHasBody(body != null);
+ fragment();
+ }
+
+ /**
+ * @see IDOMInitializer#setName(String)
+ */
+ public void setName(String name) {
+ }
+
+ /**
+ * @see DOMNode#shareContents(DOMNode)
+ */
+ protected void shareContents(DOMNode node) {
+ super.shareContents(node);
+ DOMInitializer init = (DOMInitializer) node;
+ fBody = init.fBody;
+ fBodyRange = rangeCopy(init.fBodyRange);
+ }
+
+ /**
+ * @see IDOMNode#toString()
+ */
+ public String toString() {
+ return "INITIALIZER";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMMember.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMMember.java
new file mode 100644
index 0000000000..ff72589eb3
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMMember.java
@@ -0,0 +1,376 @@
+package org.eclipse.jdt.internal.core.jdom;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.internal.compiler.env.IConstants;
+import org.eclipse.jdt.core.Flags;
+import org.eclipse.jdt.core.jdom.*;
+import org.eclipse.jdt.internal.core.util.*;
+
+/**
+ * DOMMember provides an implementation of IDOMMember.
+ *
+ * @see IDOMMember
+ * @see DOMNode
+ */
+
+abstract class DOMMember extends DOMNode implements IDOMMember {
+
+ /**
+ * The modifier flags for this member that can be
+ * analyzed with org.eclipse.jdt.core.Flags
+ */
+ protected int fFlags = 0;
+
+ /**
+ * The member's comments when it has been altered from
+ * the contents in the document, otherwise <code>null</code>.
+ */
+ protected String fComment = null;
+
+ /**
+ * The original inclusive source range of the
+ * member's preceding comments in the document,
+ * or -1's if the member did not originally have a
+ * comment.
+ */
+ protected int[] fCommentRange;
+
+ /**
+ * The member's modifiers textual representation when
+ * the modifiers (flags) have been altered from
+ * their original contents, otherwise <code>null</code>.
+ */
+ protected char[] fModifiers = null;
+
+ /**
+ * The original inclusive source range of the
+ * member's modifiers in the document, or -1's if
+ * the member did not originally have modifiers in
+ * the source code (i.e. default protection).
+ */
+ protected int[] fModifierRange;
+
+ /**
+ * Constructs an empty member node.
+ */
+ DOMMember() {
+
+ }
+
+ /**
+ * Creates a new member document fragment on the given range of the document.
+ *
+ * @param document - the document containing this node's original contents
+ * @param sourceRange - a two element array of integers describing the
+ * entire inclusive source range of this node within its document.
+ * Contents start on and include the character at the first position.
+ * Contents end on and include the character at the last position.
+ * An array of -1's indicates this node's contents do not exist
+ * in the document.
+ * @param name - the identifier portion of the name of this node, or
+ * <code>null</code> if this node does not have a name
+ * @param nameRange - a two element array of integers describing the
+ * entire inclusive source range of this node's name within its document,
+ * including any array qualifiers that might immediately follow the name.
+ * @param commentRange - a two element array describing the comments that precede
+ * the member declaration. The first matches the start of this node's
+ * sourceRange, and the second is the new-line or first non-whitespace
+ * character following the last comment. If no comments are present,
+ * this array contains two -1's.
+ * @param flags - an integer representing the modifiers for this member. The
+ * integer can be analyzed with org.eclipse.jdt.core.Flags
+ * @param modifierRange - a two element array describing the location of
+ * modifiers for this member within its source range. The first integer
+ * is the first character of the first modifier for this member, and
+ * the second integer is the last whitespace character preceeding the
+ * next part of this member declaration. If there are no modifiers present
+ * in this node's source code (i.e. default protection), this array
+ * contains two -1's.
+ */
+ DOMMember(
+ char[] document,
+ int[] sourceRange,
+ String name,
+ int[] nameRange,
+ int[] commentRange,
+ int flags,
+ int[] modifierRange) {
+ super(document, sourceRange, name, nameRange);
+ fFlags = flags;
+ fComment = null;
+ fCommentRange = commentRange;
+ fModifierRange = modifierRange;
+ setHasComment(commentRange[0] >= 0);
+ }
+
+ /**
+ * Appends the contents of this node to the given CharArrayBuffer, using
+ * the original document and indicies as a form for the current attribute values
+ * of this node.
+ *
+ * <p>To facilitate the implementation of generating contents for members,
+ * the content of members is split into three sections - the header,
+ * declaration, and body sections. The header section includes any preceding
+ * comments and modifiers. The declaration section includes the portion of
+ * the member declaration that follows any modifiers and precedes the
+ * member body. The body section includes the member body and any trailing
+ * whitespace.
+ *
+ * @see DOMNode#appendFragmentedContents(CharArrayBuffer)
+ */
+ protected void appendFragmentedContents(CharArrayBuffer buffer) {
+ if (isDetailed()) {
+ appendMemberHeaderFragment(buffer);
+ appendMemberDeclarationContents(buffer);
+ appendMemberBodyContents(buffer);
+ } else {
+ appendSimpleContents(buffer);
+ }
+ }
+
+ /**
+ * Appends this member's body contents to the given CharArrayBuffer.
+ * Body contents include the member body and any trailing whitespace.
+ */
+ protected abstract void appendMemberBodyContents(CharArrayBuffer buffer);
+ /**
+ * Appends this member's declaration contents to the given CharArrayBuffer.
+ * The declaration contents includes the portion of this member that
+ * appears after any modifiers and precedes the body.
+ */
+ protected abstract void appendMemberDeclarationContents(CharArrayBuffer buffer);
+ /**
+ * Appends this member's header contents to the given CharArrayBuffer.
+ * Header contents include any preceding comments and modifiers.
+ */
+ protected void appendMemberHeaderFragment(CharArrayBuffer buffer) {
+
+ int spaceStart, spaceEnd;
+
+ // space before comment
+ if (hasComment()) {
+ spaceStart = fSourceRange[0];
+ spaceEnd = fCommentRange[0];
+ if (spaceEnd > 0) {
+ buffer.append(fDocument, spaceStart, spaceEnd - spaceStart);
+ }
+ }
+
+ String fragment = getComment();
+ if (fragment != null) {
+ buffer.append(fragment);
+ }
+
+ if (fCommentRange[1] >= 0) {
+ spaceStart = fCommentRange[1] + 1;
+ } else {
+ spaceStart = fSourceRange[0];
+ }
+ if (fModifierRange[0] >= 0) {
+ spaceEnd = fModifierRange[0] - 1;
+ } else {
+ spaceEnd = getMemberDeclarationStartPosition() - 1;
+ }
+
+ if (spaceEnd >= spaceStart) {
+ buffer.append(fDocument, spaceStart, spaceEnd + 1 - spaceStart);
+ }
+ buffer.append(getModifiersText());
+
+ }
+
+ /**
+ * Appends the contents of this node to the given CharArrayBuffer, using
+ * the original document and indicies as a form for the current attribute values
+ * of this node. This method is called when this node is know not to have
+ * detailed source indexes.
+ */
+ protected abstract void appendSimpleContents(CharArrayBuffer buffer);
+ /**
+ * Returns a copy of the given array with the new element appended
+ * to the end of the array.
+ */
+ protected String[] appendString(String[] list, String element) {
+ String[] copy = new String[list.length + 1];
+ System.arraycopy(list, 0, copy, 0, list.length);
+ copy[list.length] = element;
+ return copy;
+ }
+
+ /**
+ * Returns a <code>String</code> describing the modifiers for this member,
+ * ending with whitespace (if not empty). This value serves as a replacement
+ * value for the member's modifier range when the modifiers have been altered
+ * from their original contents.
+ */
+ protected char[] generateFlags() {
+ char[] flags = Flags.toString(getFlags()).toCharArray();
+ if (flags.length == 0) {
+ return flags;
+ } else {
+ return CharArrayOps.concat(flags, new char[] { ' ' });
+ }
+ }
+
+ /**
+ * @see IDOMMember#getComment()
+ */
+ public String getComment() {
+ becomeDetailed();
+ if (hasComment()) {
+ if (fComment != null) {
+ return fComment;
+ } else {
+ return CharArrayOps.substring(
+ fDocument,
+ fCommentRange[0],
+ fCommentRange[1] + 1 - fCommentRange[0]);
+ }
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * @see IDOMMember#getFlags()
+ */
+ public int getFlags() {
+ return fFlags;
+ }
+
+ /**
+ * Returns the location of the first character in the member's declaration
+ * section.
+ *
+ * @see DOMMember#getMemberDeclarationContents()
+ * @see DOMMember#getFragmentedContents()
+ */
+ protected abstract int getMemberDeclarationStartPosition();
+ /**
+ * Returns the String to be used for this member's flags when
+ * generating contents - either the original contents in the document
+ * or the replacement value.
+ */
+ protected char[] getModifiersText() {
+ if (fModifiers == null) {
+ if (fModifierRange[0] < 0) {
+ return null;
+ } else {
+ return CharArrayOps.subarray(
+ fDocument,
+ fModifierRange[0],
+ fModifierRange[1] + 1 - fModifierRange[0]);
+ }
+ } else {
+ return fModifiers;
+ }
+ }
+
+ /**
+ * Returns true if this member currently has a body.
+ */
+ protected boolean hasBody() {
+ return getMask(MASK_HAS_BODY);
+ }
+
+ /**
+ * Returns true if this member currently has a comment.
+ */
+ protected boolean hasComment() {
+ return getMask(MASK_HAS_COMMENT);
+ }
+
+ /**
+ * Offsets all the source indexes in this node by the given amount.
+ */
+ protected void offset(int offset) {
+ super.offset(offset);
+ offsetRange(fCommentRange, offset);
+ offsetRange(fModifierRange, offset);
+ }
+
+ /**
+ * @see IDOMMember#setComment(String)
+ */
+ public void setComment(String comment) {
+ becomeDetailed();
+ fComment = comment;
+ fragment();
+ setHasComment(comment != null);
+ /* see 1FVIJAH */
+ if (comment != null) {
+ String commentString = new String(comment);
+ if (commentString.indexOf("@deprecated") >= 0) {
+ fFlags = fFlags | IConstants.AccDeprecated;
+ return;
+ }
+
+ }
+ fFlags = fFlags & (~IConstants.AccDeprecated);
+
+ }
+
+ /**
+ * @see IDOMMember#setFlags(int)
+ */
+ public void setFlags(int flags) {
+ becomeDetailed();
+ if (Flags.isDeprecated(fFlags)) {
+ fFlags = flags | IConstants.AccDeprecated;
+ } else {
+ fFlags = flags & (~IConstants.AccDeprecated);
+ }
+ fragment();
+ fModifiers = generateFlags();
+ }
+
+ /**
+ * Sets the state of this member declaration as having
+ * a body.
+ */
+ protected void setHasBody(boolean hasBody) {
+ setMask(MASK_HAS_BODY, hasBody);
+ }
+
+ /**
+ * Sets the state of this member declaration as having
+ * a preceding comment.
+ */
+ protected void setHasComment(boolean hasComment) {
+ setMask(MASK_HAS_COMMENT, hasComment);
+ }
+
+ /**
+ * Sets the original position of the first character of this node's contents
+ * in its document. This method is only used during DOM creation while
+ * normalizing the source range of each node.
+ *
+ * Synchronize the start of the comment position with the start of the
+ * node.
+ */
+ protected void setStartPosition(int start) {
+ if (fCommentRange[0] >= 0) {
+ fCommentRange[0] = start;
+ }
+ super.setStartPosition(start);
+ }
+
+ /**
+ * @see DOMNode#shareContents(DOMNode)
+ */
+ protected void shareContents(DOMNode node) {
+ super.shareContents(node);
+ DOMMember member = (DOMMember) node;
+ fComment = member.fComment;
+ fCommentRange = rangeCopy(member.fCommentRange);
+ fFlags = member.fFlags;
+ fModifiers = member.fModifiers;
+ fModifierRange = rangeCopy(member.fModifierRange);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMMethod.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMMethod.java
new file mode 100644
index 0000000000..d7350a1ca6
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMMethod.java
@@ -0,0 +1,828 @@
+package org.eclipse.jdt.internal.core.jdom;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.Flags;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.Signature;
+import org.eclipse.jdt.core.jdom.*;
+import org.eclipse.jdt.internal.core.JavaModelManager;
+import org.eclipse.jdt.internal.core.util.*;
+
+/**
+ * DOMMethod provides an implementation of IDOMMethod.
+ *
+ * @see IDOMMethod
+ * @see DOMNode
+ */
+
+class DOMMethod extends DOMMember implements IDOMMethod {
+
+ /**
+ * Contains the return type of the method when the
+ * return type has been altered from the contents
+ * in the document, otherwise <code>null</code>.
+ */
+ protected String fReturnType;
+
+ /**
+ * The original inclusive source range of the
+ * method's return type in the document, or -1's
+ * if no return type is present in the document.
+ * If the return type of this method is qualified with
+ * '[]' following the parameter list, this array has
+ * four entries. In this case, the last two entries
+ * of the array are the inclusive source range of
+ * the array qualifiers.
+ */
+ protected int[] fReturnTypeRange;
+
+ /**
+ * Contains the textual representation of the method's
+ * parameter list, including open and closing parentheses
+ * when the parameters had been altered from the contents
+ * in the document, otherwise <code>null</code>.
+ */
+ protected char[] fParameterList;
+
+ /**
+ * The original inclusive source range of the
+ * method's parameter list in the document.
+ */
+ protected int[] fParameterRange;
+
+ /**
+ * Contains the textual representation of the method's
+ * exception list when the exceptions had been altered
+ * from the contents in the document, otherwise
+ * <code>null</code>. The exception list is a comment
+ * delimited list of exceptions, not including the "throws"
+ * keyword.
+ */
+ protected char[] fExceptionList;
+
+ /**
+ * The original inclusive source range of the
+ * method's exception list in the document.
+ */
+ protected int[] fExceptionRange;
+
+ /**
+ * Contains the method's body when the body has
+ * been altered from the contents in the document,
+ * otherwise <code>null</code>. The body includes everything
+ * between and including the enclosing braces, and trailing
+ * whitespace.
+ */
+ protected String fBody;
+
+ /**
+ * The original inclusive source range of the
+ * method's body.
+ */
+ protected int[] fBodyRange;
+
+ /**
+ * Names of parameters in the method parameter list,
+ * or <code>null</code> if the method has no parameters.
+ */
+ protected String[] fParameterNames;
+
+ /**
+ * Types of parameters in the method parameter list,
+ * or <code>null</code> if the method has no parameters.
+ */
+ protected String[] fParameterTypes;
+
+ /**
+ * The exceptions the method throws, or <code>null</code>
+ * if the method throws no exceptions.
+ */
+ protected String[] fExceptions;
+
+ /**
+ * Constructs an empty method node.
+ */
+ DOMMethod() {
+
+ }
+
+ /**
+ * Creates a new detailed METHOD document fragment on the given range of the document.
+ *
+ * @param document - the document containing this node's original contents
+ * @param sourceRange - a two element array of integers describing the
+ * entire inclusive source range of this node within its document.
+ * Contents start on and include the character at the first position.
+ * Contents end on and include the character at the last position.
+ * An array of -1's indicates this node's contents do not exist
+ * in the document.
+ * @param name - the identifier portion of the name of this node, or
+ * <code>null</code> if this node does not have a name
+ * @param nameRange - a two element array of integers describing the
+ * entire inclusive source range of this node's name within its document,
+ * including any array qualifiers that might immediately follow the name
+ * or -1's if this node does not have a name.
+ * @param commentRange - a two element array describing the comments that precede
+ * the member declaration. The first matches the start of this node's
+ * sourceRange, and the second is the new-line or first non-whitespace
+ * character following the last comment. If no comments are present,
+ * this array contains two -1's.
+ * @param flags - an integer representing the modifiers for this member. The
+ * integer can be analyzed with org.eclipse.jdt.core.Flags
+ * @param modifierRange - a two element array describing the location of
+ * modifiers for this member within its source range. The first integer
+ * is the first character of the first modifier for this member, and
+ * the second integer is the last whitespace character preceeding the
+ * next part of this member declaration. If there are no modifiers present
+ * in this node's source code (i.e. default protection), this array
+ * contains two -1's.
+ * @param isConstructor - true if the method is a contructor, otherwise false
+ * @param returnType - the normalized return type of this method
+ * @param returnTypeRange - a two element array describing the location of the
+ * return type within the method's source range. The first integer is is
+ * the position of the first character in the return type, and the second
+ * integer is the position of the last character in the return type.
+ * For constructors, the contents of this array are -1's.
+ * If the return type of this method is qualified with '[]' following the
+ * parameter list, this array has four entries. In this case, the last
+ * two entries of the array are the inclusive source range of the array
+ * qualifiers.
+ * @param parameterTypes - an array of parameter types in the method declaration
+ * or <code>null</code> if the method has no parameters
+ * @param parameterNames - an array of parameter names in the method declaration
+ * or <code>null</code> if the method has no parameters
+ * @param parameterRange - a two element array describing the location of the
+ * parameter list in the method. The first integer is the location of the
+ * open parenthesis and the second integer is the location of the closing
+ * parenthesis.
+ * @param exceptions - an array of the names of exceptions thrown by this method
+ * or <code>null</code> if the method throws no exceptions
+ * @param exceptionRange - a two element array describing the location of the
+ * exception list in the method declaration. The first integer is the position
+ * of the first character in the first exception the method throws, and the
+ * second integer is the position of the last character of the last exception
+ * this method throws.
+ * @param bodyRange - a two element array describing the location of the method's body.
+ * The first integer is the first character following the method's
+ * parameter list, or exception list (if present). The second integer is the location
+ * of the last character in the method's source range.
+ */
+ DOMMethod(
+ char[] document,
+ int[] sourceRange,
+ String name,
+ int[] nameRange,
+ int[] commentRange,
+ int flags,
+ int[] modifierRange,
+ boolean isConstructor,
+ String returnType,
+ int[] returnTypeRange,
+ String[] parameterTypes,
+ String[] parameterNames,
+ int[] parameterRange,
+ String[] exceptions,
+ int[] exceptionRange,
+ int[] bodyRange) {
+ super(
+ document,
+ sourceRange,
+ name,
+ nameRange,
+ commentRange,
+ flags,
+ modifierRange);
+
+ setMask(MASK_IS_CONSTRUCTOR, isConstructor);
+ fReturnType = returnType;
+ fReturnTypeRange = returnTypeRange;
+ fParameterTypes = parameterTypes;
+ fParameterNames = parameterNames;
+ fParameterRange = parameterRange;
+ fExceptionRange = exceptionRange;
+ fExceptions = exceptions;
+ setHasBody(true);
+ fBodyRange = bodyRange;
+ setMask(MASK_DETAILED_SOURCE_INDEXES, true);
+
+ }
+
+ /**
+ * Creates a new simple METHOD document fragment on the given range of the document.
+ *
+ * @param document - the document containing this node's original contents
+ * @param sourceRange - a two element array of integers describing the
+ * entire inclusive source range of this node within its document.
+ * Contents start on and include the character at the first position.
+ * Contents end on and include the character at the last position.
+ * An array of -1's indicates this node's contents do not exist
+ * in the document.
+ * @param name - the identifier portion of the name of this node, or
+ * <code>null</code> if this node does not have a name
+ * @param nameRange - a two element array of integers describing the
+ * entire inclusive source range of this node's name within its document,
+ * including any array qualifiers that might immediately follow the name
+ * or -1's if this node does not have a name.
+ * @param flags - an integer representing the modifiers for this member. The
+ * integer can be analyzed with org.eclipse.jdt.core.Flags
+ * @param isConstructor - true if the method is a contructor, otherwise false
+ * @param returnType - the normalized return type of this method
+ * @param parameterTypes - an array of parameter types in the method declaration
+ * or <code>null</code> if the method has no parameters
+ * @param parameterNames - an array of parameter names in the method declaration
+ * or <code>null</code> if the method has no parameters
+ * @param exceptions - an array of the names of exceptions thrown by this method
+ * or <code>null</code> if the method throws no exceptions
+ */
+ DOMMethod(
+ char[] document,
+ int[] sourceRange,
+ String name,
+ int[] nameRange,
+ int flags,
+ boolean isConstructor,
+ String returnType,
+ String[] parameterTypes,
+ String[] parameterNames,
+ String[] exceptions) {
+ this(
+ document,
+ sourceRange,
+ name,
+ nameRange,
+ new int[] { -1, -1 },
+ flags,
+ new int[] { -1, -1 },
+ isConstructor,
+ returnType,
+ new int[] { -1, -1 },
+ parameterTypes,
+ parameterNames,
+ new int[] { -1, -1 },
+ exceptions,
+ new int[] { -1, -1 },
+ new int[] { -1, -1 });
+ setMask(MASK_DETAILED_SOURCE_INDEXES, false);
+ }
+
+ /**
+ * @see IDOMMethod#addException(String)
+ */
+ public void addException(String name) throws IllegalArgumentException {
+ if (name == null) {
+ throw new IllegalArgumentException("Cannot add null exception");
+ }
+ if (fExceptions == null) {
+ fExceptions = new String[1];
+ fExceptions[0] = name;
+ } else {
+ fExceptions = appendString(fExceptions, name);
+ }
+ setExceptions(fExceptions);
+ }
+
+ /**
+ * @see IDOMMethod#addParameter(String, String)
+ */
+ public void addParameter(String type, String name)
+ throws IllegalArgumentException {
+ if (type == null) {
+ throw new IllegalArgumentException("Cannot add parameter with null type");
+ }
+ if (name == null) {
+ throw new IllegalArgumentException("Cannot add parameter with null name");
+ }
+ if (fParameterNames == null) {
+ fParameterNames = new String[1];
+ fParameterNames[0] = name;
+ } else {
+ fParameterNames = appendString(fParameterNames, name);
+ }
+ if (fParameterTypes == null) {
+ fParameterTypes = new String[1];
+ fParameterTypes[0] = type;
+ } else {
+ fParameterTypes = appendString(fParameterTypes, type);
+ }
+ setParameters(fParameterTypes, fParameterNames);
+ }
+
+ /**
+ * @see DOMMember#appendMemberBodyContents(CharArrayBuffer)
+ */
+ protected void appendMemberBodyContents(CharArrayBuffer buffer) {
+ if (fBody != null) {
+ buffer.append(fBody);
+ } else {
+ buffer.append(fDocument, fBodyRange[0], fBodyRange[1] + 1 - fBodyRange[0]);
+ }
+ }
+
+ /**
+ * @see DOMMember#appendMemberDeclarationContents(CharArrayBuffer)
+ */
+ protected void appendMemberDeclarationContents(CharArrayBuffer buffer) {
+
+ if (isConstructor()) {
+ buffer.append(getConstructorName()).append(
+ fDocument,
+ fNameRange[1] + 1,
+ fParameterRange[0] - fNameRange[1] - 1);
+ } else {
+ buffer.append(getReturnTypeContents());
+ if (fReturnTypeRange[0] >= 0) {
+ buffer.append(
+ fDocument,
+ fReturnTypeRange[1] + 1,
+ fNameRange[0] - fReturnTypeRange[1] - 1);
+ } else {
+ buffer.append(" ");
+ }
+ buffer.append(getNameContents()).append(
+ fDocument,
+ fNameRange[1] + 1,
+ fParameterRange[0] - fNameRange[1] - 1);
+ }
+ if (fParameterList != null) {
+ buffer.append(fParameterList);
+ } else {
+ buffer.append(
+ fDocument,
+ fParameterRange[0],
+ fParameterRange[1] + 1 - fParameterRange[0]);
+ }
+ int start;
+ if (hasTrailingArrayQualifier() && isReturnTypeAltered()) {
+ start = fReturnTypeRange[3] + 1;
+ } else {
+ start = fParameterRange[1] + 1;
+ }
+ if (fExceptions != null) {
+ // add 'throws' keyword
+ if (fExceptionRange[0] >= 0) {
+ buffer.append(fDocument, start, fExceptionRange[0] - start);
+ } else {
+ buffer.append(" throws ");
+ }
+ // add exception list
+ if (fExceptionList != null) {
+ buffer.append(fExceptionList);
+ // add space before body
+ if (fExceptionRange[0] >= 0) {
+ buffer.append(
+ fDocument,
+ fExceptionRange[1] + 1,
+ fBodyRange[0] - fExceptionRange[1] - 1);
+ } else {
+ buffer.append(
+ fDocument,
+ fParameterRange[1] + 1,
+ fBodyRange[0] - fParameterRange[1] - 1);
+ }
+ } else {
+ // add list and space before body
+ buffer.append(
+ fDocument,
+ fExceptionRange[0],
+ fBodyRange[0] - fExceptionRange[0]);
+ }
+ } else {
+ // add space before body
+ if (fExceptionRange[0] >= 0) {
+ buffer.append(
+ fDocument,
+ fExceptionRange[1] + 1,
+ fBodyRange[0] - fExceptionRange[1] - 1);
+ } else {
+ buffer.append(fDocument, start, fBodyRange[0] - start);
+ }
+ }
+
+ }
+
+ /**
+ * @see DOMNode#appendSimpleContents(CharArrayBuffer)
+ */
+ protected void appendSimpleContents(CharArrayBuffer buffer) {
+ // append eveything before my name
+ buffer.append(fDocument, fSourceRange[0], fNameRange[0] - fSourceRange[0]);
+ // append my name
+ if (isConstructor()) {
+ buffer.append(getConstructorName());
+ } else {
+ buffer.append(fName);
+ }
+ // append everything after my name
+ buffer.append(fDocument, fNameRange[1] + 1, fSourceRange[1] - fNameRange[1]);
+ }
+
+ /**
+ * @see IDOMMethod#getBody()
+ */
+ public String getBody() {
+ becomeDetailed();
+ if (hasBody()) {
+ if (fBody != null) {
+ return fBody;
+ } else {
+ return CharArrayOps.substring(
+ fDocument,
+ fBodyRange[0],
+ fBodyRange[1] + 1 - fBodyRange[0]);
+ }
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the simple name of the enclsoing type for this constructor.
+ * If the constuctor is not currently enclosed in a type, the original
+ * name of the constructor as found in the documnent is returned.
+ */
+ protected String getConstructorName() {
+
+ if (isConstructor()) {
+ if (getParent() != null) {
+ return getParent().getName();
+ } else {
+ // If there is no parent use the original name
+ return new String(getNameContents());
+ }
+ } else {
+ return null;
+ }
+
+ }
+
+ /**
+ * @see DOMNode#getDetailedNode()
+ */
+ protected DOMNode getDetailedNode() {
+ return (DOMNode) getFactory().createMethod(getContents());
+ }
+
+ /**
+ * @see IDOMMethod#getExceptions()
+ */
+ public String[] getExceptions() {
+ return fExceptions;
+ }
+
+ /**
+ * @see IDOMNode#getJavaElement
+ */
+ public IJavaElement getJavaElement(IJavaElement parent)
+ throws IllegalArgumentException {
+ if (parent.getElementType() == IJavaElement.TYPE) {
+ // translate parameter types to signatures
+ String[] sigs = null;
+ if (fParameterTypes != null) {
+ sigs = new String[fParameterTypes.length];
+ int i;
+ for (i = 0; i < fParameterTypes.length; i++) {
+ sigs[i] =
+ Signature.createTypeSignature(fParameterTypes[i].toCharArray(), false);
+ }
+ }
+ String name = null;
+ if (isConstructor()) {
+ name = getConstructorName();
+ } else {
+ name = getName();
+ }
+ return ((IType) parent).getMethod(name, sigs);
+ } else {
+ throw new IllegalArgumentException("Illegal parent argument");
+ }
+ }
+
+ /**
+ * @see DOMMember#getMemberDeclarationStartPosition()
+ */
+ protected int getMemberDeclarationStartPosition() {
+ if (fReturnTypeRange[0] >= 0) {
+ return fReturnTypeRange[0];
+ } else {
+ return fNameRange[0];
+ }
+ }
+
+ /**
+ * @see IDOMNode#getName()
+ */
+ public String getName() {
+ if (isConstructor()) {
+ return null;
+ } else {
+ return super.getName();
+ }
+ }
+
+ /**
+ * @see IDOMNode#getNodeType()
+ */
+ public int getNodeType() {
+ return IDOMNode.METHOD;
+ }
+
+ /**
+ * @see IDOMMethod#getParameterNames()
+ */
+ public String[] getParameterNames() {
+ return fParameterNames;
+ }
+
+ /**
+ * @see IDOMMethod#getParameterTypes()
+ */
+ public String[] getParameterTypes() {
+ return fParameterTypes;
+ }
+
+ /**
+ * @see IDOMMethod#getReturnType()
+ */
+ public String getReturnType() {
+ if (isConstructor()) {
+ return null;
+ } else {
+ return fReturnType;
+ }
+ }
+
+ /**
+ * Returns the source code to be used for this method's return type
+ */
+ protected char[] getReturnTypeContents() {
+ if (isConstructor()) {
+ return null;
+ } else {
+ if (isReturnTypeAltered()) {
+ return fReturnType.toCharArray();
+ } else {
+ return CharArrayOps.subarray(
+ fDocument,
+ fReturnTypeRange[0],
+ fReturnTypeRange[1] + 1 - fReturnTypeRange[0]);
+ }
+
+ }
+ }
+
+ /**
+ * Returns true if this method's return type has
+ * array qualifiers ('[]') following the parameter list.
+ */
+ protected boolean hasTrailingArrayQualifier() {
+ return fReturnTypeRange.length > 2;
+ }
+
+ /**
+ * @see IDOMMethod#isConstructor()
+ */
+ public boolean isConstructor() {
+ return getMask(MASK_IS_CONSTRUCTOR);
+ }
+
+ /**
+ * Returns true if this method's return type has been altered
+ * from the original document contents.
+ */
+ protected boolean isReturnTypeAltered() {
+ return getMask(MASK_RETURN_TYPE_ALTERED);
+ }
+
+ /**
+ * @see IDOMNode#isSigantureEqual(IDOMNode).
+ *
+ * <p>Two methods have equal signatures if there names are the same
+ * and their parameter types are the same.
+ */
+ public boolean isSignatureEqual(IDOMNode node) {
+ boolean ok = node.getNodeType() == getNodeType();
+ if (ok) {
+ IDOMMethod method = (IDOMMethod) node;
+ ok =
+ (isConstructor() && method.isConstructor())
+ || (!isConstructor() && !method.isConstructor());
+ if (ok && !isConstructor()) {
+ ok = getName().equals(method.getName());
+ }
+ if (!ok) {
+ return false;
+ }
+
+ String[] types = method.getParameterTypes();
+ if (fParameterTypes == null || fParameterTypes.length == 0) {
+ // this method has no parameters
+ if (types == null || types.length == 0) {
+ // the other method has no parameters either
+ return true;
+ }
+ } else {
+ // this method has parameters
+ if (types == null || types.length == 0) {
+ // the other method has no parameters
+ return false;
+ }
+ if (fParameterTypes.length != types.length) {
+ // the methods have a different number of parameters
+ return false;
+ }
+ int i;
+ for (i = 0; i < types.length; i++) {
+ if (!fParameterTypes[i].equals(types[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+
+ }
+
+ /**
+ * @see DOMNode
+ */
+ protected DOMNode newDOMNode() {
+ return new DOMMethod();
+ }
+
+ /**
+ * Offsets all the source indexes in this node by the given amount.
+ */
+ protected void offset(int offset) {
+ super.offset(offset);
+ offsetRange(fBodyRange, offset);
+ offsetRange(fExceptionRange, offset);
+ offsetRange(fParameterRange, offset);
+ offsetRange(fReturnTypeRange, offset);
+ }
+
+ /**
+ * @see IDOMMethod#setBody
+ */
+ public void setBody(String body) {
+ becomeDetailed();
+ fragment();
+ fBody = body;
+ setHasBody(body != null);
+ if (!hasBody()) {
+ fBody = ";" + JavaModelManager.LINE_SEPARATOR;
+ }
+ }
+
+ /**
+ * Sets the end of the body range
+ */
+ void setBodyRangeEnd(int end) {
+ fBodyRange[1] = end;
+ }
+
+ /**
+ * @see IDOMMethod#setConstructor(boolean)
+ */
+ public void setConstructor(boolean b) {
+ becomeDetailed();
+ setMask(MASK_IS_CONSTRUCTOR, b);
+ fragment();
+ }
+
+ /**
+ * @see IDOMMethod#setExceptions(char[][])
+ */
+ public void setExceptions(String[] names) {
+ becomeDetailed();
+ if (names == null || names.length == 0) {
+ fExceptions = null;
+ } else {
+ fExceptions = names;
+ CharArrayBuffer buffer = new CharArrayBuffer();
+ char[] comma = new char[] { ',', ' ' };
+ for (int i = 0, length = names.length; i < length; i++) {
+ if (i > 0)
+ buffer.append(comma);
+ buffer.append(names[i]);
+ }
+ fExceptionList = buffer.getContents();
+ }
+ fragment();
+ }
+
+ /**
+ * @see IDOMMethod#setName
+ */
+ public void setName(String name) {
+ if (name == null) {
+ throw new IllegalArgumentException("illegal to set method name to null");
+ } else {
+ super.setName(name);
+ }
+ }
+
+ /**
+ * @see IDOMMethod#setParameters(char[][], char[][])
+ */
+ public void setParameters(String[] types, String[] names)
+ throws IllegalArgumentException {
+ becomeDetailed();
+ if (types == null || names == null) {
+ if (types == null && names == null) {
+ fParameterTypes = null;
+ fParameterNames = null;
+ fParameterList = new char[] { '(', ')' };
+ } else {
+ throw new IllegalArgumentException("types and names must have identical length");
+ }
+ } else
+ if (names.length != types.length) {
+ throw new IllegalArgumentException("types and names must have identical length");
+ } else
+ if (names.length == 0) {
+ setParameters(null, null);
+ } else {
+ fParameterNames = names;
+ fParameterTypes = types;
+ CharArrayBuffer parametersBuffer = new CharArrayBuffer();
+ parametersBuffer.append("(");
+ char[] comma = new char[] { ',', ' ' };
+ for (int i = 0; i < names.length; i++) {
+ if (i > 0) {
+ parametersBuffer.append(comma);
+ }
+ parametersBuffer.append(types[i]).append(" ").append(names[i]);
+ }
+ parametersBuffer.append(")");
+ fParameterList = parametersBuffer.getContents();
+ }
+ fragment();
+ }
+
+ /**
+ * @see IDOMMethod#setReturnType(char[])
+ */
+ public void setReturnType(String name) throws IllegalArgumentException {
+ if (name == null) {
+ throw new IllegalArgumentException("illegal return type of null");
+ }
+ becomeDetailed();
+ fragment();
+ setReturnTypeAltered(true);
+ fReturnType = name;
+ }
+
+ /**
+ * Sets the state of this method declaration as having
+ * the return type altered from the original document.
+ */
+ protected void setReturnTypeAltered(boolean typeAltered) {
+ setMask(MASK_RETURN_TYPE_ALTERED, typeAltered);
+ }
+
+ /**
+ */
+ protected void setSourceRangeEnd(int end) {
+ super.setSourceRangeEnd(end);
+ fBodyRange[1] = end;
+ }
+
+ /**
+ * @see DOMNode#shareContents(DOMNode)
+ */
+ protected void shareContents(DOMNode node) {
+ super.shareContents(node);
+ DOMMethod method = (DOMMethod) node;
+ fBody = method.fBody;
+ fBodyRange = rangeCopy(method.fBodyRange);
+ fExceptionList = method.fExceptionList;
+ fExceptionRange = rangeCopy(method.fExceptionRange);
+ fExceptions = method.fExceptions;
+ fParameterList = method.fParameterList;
+ fParameterNames = method.fParameterNames;
+ fParameterRange = rangeCopy(method.fParameterRange);
+ fParameterTypes = method.fParameterTypes;
+ fReturnType = method.fReturnType;
+ fReturnTypeRange = rangeCopy(method.fReturnTypeRange);
+ }
+
+ /**
+ * @see IDOMNode#toString()
+ */
+ public String toString() {
+ if (isConstructor()) {
+ return "CONSTRUCTOR";
+ } else {
+ return "METHOD: " + getName();
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMNode.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMNode.java
new file mode 100644
index 0000000000..d60e83c20f
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMNode.java
@@ -0,0 +1,1008 @@
+package org.eclipse.jdt.internal.core.jdom;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.core.jdom.*;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.internal.core.util.*;
+
+import java.util.*;
+
+/**
+ * DOMNode provides an implementation for <code>IDOMNode</code>.
+ *
+ * <p>A node represents a document fragment. When a node is created, its
+ * contents are located in a contiguous range of a shared document. A shared
+ * document is a char array, and is shared in the sense that the contents of other
+ * document fragments may also be contained in the array.
+ *
+ * <p>A node maintains indicies of relevant portions of its contents
+ * in the shared document. Thus the original document and indicies create a
+ * form from which to generate the contents of the document fragment. As attributes
+ * of a node are changed, the node attempts to maintain the original formatting
+ * by only replacing relevant portions of the shared document with the value
+ * of new attributes (i.e. filling in the form with replacement values).
+ *
+ * <p>When a node is first created, it is considered unfragmented. When any
+ * attribute of the node is altered, the node is then considered fragmented
+ * from that point on. A node is also considered fragmented if any of its
+ * descendants are fragmented. When a node is unfragmented, the contents of the
+ * node can be efficiently generated from the original shared document. When
+ * a node is fragmented, the contents of the node must be created using the
+ * original document and indicies as a form, filling in replacement values
+ * as required.
+ *
+ * <p>Generally, a node's contents consists of complete lines in a shared document.
+ * The contents of the node are normalized on creation to include any whitespace
+ * preceding the node on the line where the node begins, and to include and trailing
+ * whitespace up to the line where the next node begins. Any trailing // comments
+ * that begin on the line where the current node ends, are considered part of that
+ * node.
+ *
+ * @see IDOMNode
+ */
+public abstract class DOMNode implements IDOMNode {
+
+ /**
+ * The first child of this node - <code>null</code>
+ * when this node has no children. (Children of a node
+ * are implemented as a doubly linked list).
+ */
+ protected DOMNode fFirstChild = null;
+
+ /**
+ * The last child of this node - <code>null</code>
+ * when this node has no children. Used for efficient
+ * access to the last child when adding new children
+ * at the end of the linked list of children.
+ */
+ protected DOMNode fLastChild = null;
+
+ /**
+ * The sibling node following this node - <code>null</code>
+ * for the last node in the sibling list.
+ */
+ protected DOMNode fNextNode = null;
+
+ /**
+ * The parent of this node. A <code>null</code>
+ * parent indicates that this node is a root
+ * node of a document fragment.
+ */
+ protected DOMNode fParent = null;
+
+ /**
+ * The sibling node preceding this node - <code>null</code>
+ * for the first node in the sibling list.
+ */
+ protected DOMNode fPreviousNode = null;
+
+ /**
+ * True when this node has attributes that have
+ * been altered from their original state in the
+ * shared document, or when the attributes of a
+ * descendant have been altered. False when the
+ * contents of this node and all descendants are
+ * consistent with the content of the shared
+ * document.
+ */
+ protected boolean fIsFragmented = false;
+
+ /**
+ * The name of this node. For efficiency, the
+ * name of a node is duplicated in this variable
+ * on creation, rather than always having to fetch
+ * the name from the shared document.
+ */
+ protected String fName = null;
+
+ /**
+ * The original inclusive indicies of this node's name in
+ * the shared document. Values of -1 indiciate the name
+ * does not exist in the document.
+ */
+ protected int[] fNameRange;
+
+ /**
+ * The shared document that the contents for this node
+ * are contained in. Attribute indicies are positions
+ * in this character array.
+ */
+ protected char[] fDocument = null;
+
+ /**
+ * The original entire inclusive range of this node's contents
+ * within its document. Values of -1 indicate the contents
+ * of this node do not exist in the document.
+ */
+ protected int[] fSourceRange;
+
+ /**
+ * The current state of bit masks defined by this node.
+ * Initially all bit flags are turned off. All bit masks
+ * are defined by this class to avoid overlap, although
+ * bit masks are node type specific.
+ *
+ * @see #setMask
+ * @see #getMask
+ */
+ protected int fStateMask = 0;
+
+ /**
+ * A bit mask indicating this field has an initializer
+ * expression
+ */
+ protected static final int MASK_FIELD_HAS_INITIALIZER = 0x00000001;
+
+ /**
+ * A bit mask indicating this field is a secondary variable
+ * declarator for a previous field declaration.
+ */
+ protected static final int MASK_FIELD_IS_VARIABLE_DECLARATOR = 0x00000002;
+
+ /**
+ * A bit mask indicating this field's type has been
+ * altered from its original contents in the document.
+ */
+ protected static final int MASK_FIELD_TYPE_ALTERED = 0x00000004;
+
+ /**
+ * A bit mask indicating this node's name has been
+ * altered from its original contents in the document.
+ */
+ protected static final int MASK_NAME_ALTERED = 0x00000008;
+
+ /**
+ * A bit mask indicating this node currently has a
+ * body.
+ */
+ protected static final int MASK_HAS_BODY = 0x00000010;
+
+ /**
+ * A bit mask indicating this node currently has a
+ * preceding comment.
+ */
+ protected static final int MASK_HAS_COMMENT = 0x00000020;
+
+ /**
+ * A bit mask indicating this method is a constructor.
+ */
+ protected static final int MASK_IS_CONSTRUCTOR = 0x00000040;
+
+ /**
+ * A bit mask indicating this type is a class.
+ */
+ protected static final int MASK_TYPE_IS_CLASS = 0x00000080;
+
+ /**
+ * A bit mask indicating this type has a superclass
+ * (requires or has an 'extends' clause).
+ */
+ protected static final int MASK_TYPE_HAS_SUPERCLASS = 0x00000100;
+
+ /**
+ * A bit mask indicating this type implements
+ * or extends some interfaces
+ */
+ protected static final int MASK_TYPE_HAS_INTERFACES = 0x00000200;
+
+ /**
+ * A bit mask indicating this return type of this method has
+ * been altered from the original contents.
+ */
+ protected static final int MASK_RETURN_TYPE_ALTERED = 0x00000400;
+
+ /**
+ * A bit mask indicating this node has detailed source indexes
+ */
+ protected static final int MASK_DETAILED_SOURCE_INDEXES = 0x00000800;
+
+ /**
+ * Creates a new empty document fragment.
+ */
+ DOMNode() {
+ fName = null;
+ fDocument = null;
+ fSourceRange = new int[] { -1, -1 };
+ fNameRange = new int[] { -1, -1 };
+ fragment();
+ }
+
+ /**
+ * Creates a new document fragment on the given range of the document.
+ *
+ * @param document - the document containing this node's original contents
+ * @param sourceRange - a two element array of integers describing the
+ * entire inclusive source range of this node within its document.
+ * Contents start on and include the character at the first position.
+ * Contents end on and include the character at the last position.
+ * An array of -1's indicates this node's contents do not exist
+ * in the document.
+ * @param name - the identifier portion of the name of this node, or
+ * <code>null</code> if this node does not have a name
+ * @param nameRange - a two element array of integers describing the
+ * entire inclusive source range of this node's name within its document,
+ * including any array qualifiers that might immediately follow the name
+ * or -1's if this node does not have a name.
+ */
+ DOMNode(char[] document, int[] sourceRange, String name, int[] nameRange) {
+ super();
+ fDocument = document;
+ fSourceRange = sourceRange;
+ fName = name;
+ fNameRange = nameRange;
+
+ }
+
+ /**
+ * Adds the given un-parented node (document fragment) as the last child of
+ * this node.
+ *
+ * <p>When a child is added, this node must be considered fragmented such that
+ * the contents of this node are properly generated.
+ *
+ * @see IDOMNode#addChild(IDOMNode)
+ */
+ public void addChild(IDOMNode child)
+ throws IllegalArgumentException, DOMException {
+ basicAddChild(child);
+
+ // if the node is a constructor, it must also be fragmented to update the constructor's name
+ if (child.getNodeType() == IDOMNode.METHOD
+ && ((IDOMMethod) child).isConstructor()) {
+ ((DOMNode) child).fragment();
+ } else {
+ fragment();
+ }
+ }
+
+ /**
+ * Appends the current contents of this document fragment
+ * to the given <code>CharArrayBuffer</code>.
+ *
+ * <p>If this node is fragmented, contents must be generated by
+ * using the original document and indicies as a form for the current
+ * attribute values of this node. If this node not fragmented, the
+ * contents can be obtained from the document.
+ *
+ */
+ protected void appendContents(CharArrayBuffer buffer) {
+ if (isFragmented()) {
+ appendFragmentedContents(buffer);
+ } else {
+ buffer.append(
+ fDocument,
+ fSourceRange[0],
+ fSourceRange[1] + 1 - fSourceRange[0]);
+ }
+ }
+
+ /**
+ * Appends the contents of all children of this node to the
+ * given <code>CharArrayBuffer</code>.
+ *
+ * <p>This algorithm used minimizes String generation by merging
+ * adjacent unfragmented children into one substring operation.
+ *
+ */
+ protected void appendContentsOfChildren(CharArrayBuffer buffer) {
+ DOMNode child = fFirstChild;
+ DOMNode sibling;
+
+ int start = 0, end = 0;
+ if (child != null) {
+ start = child.getStartPosition();
+ end = child.getEndPosition();
+ }
+ while (child != null) {
+ sibling = child.fNextNode;
+ if (sibling != null) {
+ if (sibling.isContentMergableWith(child)) {
+ end = sibling.getEndPosition();
+ } else {
+ if (child.isFragmented()) {
+ child.appendContents(buffer);
+ } else {
+ buffer.append(child.getDocument(), start, end + 1 - start);
+ }
+ start = sibling.getStartPosition();
+ end = sibling.getEndPosition();
+ }
+ } else {
+ if (child.isFragmented()) {
+ child.appendContents(buffer);
+ } else {
+ buffer.append(child.getDocument(), start, end + 1 - start);
+ }
+ }
+ child = sibling;
+ }
+ }
+
+ /**
+ * Appends the contents of this node to the given <code>CharArrayBufer</code>, using
+ * the original document and indicies as a form for the current attribute
+ * values of this node.
+ */
+ protected abstract void appendFragmentedContents(CharArrayBuffer buffer);
+ /**
+ * Adds the given un-parented node (document fragment) as the last child of
+ * this node without setting this node's 'fragmented' flag. This
+ * method is only used by the <code>DOMBuilder</code> when creating a new DOM such
+ * that a new DOM is unfragmented.
+ */
+ void basicAddChild(IDOMNode child)
+ throws IllegalArgumentException, DOMException {
+ // verify child may be added
+ if (!canHaveChildren()) {
+ throw new DOMException("attempt to add child to node that cannot have children");
+ }
+ if (child == null) {
+ throw new IllegalArgumentException("attempt to add null child");
+ }
+ if (!isAllowableChild(child)) {
+ throw new DOMException("attempt to add child of incompatible type");
+ }
+ if (child.getParent() != null) {
+ throw new DOMException("attempt to add child that is already parented");
+ }
+ /* NOTE: To test if the child is an ancestor of this node, we
+ * need only test if the root of this node is the child (the child
+ * is already a root since we have just guarenteed it has no parent).
+ */
+ if (child == getRoot()) {
+ throw new DOMException("attempt to add ancestor as child");
+ }
+
+ DOMNode node = (DOMNode) child;
+
+ // if the child is not already part of this document, localize its contents
+ // before adding it to the tree
+ if (node.getDocument() != getDocument()) {
+ node.localizeContents();
+ }
+
+ // add the child last
+ if (fFirstChild == null) {
+ // this is the first and only child
+ fFirstChild = node;
+ } else {
+ fLastChild.fNextNode = node;
+ node.fPreviousNode = fLastChild;
+ }
+ fLastChild = node;
+ node.fParent = this;
+ }
+
+ /**
+ * Generates detailed source indexes for this node if possible.
+ *
+ * @exception DOMException if unable to generate detailed source indexes
+ * for this node
+ */
+ protected void becomeDetailed() throws DOMException {
+ if (!isDetailed()) {
+ DOMNode detailed = getDetailedNode();
+ if (detailed == null) {
+ throw new DOMException("Unable to generate detailed source indexes.");
+ }
+ if (detailed != this) {
+ shareContents(detailed);
+ }
+ }
+ }
+
+ /**
+ * Returns true if this node is allowed to have children, otherwise false.
+ *
+ * <p>Default implementation of <code>IDOMNode</code> interface method returns false; this
+ * method must be overridden by subclasses that implement nodes that allow
+ * children.
+ *
+ * @see IDOMNode#canHaveChildren()
+ */
+ public boolean canHaveChildren() {
+ return false;
+ }
+
+ /**
+ * @see IDOMNode#clone()
+ */
+ public Object clone() {
+
+ // create a new buffer with all my contents and children contents
+ int length = 0;
+ char[] buffer = null;
+ int offset = fSourceRange[0];
+
+ if (offset >= 0) {
+ length = fSourceRange[1] - offset + 1;
+ buffer = new char[length];
+ System.arraycopy(fDocument, offset, buffer, 0, length);
+ }
+ DOMNode clone = newDOMNode();
+ clone.shareContents(this);
+ clone.fDocument = buffer;
+
+ if (offset > 0) {
+ clone.offset(0 - offset);
+ }
+
+ // clone my children
+ if (canHaveChildren()) {
+ Enumeration children = getChildren();
+ while (children.hasMoreElements()) {
+ DOMNode child = (DOMNode) children.nextElement();
+ if (child.fDocument == fDocument) {
+ DOMNode childClone = child.cloneSharingDocument(buffer, offset);
+ clone.basicAddChild(childClone);
+ } else {
+ DOMNode childClone = (DOMNode) child.clone();
+ clone.addChild(childClone);
+ }
+
+ }
+ }
+
+ return clone;
+ }
+
+ private DOMNode cloneSharingDocument(char[] document, int rootOffset) {
+
+ int length = 0;
+ int offset = fSourceRange[0];
+
+ DOMNode clone = newDOMNode();
+ clone.shareContents(this);
+ clone.fDocument = document;
+ if (rootOffset > 0) {
+ clone.offset(0 - rootOffset);
+ }
+
+ if (canHaveChildren()) {
+ Enumeration children = getChildren();
+ while (children.hasMoreElements()) {
+ DOMNode child = (DOMNode) children.nextElement();
+ if (child.fDocument == fDocument) {
+ DOMNode childClone = child.cloneSharingDocument(document, rootOffset);
+ clone.basicAddChild(childClone);
+ } else {
+ DOMNode childClone = (DOMNode) child.clone();
+ clone.addChild(childClone);
+ }
+ }
+ }
+ return clone;
+ }
+
+ /**
+ * Sets this node's fragmented flag and all ancestor fragmented flags
+ * to <code>true<code>. This happens when an attribute of this node or a descendant
+ * node has been altered. When a node is fragmented, its contents must
+ * be generated from its attributes and original "form" rather than
+ * from the original contents in the document.
+ */
+ protected void fragment() {
+ if (!isFragmented()) {
+ fIsFragmented = true;
+ if (fParent != null) {
+ fParent.fragment();
+ }
+ }
+ }
+
+ /**
+ * @see IDOMNode#getCharacters()
+ */
+ public char[] getCharacters() {
+ CharArrayBuffer buffer = new CharArrayBuffer();
+ appendContents(buffer);
+ return buffer.getContents();
+ }
+
+ /**
+ * @see IDOMNode#getChild(String)
+ */
+ public IDOMNode getChild(String name) {
+ DOMNode child = fFirstChild;
+ while (child != null) {
+ String n = child.getName();
+ if (n != null && n.equals(name)) {
+ return child;
+ }
+ child = child.fNextNode;
+ }
+ return null;
+ }
+
+ /**
+ * @see IDOMNode#getChildren()
+ */
+ public Enumeration getChildren() {
+ return new SiblingEnumeration(fFirstChild);
+ }
+
+ /**
+ * Returns the current contents of this document fragment,
+ * or <code>null</code> if this node has no contents.
+ *
+ * <p>If this node is fragmented, contents must be generated by
+ * using the original document and indicies as a form for the current
+ * attribute values of this node. If this node not fragmented, the
+ * contents can be obtained from the document.
+ *
+ * @see IDOMNode#getContents()
+ */
+ public String getContents() {
+ CharArrayBuffer buffer = new CharArrayBuffer();
+ appendContents(buffer);
+ return buffer.toString();
+ }
+
+ /**
+ * Returns a new document fragment representing this node with
+ * detailed source indexes. Subclasses that provide a detailed
+ * implementation must override this method.
+ */
+ protected DOMNode getDetailedNode() {
+ return this;
+ }
+
+ /**
+ * Returns the document containing this node's original contents.
+ * The document may be shared by other nodes.
+ */
+ protected char[] getDocument() {
+ return fDocument;
+ }
+
+ /**
+ * Returns the original position of the last character of this
+ * node's contents in its document.
+ */
+ public int getEndPosition() {
+ return fSourceRange[1];
+ }
+
+ /**
+ * Returns a factory with which to create new document fragments.
+ */
+ protected IDOMFactory getFactory() {
+ return new DOMFactory();
+ }
+
+ /**
+ * @see IDOMNode#getFirstChild()
+ */
+ public IDOMNode getFirstChild() {
+ return fFirstChild;
+ }
+
+ /**
+ * Returns the position at which the first child of this node should be inserted.
+ */
+ public int getInsertionPosition() {
+ return getEndPosition();
+ }
+
+ /**
+ * Returns <code>true</code> if the given mask of this node's state flag
+ * is turned on, otherwise <code>false</code>.
+ */
+ protected boolean getMask(int mask) {
+ return (fStateMask & mask) > 0;
+ }
+
+ /**
+ * @see IDOMNode#getName()
+ */
+ public String getName() {
+ return fName;
+ }
+
+ /**
+ * Returns the source code to be used for this node's name.
+ */
+ protected char[] getNameContents() {
+ if (isNameAltered()) {
+ return fName.toCharArray();
+ } else {
+ if (fName == null || fNameRange[0] < 0) {
+ return null;
+ } else {
+ int length = fNameRange[1] + 1 - fNameRange[0];
+ char[] result = new char[length];
+ System.arraycopy(fDocument, fNameRange[0], result, 0, length);
+ return result;
+ }
+ }
+ }
+
+ /**
+ * @see IDOMNode#getNextNode()
+ */
+ public IDOMNode getNextNode() {
+ return fNextNode;
+ }
+
+ /**
+ * @see IDOMNode#getParent()
+ */
+ public IDOMNode getParent() {
+ return fParent;
+ }
+
+ /**
+ * Answers a source position which corresponds to the end of the parent
+ * element's declaration.
+ */
+ protected int getParentEndDeclaration() {
+ IDOMNode parent = getParent();
+ if (parent == null) {
+ return 0;
+ } else {
+ if (parent instanceof IDOMCompilationUnit) {
+ return 0;
+ } else {
+ return ((DOMType) parent).getOpenBodyEnd();
+ }
+ }
+ }
+
+ /**
+ * @see IDOMNode#getPreviousNode()
+ */
+ public IDOMNode getPreviousNode() {
+ return fPreviousNode;
+ }
+
+ /**
+ * Returns the root node of this document fragment.
+ */
+ protected IDOMNode getRoot() {
+ if (fParent == null) {
+ return this;
+ } else {
+ return fParent.getRoot();
+ }
+ }
+
+ /**
+ * Returns the original position of the first character of this
+ * node's contents in its document.
+ */
+ public int getStartPosition() {
+ return fSourceRange[0];
+ }
+
+ /**
+ * @see IDOMNode#insertSibling(IDOMNode)
+ */
+ public void insertSibling(IDOMNode sibling)
+ throws IllegalArgumentException, DOMException {
+ // verify sibling may be added
+ if (sibling == null) {
+ throw new IllegalArgumentException("attempt to insert null sibling");
+ }
+ if (fParent == null) {
+ throw new DOMException("attempt to insert sibling before root node");
+ }
+ if (!fParent.isAllowableChild(sibling)) {
+ throw new DOMException("attempt to insert sibling of incompatible type");
+ }
+ if (sibling.getParent() != null) {
+ throw new DOMException("attempt to insert sibling that is already parented");
+ }
+ /* NOTE: To test if the sibling is an ancestor of this node, we
+ * need only test if the root of this node is the child (the sibling
+ * is already a root since we have just guaranteed it has no parent).
+ */
+ if (sibling == getRoot()) {
+ throw new DOMException("attempt to insert ancestor as sibling");
+ }
+
+ DOMNode node = (DOMNode) sibling;
+
+ // if the sibling is not already part of this document, localize its contents
+ // before inserting it into the tree
+ if (node.getDocument() != getDocument()) {
+ node.localizeContents();
+ }
+
+ // insert the node
+ if (fPreviousNode == null) {
+ fParent.fFirstChild = node;
+ } else {
+ fPreviousNode.fNextNode = node;
+ }
+ node.fParent = fParent;
+ node.fPreviousNode = fPreviousNode;
+ node.fNextNode = this;
+ fPreviousNode = node;
+
+ // if the node is a constructor, it must also be fragmented to update the constructor's name
+ if (node.getNodeType() == IDOMNode.METHOD
+ && ((IDOMMethod) node).isConstructor()) {
+ node.fragment();
+ } else {
+ fParent.fragment();
+ }
+ }
+
+ /**
+ * @see IDOMNode
+ */
+ public boolean isAllowableChild(IDOMNode node) {
+ return false;
+ }
+
+ /**
+ * Returns <code>true</code> if the contents of this node are from the same document as
+ * the given node, the contents of this node immediately follow the contents
+ * of the given node, and neither this node or the given node are fragmented -
+ * otherwise <code>false</code>.
+ */
+ protected boolean isContentMergableWith(DOMNode node) {
+ return !node.isFragmented()
+ && !isFragmented()
+ && node.getDocument() == getDocument()
+ && node.getEndPosition() + 1 == getStartPosition();
+ }
+
+ /**
+ * Returns <code>true</code> if this node has detailed source index information,
+ * or <code>false</code> if this node has limited source index information. To
+ * perform some manipulations, detailed indexes are required.
+ */
+ protected boolean isDetailed() {
+ return getMask(MASK_DETAILED_SOURCE_INDEXES);
+ }
+
+ /**
+ * Returns <code>true</code> if this node's or a descendant node's contents
+ * have been altered since this node was created. This indicates
+ * that the contents of this node are no longer consistent with
+ * the contents of this node's document.
+ */
+ protected boolean isFragmented() {
+ return fIsFragmented;
+ }
+
+ /**
+ * Returns <code>true</code> if this noed's name has been altered
+ * from the original document contents.
+ */
+ protected boolean isNameAltered() {
+ return getMask(MASK_NAME_ALTERED);
+ }
+
+ /**
+ * @see IDOMNode#isSignatureEqual(IDOMNode).
+ *
+ * <p>By default, the signatures of two nodes are equal if their
+ * type and names are equal. Node types that have other requirements
+ * for equality must override this method.
+ */
+ public boolean isSignatureEqual(IDOMNode node) {
+ return getNodeType() == node.getNodeType() && getName().equals(node.getName());
+ }
+
+ /**
+ * Localizes the contents of this node and all descendant nodes,
+ * such that this node is no longer dependent on its original
+ * document in order to generate its contents. This node and all
+ * descendant nodes become unfragmented and share a new
+ * document.
+ */
+ protected void localizeContents() {
+
+ DOMNode clone = (DOMNode) clone();
+ shareContents(clone);
+
+ }
+
+ /**
+ * Returns a new empty <code>DOMNode</code> for this instance.
+ */
+ protected abstract DOMNode newDOMNode();
+ /**
+ * Normalizes this <code>DOMNode</code>'s source positions to include whitespace preceeding
+ * the node on the line on which the node starts, and all whitespace after the node up to
+ * the next node's start
+ */
+ void normalize(ILineStartFinder finder) {
+ if (getPreviousNode() == null)
+ normalizeStartPosition(getParentEndDeclaration(), finder);
+
+ // Set the children's position
+ if (canHaveChildren()) {
+ Enumeration children = getChildren();
+ while (children.hasMoreElements())
+ ((DOMNode) children.nextElement()).normalize(finder);
+ }
+
+ normalizeEndPosition(finder, (DOMNode) getNextNode());
+ }
+
+ /**
+ * Normalizes this <code>DOMNode</code>'s end position.
+ */
+ void normalizeEndPosition(ILineStartFinder finder, DOMNode next) {
+ if (next == null) {
+ // this node's end position includes all of the characters up
+ // to the end of the enclosing node
+ DOMNode parent = (DOMNode) getParent();
+ if (parent == null || parent instanceof DOMCompilationUnit) {
+ setSourceRangeEnd(fDocument.length - 1);
+ } else {
+ // parent is a type
+ setSourceRangeEnd(((DOMType) parent).getCloseBodyPosition() - 1);
+ }
+ } else {
+ // this node's end position is just before the start of the next node
+ next.normalizeStartPosition(getEndPosition(), finder);
+ setSourceRangeEnd(next.getStartPosition() - 1);
+ }
+ }
+
+ /**
+ * Normalizes this <code>DOMNode</code>'s start position.
+ */
+ void normalizeStartPosition(int previousEnd, ILineStartFinder finder) {
+ int nodeStart = getStartPosition();
+ int lineStart = finder.getLineStart(nodeStart);
+ if (nodeStart > lineStart
+ && (lineStart > previousEnd || (previousEnd == 0 && lineStart == 0)))
+ setStartPosition(lineStart);
+ }
+
+ /**
+ * Offsets all the source indexes in this node by the given amount.
+ */
+ protected void offset(int offset) {
+ offsetRange(fNameRange, offset);
+ offsetRange(fSourceRange, offset);
+ }
+
+ /**
+ * Offsets the source range by the given amount
+ */
+ protected void offsetRange(int[] range, int offset) {
+ for (int i = 0; i < range.length; i++) {
+ range[i] += offset;
+ if (range[i] < 0) {
+ range[i] = -1;
+ }
+ }
+ }
+
+ /**
+ * Returns a copy of the given range.
+ */
+ protected int[] rangeCopy(int[] range) {
+ int[] copy = new int[range.length];
+ for (int i = 0; i < range.length; i++) {
+ copy[i] = range[i];
+ }
+ return copy;
+ }
+
+ /**
+ * Separates this node from its parent and siblings, maintaining any ties that
+ * this node has to the underlying document fragment.
+ *
+ * <p>When a child is removed, its parent is fragmented such that it properly
+ * generates its contents.
+ *
+ * @see IDOMNode#remove()
+ */
+ public void remove() {
+
+ if (fParent != null) {
+ fParent.fragment();
+ }
+
+ // link siblings
+ if (fNextNode != null) {
+ fNextNode.fPreviousNode = fPreviousNode;
+ }
+ if (fPreviousNode != null) {
+ fPreviousNode.fNextNode = fNextNode;
+ }
+ // fix parent's pointers
+ if (fParent != null) {
+ if (fParent.fFirstChild == this) {
+ fParent.fFirstChild = fNextNode;
+ }
+ if (fParent.fLastChild == this) {
+ fParent.fLastChild = fPreviousNode;
+ }
+ }
+ // remove myself
+ fParent = null;
+ fNextNode = null;
+ fPreviousNode = null;
+ }
+
+ /**
+ * Sets the specified mask of this node's state mask on or off
+ * based on the boolean value - true -> on, false -> off.
+ */
+ protected void setMask(int mask, boolean on) {
+ if (on) {
+ fStateMask |= mask;
+ } else {
+ fStateMask &= ~mask;
+ }
+ }
+
+ /**
+ * @see IDOMNode#setName
+ */
+ public void setName(String name) {
+ fName = name;
+ setNameAltered(true);
+ fragment();
+ }
+
+ /**
+ * Sets the state of this node as having
+ * its name attribute altered from the original
+ * document contents.
+ */
+ protected void setNameAltered(boolean altered) {
+ setMask(MASK_NAME_ALTERED, altered);
+ }
+
+ /**
+ * Sets the original position of the last character of this node's contents
+ * in its document. This method is only used during DOM creation while
+ * normalizing the source range of each node.
+ */
+ protected void setSourceRangeEnd(int end) {
+ fSourceRange[1] = end;
+ }
+
+ /**
+ * Sets the original position of the first character of this node's contents
+ * in its document. This method is only used during DOM creation while
+ * normalizing the source range of each node.
+ */
+ protected void setStartPosition(int start) {
+ fSourceRange[0] = start;
+ }
+
+ /**
+ * Sets the contents of this node and descendant nodes to be the
+ * (identical) contents of the given node and its descendants. This
+ * does not effect this node's parent and sibling configuration,
+ * only the contents of this node. This is used only to localize
+ * the contents of this node.
+ */
+ protected void shareContents(DOMNode node) {
+ fDocument = node.fDocument;
+ fIsFragmented = node.fIsFragmented;
+ fName = node.fName;
+ fNameRange = rangeCopy(node.fNameRange);
+ fSourceRange = rangeCopy(node.fSourceRange);
+ fStateMask = node.fStateMask;
+
+ if (canHaveChildren()) {
+ Enumeration myChildren = getChildren();
+ Enumeration otherChildren = node.getChildren();
+ DOMNode myChild, otherChild;
+ while (myChildren.hasMoreElements()) {
+ myChild = (DOMNode) myChildren.nextElement();
+ otherChild = (DOMNode) otherChildren.nextElement();
+ myChild.shareContents(otherChild);
+ }
+ }
+ }
+
+ /**
+ * Returns a <code>String</code> representing this node - for Debug purposes only.
+ */
+ public abstract String toString();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMPackage.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMPackage.java
new file mode 100644
index 0000000000..d0698c20ac
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMPackage.java
@@ -0,0 +1,146 @@
+package org.eclipse.jdt.internal.core.jdom;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.Flags;
+import org.eclipse.jdt.core.jdom.*;
+import org.eclipse.jdt.internal.core.JavaModelManager;
+import org.eclipse.jdt.internal.core.util.*;
+
+/**
+ * DOMPackage provides an implementation of IDOMPackage.
+ *
+ * @see IDOMPackage
+ * @see DOMNode
+ */
+class DOMPackage extends DOMNode implements IDOMPackage {
+
+ /**
+ * Creates an empty PACKAGE node.
+ */
+ DOMPackage() {
+ setMask(MASK_DETAILED_SOURCE_INDEXES, true);
+ }
+
+ /**
+ * Creates a new simple PACKAGE document fragment on the given range of the document.
+ *
+ * @param document - the document containing this node's original contents
+ * @param sourceRange - a two element array of integers describing the
+ * entire inclusive source range of this node within its document.
+ * Contents start on and include the character at the first position.
+ * Contents end on and include the character at the last position.
+ * An array of -1's indicates this node's contents do not exist
+ * in the document.
+ * @param name - the identifier portion of the name of this node, or
+ * <code>null</code> if this node does not have a name
+ */
+ DOMPackage(char[] document, int[] sourceRange, String name) {
+ super(document, sourceRange, name, new int[] { -1, -1 });
+ setMask(MASK_DETAILED_SOURCE_INDEXES, false);
+ }
+
+ /**
+ * Creates a new detailed PACKAGE document fragment on the given range of the document.
+ *
+ * @param document - the document containing this node's original contents
+ * @param sourceRange - a two element array of integers describing the
+ * entire inclusive source range of this node within its document.
+ * Contents start on and include the character at the first position.
+ * Contents end on and include the character at the last position.
+ * An array of -1's indicates this node's contents do not exist
+ * in the document.
+ * @param name - the identifier portion of the name of this node, or
+ * <code>null</code> if this node does not have a name
+ * @param nameRange - a two element array of integers describing the
+ * entire inclusive source range of this node's name within its document,
+ * including any array qualifiers that might immediately follow the name
+ * or -1's if this node does not have a name.
+ */
+ DOMPackage(char[] document, int[] sourceRange, String name, int[] nameRange) {
+ super(document, sourceRange, name, nameRange);
+ setMask(MASK_DETAILED_SOURCE_INDEXES, true);
+ }
+
+ /**
+ * @see DOMNode#appendFragmentedContents(CharArrayBuffer)
+ */
+ protected void appendFragmentedContents(CharArrayBuffer buffer) {
+ if (fNameRange[0] < 0) {
+ buffer.append("package ").append(fName).append(';').append(
+ JavaModelManager.LINE_SEPARATOR);
+ } else {
+ buffer
+ .append(fDocument, fSourceRange[0], fNameRange[0] - fSourceRange[0])
+ .append(fName)
+ .append(fDocument, fNameRange[1] + 1, fSourceRange[1] - fNameRange[1]);
+ }
+ }
+
+ /**
+ * @see IDOMNode#getContents()
+ */
+ public String getContents() {
+ if (fName == null) {
+ return null;
+ } else {
+ return super.getContents();
+ }
+ }
+
+ /**
+ * @see DOMNode#getDetailedNode()
+ */
+ protected DOMNode getDetailedNode() {
+ return (DOMNode) getFactory().createPackage(getContents());
+ }
+
+ /**
+ * @see IDOMNode#getJavaElement
+ */
+ public IJavaElement getJavaElement(IJavaElement parent)
+ throws IllegalArgumentException {
+ if (parent.getElementType() == IJavaElement.COMPILATION_UNIT) {
+ return ((ICompilationUnit) parent).getPackageDeclaration(getName());
+ } else {
+ throw new IllegalArgumentException("Illegal parent argument");
+ }
+ }
+
+ /**
+ * @see IDOMNode#getNodeType()
+ */
+ public int getNodeType() {
+ return IDOMNode.PACKAGE;
+ }
+
+ /**
+ * @see DOMNode
+ */
+ protected DOMNode newDOMNode() {
+ return new DOMPackage();
+ }
+
+ /**
+ * @see IDOMNode#setName
+ */
+ public void setName(String name) {
+ becomeDetailed();
+ super.setName(name);
+ }
+
+ /**
+ * @see IDOMNode#toString()
+ */
+ public String toString() {
+ return "PACKAGE: " + getName();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMType.java
new file mode 100644
index 0000000000..035be3ddcf
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMType.java
@@ -0,0 +1,764 @@
+package org.eclipse.jdt.internal.core.jdom;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.jdom.*;
+import org.eclipse.jdt.internal.core.util.*;
+import org.eclipse.jdt.internal.compiler.parser.InvalidInputException;
+import org.eclipse.jdt.internal.compiler.parser.Scanner;
+import org.eclipse.jdt.internal.compiler.parser.TerminalSymbols;
+
+import java.util.Enumeration;
+
+/**
+ * DOMType provides an implementation of IDOMType.
+ *
+ * @see IDOMType
+ * @see DOMNode
+ */
+
+/* package */
+class DOMType extends DOMMember implements IDOMType {
+
+ /**
+ * The 'class' or 'interface' keyword if altered
+ * from the documents contents, otherwise <code>null</code>.
+ */
+ protected String fTypeKeyword;
+
+ /**
+ * The original inclusive source range of the 'class'
+ * or 'interface' keyword in the document.
+ */
+ protected int[] fTypeRange;
+
+ /**
+ * The superclass name for the class declaration
+ * if altered from the document's contents, otherwise
+ * <code>null</code>. Also <code>null</code> when this
+ * type represents an interface.
+ */
+ protected String fSuperclass;
+
+ /**
+ * The original inclusive source range of the superclass
+ * name in the document, or -1's of no superclass was
+ * specified in the document.
+ */
+ protected int[] fSuperclassRange;
+
+ /**
+ * The original inclusive souce range of the 'extends' keyword
+ * in the document, including surrounding whitespace, or -1's if
+ * the keyword was not present in the document.
+ */
+ protected int[] fExtendsRange;
+
+ /**
+ * The original inclusive souce range of the 'implements' keyword
+ * in the document, including surrounding whitespace, or -1's if
+ * the keyword was not present in the document.
+ */
+ protected int[] fImplementsRange;
+
+ /**
+ * The comma delimited list of interfaces this type implements
+ * or extends, if altered from the document's contents, otherwise
+ * <code>null</code>. Also <code>null</code> if this type does
+ * not implement or extend any interfaces.
+ */
+ protected char[] fInterfaces;
+
+ /**
+ * The original inclusive source range of the list of interfaces this
+ * type implements or extends, not including any surrouding whitespace.
+ * If the document did not specify interfaces, this array contains -1's.
+ */
+ protected int[] fInterfacesRange;
+
+ /**
+ * The original source range of the first character following the
+ * type name superclass name, or interface list, up to and including
+ * the first character before the first type member.
+ */
+ protected int[] fOpenBodyRange;
+
+ /**
+ * The original source range of the first new line or non whitespace
+ * character preceding the close brace of the type's body, up to the
+ * and including the first character before the next node (if there are
+ * no following nodes, the range ends at the position of the last
+ * charater in the document).
+ */
+ protected int[] fCloseBodyRange;
+
+ /**
+ * A list of interfaces this type extends or implements.
+ * <code>null</code> when this type does not extend
+ * or implement any interfaces.
+ */
+ protected String[] fSuperInterfaces = new String[0];
+ /**
+ * Constructs an empty type node.
+ */
+ DOMType() {
+
+ }
+
+ /**
+ * Creates a new detailed TYPE document fragment on the given range of the document.
+ *
+ * @param document - the document containing this node's original contents
+ * @param sourceRange - a two element array of integers describing the
+ * entire inclusive source range of this node within its document.
+ * Contents start on and include the character at the first position.
+ * Contents end on and include the character at the last position.
+ * An array of -1's indicates this node's contents do not exist
+ * in the document.
+ * @param name - the identifier portion of the name of this node, or
+ * <code>null</code> if this node does not have a name
+ * @param nameRange - a two element array of integers describing the
+ * entire inclusive source range of this node's name within its document,
+ * including any array qualifiers that might immediately follow the name
+ * or -1's if this node does not have a name.
+ * @param commentRange - a two element array describing the comments that precede
+ * the member declaration. The first matches the start of this node's
+ * sourceRange, and the second is the new-line or first non-whitespace
+ * character following the last comment. If no comments are present,
+ * this array contains two -1's.
+ * @param flags - an integer representing the modifiers for this member. The
+ * integer can be analyzed with org.eclipse.jdt.core.Flags
+ * @param modifierRange - a two element array describing the location of
+ * modifiers for this member within its source range. The first integer
+ * is the first character of the first modifier for this member, and
+ * the second integer is the last whitespace character preceeding the
+ * next part of this member declaration. If there are no modifiers present
+ * in this node's source code (i.e. default protection), this array
+ * contains two -1's.
+ * @param typeRange - a two element array describing the location of the 'class'
+ * or 'interface' keyword in the type declaration - first and last character
+ * positions.
+ * @param superclassRange - a two element array describing the location of the
+ * superclass name in the type declaration - first and last character
+ * positions or two -1's if a superclass is not present in the document.
+ * @param extendsRange - a two element array describing the location of the
+ * 'extends' keyword in the type declaration, including any surrounding
+ * whitespace, or -1's if the 'extends' keyword is not present in the document.
+ * @param implementsList - an array of names of the interfaces this type implements
+ * or extends, or <code>null</code> if this type does not implement or extend
+ * any interfaces.
+ * @param implementsRange - a two element array describing the location of the
+ * comment delimited list of interfaces this type implements or extends,
+ * not including any surrounding whitespace, or -1's if no interface list
+ * is present in the document.
+ * @param implementsKeywordRange - a two element array describing the location of the
+ * 'implements' keyword, including any surrounding whitespace, or -1's if no
+ * 'implements' keyword is present in the document.
+ * @param openBodyRange - a two element array describing the location of the
+ * open brace of the type's body and whitespace following the type declaration
+ * and preceeding the first member in the type.
+ * @param closeBodyRange - a two element array describing the source range of the
+ * first new line or non whitespace character preceeding the close brace of the
+ * type's body, up to the close brace
+ * @param isClass - true is the type is a class, false if it is an interface
+ */
+ DOMType(
+ char[] document,
+ int[] sourceRange,
+ String name,
+ int[] nameRange,
+ int[] commentRange,
+ int flags,
+ int[] modifierRange,
+ int[] typeRange,
+ int[] superclassRange,
+ int[] extendsRange,
+ String[] implementsList,
+ int[] implementsRange,
+ int[] implementsKeywordRange,
+ int[] openBodyRange,
+ int[] closeBodyRange,
+ boolean isClass) {
+ super(
+ document,
+ sourceRange,
+ name,
+ nameRange,
+ commentRange,
+ flags,
+ modifierRange);
+
+ fTypeRange = typeRange;
+ setMask(MASK_TYPE_IS_CLASS, isClass);
+
+ fExtendsRange = extendsRange;
+ fImplementsRange = implementsKeywordRange;
+ fSuperclassRange = superclassRange;
+ fInterfacesRange = implementsRange;
+ fCloseBodyRange = closeBodyRange;
+ setMask(MASK_TYPE_HAS_SUPERCLASS, superclassRange[0] > 0);
+ setMask(MASK_TYPE_HAS_INTERFACES, implementsList != null);
+ fSuperInterfaces = implementsList;
+ fOpenBodyRange = openBodyRange;
+ fCloseBodyRange = closeBodyRange;
+ setMask(MASK_DETAILED_SOURCE_INDEXES, true);
+
+ }
+
+ /**
+ * Creates a new simple TYPE document fragment on the given range of the document.
+ *
+ * @param document - the document containing this node's original contents
+ * @param sourceRange - a two element array of integers describing the
+ * entire inclusive source range of this node within its document.
+ * Contents start on and include the character at the first position.
+ * Contents end on and include the character at the last position.
+ * An array of -1's indicates this node's contents do not exist
+ * in the document.
+ * @param name - the identifier portion of the name of this node, or
+ * <code>null</code> if this node does not have a name
+ * @param nameRange - a two element array of integers describing the
+ * entire inclusive source range of this node's name within its document,
+ * including any array qualifiers that might immediately follow the name
+ * or -1's if this node does not have a name.
+ * @param flags - an integer representing the modifiers for this member. The
+ * integer can be analyzed with org.eclipse.jdt.core.Flags
+ * @param implementsList - an array of names of the interfaces this type implements
+ * or extends, or <code>null</code> if this type does not implement or extend
+ * any interfaces.
+ * @param isClass - true is the type is a class, false if it is an interface
+ */
+ DOMType(
+ char[] document,
+ int[] sourceRange,
+ String name,
+ int[] nameRange,
+ int flags,
+ String[] implementsList,
+ boolean isClass) {
+ this(
+ document,
+ sourceRange,
+ name,
+ nameRange,
+ new int[] { -1, -1 },
+ flags,
+ new int[] { -1, -1 },
+ new int[] { -1, -1 },
+ new int[] { -1, -1 },
+ new int[] { -1, -1 },
+ implementsList,
+ new int[] { -1, -1 },
+ new int[] { -1, -1 },
+ new int[] { -1, -1 },
+ new int[] { sourceRange[1], sourceRange[1] },
+ isClass);
+ setMask(MASK_DETAILED_SOURCE_INDEXES, false);
+ }
+
+ /**
+ * @see IDOMType#addSuperInterface(String)
+ */
+ public void addSuperInterface(String name) throws IllegalArgumentException {
+ if (name == null) {
+ throw new IllegalArgumentException("Cannot add null interface");
+ }
+ if (fSuperInterfaces == null) {
+ fSuperInterfaces = new String[1];
+ fSuperInterfaces[0] = name;
+ } else {
+ fSuperInterfaces = appendString(fSuperInterfaces, name);
+ }
+ setSuperInterfaces(fSuperInterfaces);
+ }
+
+ /**
+ * @see DOMMember#appendMemberBodyContents(CharArrayBuffer)
+ */
+ protected void appendMemberBodyContents(CharArrayBuffer buffer) {
+ buffer.append(
+ fDocument,
+ fOpenBodyRange[0],
+ fOpenBodyRange[1] + 1 - fOpenBodyRange[0]);
+ appendContentsOfChildren(buffer);
+ buffer.append(
+ fDocument,
+ fCloseBodyRange[0],
+ fCloseBodyRange[1] + 1 - fCloseBodyRange[0]);
+ buffer.append(
+ fDocument,
+ fCloseBodyRange[1] + 1,
+ fSourceRange[1] - fCloseBodyRange[1]);
+ }
+
+ /**
+ * @see DOMMember#appendMemberDeclarationContents(CharArrayBuffer )
+ */
+ protected void appendMemberDeclarationContents(CharArrayBuffer buffer) {
+
+ if (fTypeKeyword != null) {
+ buffer.append(fTypeKeyword);
+ buffer.append(fDocument, fTypeRange[1], fNameRange[0] - fTypeRange[1]);
+ } else {
+ buffer.append(fDocument, fTypeRange[0], fTypeRange[1] + 1 - fTypeRange[0]);
+ }
+
+ buffer.append(getName());
+
+ if (isClass()) {
+ boolean hasSuperclass = false, hasInterfaces = false;
+ if (getMask(MASK_TYPE_HAS_SUPERCLASS)) {
+ hasSuperclass = true;
+ if (fExtendsRange[0] < 0) {
+ buffer.append(" extends ");
+ } else {
+ buffer.append(
+ fDocument,
+ fExtendsRange[0],
+ fExtendsRange[1] + 1 - fExtendsRange[0]);
+ }
+ if (fSuperclass != null) {
+ buffer.append(fSuperclass);
+ } else {
+ buffer.append(
+ fDocument,
+ fSuperclassRange[0],
+ fSuperclassRange[1] + 1 - fSuperclassRange[0]);
+ }
+ }
+ if (getMask(MASK_TYPE_HAS_INTERFACES)) {
+ hasInterfaces = true;
+ if (fImplementsRange[0] < 0) {
+ buffer.append(" implements ");
+ } else {
+ buffer.append(
+ fDocument,
+ fImplementsRange[0],
+ fImplementsRange[1] + 1 - fImplementsRange[0]);
+ }
+ if (fInterfaces != null) {
+ buffer.append(fInterfaces);
+ } else {
+ buffer.append(
+ fDocument,
+ fInterfacesRange[0],
+ fInterfacesRange[1] + 1 - fInterfacesRange[0]);
+ }
+ }
+ if (hasInterfaces) {
+ if (fImplementsRange[0] < 0) {
+ buffer.append(" ");
+ } else {
+ buffer.append(
+ fDocument,
+ fInterfacesRange[1] + 1,
+ fOpenBodyRange[0] - fInterfacesRange[1] - 1);
+ }
+ } else {
+ if (hasSuperclass) {
+ if (fSuperclassRange[0] < 0) {
+ buffer.append(" ");
+ } else {
+ buffer.append(
+ fDocument,
+ fSuperclassRange[1] + 1,
+ fOpenBodyRange[0] - fSuperclassRange[1] - 1);
+ }
+ } else {
+ buffer.append(
+ fDocument,
+ fNameRange[1] + 1,
+ fOpenBodyRange[0] - fNameRange[1] - 1);
+ }
+ }
+ } else {
+ if (getMask(MASK_TYPE_HAS_INTERFACES)) {
+ if (fExtendsRange[0] < 0) {
+ buffer.append(" extends ");
+ } else {
+ buffer.append(
+ fDocument,
+ fExtendsRange[0],
+ fExtendsRange[1] + 1 - fExtendsRange[0]);
+ }
+ if (fInterfaces != null) {
+ buffer.append(fInterfaces);
+ buffer.append(" ");
+ } else {
+ buffer.append(
+ fDocument,
+ fInterfacesRange[0],
+ fInterfacesRange[1] + 1 - fInterfacesRange[0]);
+ }
+ } else {
+ buffer.append(
+ fDocument,
+ fNameRange[1] + 1,
+ fOpenBodyRange[0] - fNameRange[1] - 1);
+ }
+ }
+
+ }
+
+ /**
+ * @see DOMNode#appendSimpleContents(CharArrayBuffer)
+ */
+ protected void appendSimpleContents(CharArrayBuffer buffer) {
+ // append eveything before my name
+ buffer.append(fDocument, fSourceRange[0], fNameRange[0] - fSourceRange[0]);
+ // append my name
+ buffer.append(fName);
+
+ // append everything after my name and before my first child
+ buffer.append(fDocument, fNameRange[1] + 1, fOpenBodyRange[1] - fNameRange[1]);
+ // append my children
+ appendContentsOfChildren(buffer);
+ // append from my last child to my end
+ buffer.append(
+ fDocument,
+ fCloseBodyRange[0],
+ fSourceRange[1] - fCloseBodyRange[0] + 1);
+
+ }
+
+ /**
+ * @see IDOMNode#canHaveChildren()
+ */
+ public boolean canHaveChildren() {
+ return true;
+ }
+
+ /**
+ * Returns the position of the closing brace for the body of this type.
+ * This value this method returns is only valid before the type has
+ * been normalized and is present only for normalization.
+ */
+ int getCloseBodyPosition() {
+ return fCloseBodyRange[0];
+ }
+
+ /**
+ * @see DOMNode#getDetailedNode()
+ */
+ protected DOMNode getDetailedNode() {
+ return (DOMNode) getFactory().createType(getContents());
+ }
+
+ /**
+ * @see DOMNode#getInsertionPosition()
+ */
+ public int getInsertionPosition() {
+ return getCloseBodyPosition();
+ }
+
+ /**
+ * @see IDOMNode#getJavaElement
+ */
+ public IJavaElement getJavaElement(IJavaElement parent)
+ throws IllegalArgumentException {
+ if (parent.getElementType() == IJavaElement.TYPE) {
+ return ((IType) parent).getType(getName());
+ } else
+ if (parent.getElementType() == IJavaElement.COMPILATION_UNIT) {
+ return ((ICompilationUnit) parent).getType(getName());
+ } else {
+ throw new IllegalArgumentException("Illegal parent argument");
+ }
+ }
+
+ /**
+ * @see DOMMember#getMemberDeclarationStartPosition()
+ */
+ protected int getMemberDeclarationStartPosition() {
+ return fTypeRange[0];
+ }
+
+ /**
+ * @see IDOMNode#getNodeType()
+ */
+ public int getNodeType() {
+ return IDOMNode.TYPE;
+ }
+
+ /**
+ * Answers the open body range end position.
+ */
+ int getOpenBodyEnd() {
+ return fOpenBodyRange[1];
+ }
+
+ /**
+ * @see IDOMType#getSuperclass()
+ */
+ public String getSuperclass() {
+ becomeDetailed();
+ if (getMask(MASK_TYPE_HAS_SUPERCLASS)) {
+ if (fSuperclass != null) {
+ return fSuperclass;
+ } else {
+ return CharArrayOps.substring(
+ fDocument,
+ fSuperclassRange[0],
+ fSuperclassRange[1] + 1 - fSuperclassRange[0]);
+ }
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * @see IDOMType#getSuperInterfaces()
+ */
+ public String[] getSuperInterfaces() {
+ return fSuperInterfaces;
+ }
+
+ /**
+ * @see IDOMNode
+ */
+ public boolean isAllowableChild(IDOMNode node) {
+ if (node != null) {
+ int type = node.getNodeType();
+ return type == IDOMNode.TYPE
+ || type == IDOMNode.FIELD
+ || type == IDOMNode.METHOD
+ || type == IDOMNode.INITIALIZER;
+ } else {
+ return false;
+ }
+
+ }
+
+ /**
+ * @see IDOMType#isClass()
+ */
+ public boolean isClass() {
+ return getMask(MASK_TYPE_IS_CLASS);
+ }
+
+ /**
+ * @see DOMNode
+ */
+ protected DOMNode newDOMNode() {
+ return new DOMType();
+ }
+
+ /**
+ * Normalizes this <code>DOMNode</code>'s source positions to include whitespace preceeding
+ * the node on the line on which the node starts, and all whitespace after the node up to
+ * the next node's start
+ */
+ void normalize(ILineStartFinder finder) {
+ // perform final changes to the open and close body ranges
+ int openBodyEnd, closeBodyStart;
+ DOMNode first = (DOMNode) getFirstChild();
+ closeBodyStart = fCloseBodyRange[1];
+ if (isDetailed()) {
+ if (first == null) {
+ openBodyEnd = fCloseBodyRange[0] - 1;
+ } else {
+ openBodyEnd = first.getStartPosition();
+ int lineStart = finder.getLineStart(openBodyEnd);
+ openBodyEnd--;
+ if (lineStart > fOpenBodyRange[0])
+ openBodyEnd = lineStart - 1;
+ }
+ } else {
+ if (first != null) {
+ // look for the open body
+ openBodyEnd = CharArrayOps.indexOf('{', fDocument, fNameRange[1] + 1);
+ if (openBodyEnd < 0 || openBodyEnd >= first.getStartPosition()) {
+ openBodyEnd = first.getStartPosition() - 1;
+ } else {
+ int lineStart = finder.getLineStart(first.getStartPosition());
+ if (lineStart > openBodyEnd) {
+ openBodyEnd = lineStart - 1;
+ } else {
+ openBodyEnd = first.getStartPosition() - 1;
+ }
+ }
+ if (fDocument[closeBodyStart] != '}') {
+ // look for the body end
+ Scanner scanner = new Scanner();
+ scanner.setSourceBuffer(
+ CharArrayOps.subarray(
+ fDocument,
+ fLastChild.getEndPosition() + 1,
+ closeBodyStart - fLastChild.getEndPosition() + 1));
+
+ try {
+ int currentToken = scanner.getNextToken();
+ while (currentToken != TerminalSymbols.TokenNameRBRACE
+ && currentToken != TerminalSymbols.TokenNameEOF) {
+ currentToken = scanner.getNextToken();
+ }
+ if (currentToken == TerminalSymbols.TokenNameRBRACE) {
+ closeBodyStart = fLastChild.getEndPosition() + scanner.currentPosition;
+ }
+ } catch (InvalidInputException e) {
+ // leave closeBodyStart as is
+ }
+
+ }
+ } else {
+ openBodyEnd = fCloseBodyRange[0] - 1;
+ }
+ }
+ setOpenBodyRangeEnd(openBodyEnd);
+ setCloseBodyRangeStart(closeBodyStart);
+ super.normalize(finder);
+ }
+
+ /**
+ * Offsets all the source indexes in this node by the given amount.
+ */
+ protected void offset(int offset) {
+ super.offset(offset);
+ offsetRange(fCloseBodyRange, offset);
+ offsetRange(fExtendsRange, offset);
+ offsetRange(fImplementsRange, offset);
+ offsetRange(fInterfacesRange, offset);
+ offsetRange(fOpenBodyRange, offset);
+ offsetRange(fSuperclassRange, offset);
+ offsetRange(fTypeRange, offset);
+ }
+
+ /**
+ * @see IDOMType#setClass(boolean)
+ */
+ public void setClass(boolean b) {
+ becomeDetailed();
+ fragment();
+ setMask(MASK_TYPE_IS_CLASS, b);
+ if (b) {
+ fTypeKeyword = "class";
+ } else {
+ fTypeKeyword = "interface";
+ setSuperclass(null);
+ }
+ }
+
+ /**
+ * Sets the end of the close body range
+ */
+ void setCloseBodyRangeEnd(int end) {
+ fCloseBodyRange[1] = end;
+ }
+
+ /**
+ * Sets the start of the close body range
+ */
+ void setCloseBodyRangeStart(int start) {
+ fCloseBodyRange[0] = start;
+ }
+
+ /**
+ * Sets the name of this node.
+ *
+ * <p>When the name of a type is set, all of its constructors must be marked
+ * as fragmented, since the names of the constructors must reflect the name
+ * of this type.
+ *
+ * @see IDOMNode#setName(char[])
+ */
+ public void setName(String name) throws IllegalArgumentException {
+ if (name == null) {
+ throw new IllegalArgumentException("illegal to set type name to null");
+ }
+ super.setName(name);
+ Enumeration children = getChildren();
+ while (children.hasMoreElements()) {
+ IDOMNode child = (IDOMNode) children.nextElement();
+ if (child.getNodeType() == IDOMNode.METHOD
+ && ((IDOMMethod) child).isConstructor()) {
+ ((DOMNode) child).fragment();
+ }
+ }
+ }
+
+ /**
+ * Sets the end of the open body range
+ */
+ void setOpenBodyRangeEnd(int end) {
+ fOpenBodyRange[1] = end;
+ }
+
+ /**
+ * @see IDOMType#setSuperclass(char[])
+ */
+ public void setSuperclass(String superclassName) {
+ becomeDetailed();
+ fragment();
+ fSuperclass = superclassName;
+ setMask(MASK_TYPE_HAS_SUPERCLASS, superclassName != null);
+ }
+
+ /**
+ * @see IDOMType#setSuperInterfaces(String[])
+ */
+ public void setSuperInterfaces(String[] names) {
+ becomeDetailed();
+ if (names == null) {
+ throw new IllegalArgumentException("illegal to set super interfaces to null");
+ }
+ fragment();
+ fSuperInterfaces = names;
+ if (names == null || names.length == 0) {
+ fInterfaces = null;
+ fSuperInterfaces = null;
+ setMask(MASK_TYPE_HAS_INTERFACES, false);
+ } else {
+ setMask(MASK_TYPE_HAS_INTERFACES, true);
+ CharArrayBuffer buffer = new CharArrayBuffer();
+ for (int i = 0; i < names.length; i++) {
+ if (i > 0) {
+ buffer.append(", ");
+ }
+ buffer.append(names[i]);
+ }
+ fInterfaces = buffer.getContents();
+ }
+ }
+
+ /**
+ * Sets the type keyword
+ */
+ void setTypeKeyword(String keyword) {
+ fTypeKeyword = keyword;
+ }
+
+ /**
+ * @see DOMNode#shareContents(DOMNode)
+ */
+ protected void shareContents(DOMNode node) {
+ super.shareContents(node);
+ DOMType type = (DOMType) node;
+ fCloseBodyRange = rangeCopy(type.fCloseBodyRange);
+ fExtendsRange = type.fExtendsRange;
+ fImplementsRange = rangeCopy(type.fImplementsRange);
+ fInterfaces = type.fInterfaces;
+ fInterfacesRange = rangeCopy(type.fInterfacesRange);
+ fOpenBodyRange = rangeCopy(type.fOpenBodyRange);
+ fSuperclass = type.fSuperclass;
+ fSuperclassRange = rangeCopy(type.fSuperclassRange);
+ fSuperInterfaces = type.fSuperInterfaces;
+ fTypeKeyword = type.fTypeKeyword;
+ fTypeRange = rangeCopy(type.fTypeRange);
+ }
+
+ /**
+ * @see IDOMNode#toString()
+ */
+ public String toString() {
+ return "TYPE: " + getName();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/ILineStartFinder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/ILineStartFinder.java
new file mode 100644
index 0000000000..73fdd88c8b
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/ILineStartFinder.java
@@ -0,0 +1,11 @@
+package org.eclipse.jdt.internal.core.jdom;
+
+interface ILineStartFinder {
+ /**
+ * Returns the position of the start of the line at or before the given source position.
+ *
+ * <p>This defaults to zero if the position corresponds to a position on the first line
+ * of the source.
+ */
+ public int getLineStart(int position);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/NullProblem.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/NullProblem.java
new file mode 100644
index 0000000000..4a0e1856d9
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/NullProblem.java
@@ -0,0 +1,162 @@
+package org.eclipse.jdt.internal.core.jdom;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+
+/**
+ * An implementation of IProblem which keeps track of the info given to it, but does
+ * nothing more. The need for this class is dependent upon the compilers ability to
+ * accept null <code>IProblemFactory</code>s and null <code>IProblem</code>s.
+ */
+public class NullProblem implements IProblem {
+ /**
+ * The filename of the compilation unit which was being processed when this problem occured.
+ */
+ char[] fFileName;
+
+ /**
+ * The problem identification number of this problem.
+ */
+ int fProblemId;
+
+ /**
+ * Specific arguments relating to this problem.
+ */
+ String[] fArguements;
+
+ /**
+ * The severity of this problem
+ */
+ int fSeverity;
+
+ /**
+ * The source position corresponding to the beginning of the source element which caused
+ * this problem.
+ */
+ int fStartPosition;
+
+ /**
+ * The source position corresponding to the end of the source element which caused
+ * this problem.
+ */
+ int fEndPosition;
+
+ /**
+ * The line number in the compilation unit which caused the problem
+ */
+ int fLineNumber;
+ /**
+ * Creates a NullProblem
+ */
+ public NullProblem(
+ char[] originatingFileName,
+ int problemId,
+ String[] arguments,
+ int severity,
+ int startPosition,
+ int endPosition,
+ int lineNumber) {
+ fFileName = originatingFileName;
+ fProblemId = problemId;
+ fArguements = arguments;
+ fSeverity = severity;
+ fStartPosition = startPosition;
+ fEndPosition = endPosition;
+ fLineNumber = lineNumber;
+ }
+
+ /**
+ * @see IProblem
+ */
+ public String[] getArguments() {
+ return fArguements;
+ }
+
+ /**
+ * @see IProblem
+ */
+ public int getID() {
+ return fProblemId;
+ }
+
+ /**
+ * @see IProblem
+ */
+ public String getMessage() {
+ return Integer.toString(fProblemId);
+ }
+
+ /**
+ * @see IProblem
+ */
+ public char[] getOriginatingFileName() {
+ return fFileName;
+ }
+
+ /**
+ * @see IProblem.
+ */
+ public int getSeverity() {
+ return fSeverity;
+ }
+
+ /**
+ * @see IProblem
+ */
+ public int getSourceEnd() {
+ return fEndPosition;
+ }
+
+ /**
+ * @see IProblem
+ */
+ public int getSourceLineNumber() {
+ return fLineNumber;
+ }
+
+ /**
+ * @see IProblem
+ */
+ public int getSourceStart() {
+ return fStartPosition;
+ }
+
+ /**
+ * @see IProblem
+ */
+ public boolean isError() {
+ return true;
+ }
+
+ /**
+ * @see IProblem
+ */
+ public boolean isWarning() {
+ return false;
+ }
+
+ /**
+ * @see IProblem
+ */
+ public void setSourceEnd(int sourceEnd) {
+ fEndPosition = sourceEnd;
+ }
+
+ /**
+ * @see IProblem
+ */
+ public void setSourceLineNumber(int lineNumber) {
+ fLineNumber = lineNumber;
+ }
+
+ /**
+ * @see IProblem
+ */
+ public void setSourceStart(int sourceStart) {
+ fStartPosition = sourceStart;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/NullProblemFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/NullProblemFactory.java
new file mode 100644
index 0000000000..1542e805cc
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/NullProblemFactory.java
@@ -0,0 +1,52 @@
+package org.eclipse.jdt.internal.core.jdom;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+
+import java.util.*;
+
+/**
+ * Implements the <code>IProblemFactory</code> interface to provide <code>NullProblem</code>s.
+ * The need for this class is dependent upon the compilers ability to accept null
+ * <code>IProblemFactory</code>s and null <code>IProblem</code>s.
+ */
+public class NullProblemFactory implements IProblemFactory {
+ /**
+ * Returns a new <code>NullProblem</code> initialized to the given info.
+ */
+ public IProblem createProblem(
+ char[] originatingFileName,
+ int problemId,
+ String[] arguments,
+ int severity,
+ int startPosition,
+ int endPosition,
+ int lineNumber) {
+ return new NullProblem(
+ originatingFileName,
+ problemId,
+ arguments,
+ severity,
+ startPosition,
+ endPosition,
+ lineNumber);
+ }
+
+ /**
+ * Returns the default locale
+ */
+ public Locale getLocale() {
+ return Locale.getDefault();
+ }
+
+ /**
+ * Answers a String representation of the problemId.
+ */
+ public String getLocalizedMessage(int problemId, String[] problemArguments) {
+ return Integer.toString(problemId);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/SiblingEnumeration.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/SiblingEnumeration.java
new file mode 100644
index 0000000000..2ebbd88f46
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/SiblingEnumeration.java
@@ -0,0 +1,52 @@
+package org.eclipse.jdt.internal.core.jdom;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.core.jdom.IDOMNode;
+
+import java.util.Enumeration;
+
+/**
+ * SiblingEnumeration provides an enumeration on a linked list
+ * of sibling DOM nodes.
+ *
+ * @see java.util.Enumeration
+ */
+
+/* package */
+class SiblingEnumeration implements Enumeration {
+
+ /**
+ * The current location in the linked list
+ * of DOM nodes.
+ */
+ protected IDOMNode fCurrentElement;
+ /**
+ * Creates an enumeration of silbings starting at the given node.
+ * If the given node is <code>null</code> the enumeration is empty.
+ */
+ SiblingEnumeration(IDOMNode child) {
+ fCurrentElement = child;
+ }
+
+ /**
+ * @see java.util.Enumeration#hasMoreElements()
+ */
+ public boolean hasMoreElements() {
+ return fCurrentElement != null;
+ }
+
+ /**
+ * @see java.util.Enumeration#nextElement()
+ */
+ public Object nextElement() {
+ IDOMNode curr = fCurrentElement;
+ if (curr != null) {
+ fCurrentElement = fCurrentElement.getNextNode();
+ }
+ return curr;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/SimpleDOMBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/SimpleDOMBuilder.java
new file mode 100644
index 0000000000..05f9977be8
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/SimpleDOMBuilder.java
@@ -0,0 +1,347 @@
+package org.eclipse.jdt.internal.core.jdom;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+import org.eclipse.jdt.core.jdom.*;
+import org.eclipse.jdt.internal.core.util.*;
+
+import java.lang.reflect.Modifier;
+import java.util.Enumeration;
+import java.util.Stack;
+
+/**
+ * A DOM builder that uses the SourceElementParser
+ */
+public class SimpleDOMBuilder
+ extends AbstractDOMBuilder
+ implements ISourceElementRequestor {
+
+ /**
+
+ */
+ public void acceptImport(
+ int declarationStart,
+ int declarationEnd,
+ char[] name,
+ boolean onDemand) {
+ int[] sourceRange = { declarationStart, declarationEnd };
+ String importName = new String(name);
+ /** name is set to contain the '*' */
+ if (onDemand) {
+ importName += ".*";
+ }
+ fNode = new DOMImport(fDocument, sourceRange, importName, onDemand);
+ addChild(fNode);
+ }
+
+ /**
+
+ */
+ public void acceptInitializer(
+ int modifiers,
+ int declarationSourceStart,
+ int declarationSourceEnd) {
+ int[] sourceRange = { declarationSourceStart, declarationSourceEnd };
+ fNode = new DOMInitializer(fDocument, sourceRange, modifiers);
+ addChild(fNode);
+ }
+
+ /**
+ */
+ public void acceptPackage(
+ int declarationStart,
+ int declarationEnd,
+ char[] name) {
+ int[] sourceRange = new int[] { declarationStart, declarationEnd };
+ fNode = new DOMPackage(fDocument, sourceRange, CharArrayOps.charToString(name));
+ addChild(fNode);
+ }
+
+ /**
+ * @see IDOMFactory#createCompilationUnit(String)
+ */
+ public IDOMCompilationUnit createCompilationUnit(
+ String sourceCode,
+ String name) {
+ return createCompilationUnit(sourceCode.toCharArray(), name.toCharArray());
+ }
+
+ /**
+ * @see IDOMFactory#createCompilationUnit(String)
+ */
+ public IDOMCompilationUnit createCompilationUnit(ICompilationUnit compilationUnit) {
+ initializeBuild(compilationUnit.getContents(), true, true);
+ getParser().parseCompilationUnit(compilationUnit, false);
+ return super.createCompilationUnit(compilationUnit);
+ }
+
+ /**
+ * Creates a new DOMMethod and inizializes.
+ *
+ * @param declarationStart - a source position corresponding to the first character
+ * of this constructor declaration
+ * @param modifiers - the modifiers for this constructor converted to a flag
+ * @param returnType - the name of the return type
+ * @param name - the name of this constructor
+ * @param nameStart - a source position corresponding to the first character of the name
+ * @param nameEnd - a source position corresponding to the last character of the name
+ * @param parameterTypes - a list of parameter type names
+ * @param parameterNames - a list of the names of the parameters
+ * @param exceptionTypes - a list of the exception types
+ */
+ protected void enterAbstractMethod(
+ int declarationStart,
+ int modifiers,
+ char[] returnType,
+ char[] name,
+ int nameStart,
+ int nameEnd,
+ char[][] parameterTypes,
+ char[][] parameterNames,
+ char[][] exceptionTypes,
+ boolean isConstructor) {
+
+ int[] sourceRange = { declarationStart, -1 }; // will be fixed up on exit
+ int[] nameRange = { nameStart, nameEnd };
+ fNode =
+ new DOMMethod(
+ fDocument,
+ sourceRange,
+ CharArrayOps.charToString(name),
+ nameRange,
+ modifiers,
+ isConstructor,
+ CharArrayOps.charToString(returnType),
+ CharArrayOps.charcharToString(parameterTypes),
+ CharArrayOps.charcharToString(parameterNames),
+ CharArrayOps.charcharToString(exceptionTypes));
+ addChild(fNode);
+ fStack.push(fNode);
+ }
+
+ /**
+ */
+ public void enterClass(
+ int declarationStart,
+ int modifiers,
+ char[] name,
+ int nameStart,
+ int nameEnd,
+ char[] superclass,
+ char[][] superinterfaces) {
+ enterType(
+ declarationStart,
+ modifiers,
+ name,
+ nameStart,
+ nameEnd,
+ superclass,
+ superinterfaces,
+ true);
+ }
+
+ /**
+ */
+ public void enterConstructor(
+ int declarationStart,
+ int modifiers,
+ char[] name,
+ int nameStart,
+ int nameEnd,
+ char[][] parameterTypes,
+ char[][] parameterNames,
+ char[][] exceptionTypes) {
+ /* see 1FVIIQZ */
+ String nameString = new String(fDocument, nameStart, nameEnd - nameStart);
+ int openParenPosition = nameString.indexOf('(');
+ if (openParenPosition > -1)
+ nameEnd = nameStart + openParenPosition - 1;
+
+ enterAbstractMethod(
+ declarationStart,
+ modifiers,
+ null,
+ name,
+ nameStart,
+ nameEnd,
+ parameterTypes,
+ parameterNames,
+ exceptionTypes,
+ true);
+ }
+
+ /**
+ */
+ public void enterField(
+ int declarationStart,
+ int modifiers,
+ char[] type,
+ char[] name,
+ int nameStart,
+ int nameEnd) {
+
+ int[] sourceRange = { declarationStart, -1 };
+ int[] nameRange = { nameStart, nameEnd };
+ boolean isSecondary = false;
+ if (fNode instanceof DOMField) {
+ isSecondary = declarationStart == fNode.fSourceRange[0];
+ }
+ fNode =
+ new DOMField(
+ fDocument,
+ sourceRange,
+ CharArrayOps.charToString(name),
+ nameRange,
+ modifiers,
+ CharArrayOps.charToString(type),
+ isSecondary);
+ addChild(fNode);
+ fStack.push(fNode);
+ }
+
+ /**
+ */
+ public void enterInterface(
+ int declarationStart,
+ int modifiers,
+ char[] name,
+ int nameStart,
+ int nameEnd,
+ char[][] superinterfaces) {
+ enterType(
+ declarationStart,
+ modifiers,
+ name,
+ nameStart,
+ nameEnd,
+ null,
+ superinterfaces,
+ false);
+ }
+
+ /**
+ */
+ public void enterMethod(
+ int declarationStart,
+ int modifiers,
+ char[] returnType,
+ char[] name,
+ int nameStart,
+ int nameEnd,
+ char[][] parameterTypes,
+ char[][] parameterNames,
+ char[][] exceptionTypes) {
+ enterAbstractMethod(
+ declarationStart,
+ modifiers,
+ null,
+ name,
+ nameStart,
+ nameEnd,
+ parameterTypes,
+ parameterNames,
+ exceptionTypes,
+ false);
+ }
+
+ /**
+ */
+ protected void enterType(
+ int declarationStart,
+ int modifiers,
+ char[] name,
+ int nameStart,
+ int nameEnd,
+ char[] superclass,
+ char[][] superinterfaces,
+ boolean isClass) {
+ if (fBuildingType) {
+ int[] sourceRange = { declarationStart, -1 }; // will be fixed in the exit
+ int[] nameRange = new int[] { nameStart, nameEnd };
+ fNode =
+ new DOMType(
+ fDocument,
+ sourceRange,
+ new String(name),
+ nameRange,
+ modifiers,
+ CharArrayOps.charcharToString(superinterfaces),
+ isClass);
+ addChild(fNode);
+ fStack.push(fNode);
+ }
+ }
+
+ /**
+ * Finishes the configuration of the class DOM object which
+ * was created by a previous enterClass call.
+ *
+ * @see ISourceElementRequestor.exitClass(...);
+ */
+ public void exitClass(int declarationEnd) {
+ exitType(declarationEnd);
+ }
+
+ /**
+ * Finishes the configuration of the method DOM object which
+ * was created by a previous enterConstructor call.
+ *
+ * @see ISourceElementRequestor.exitConstructor(...);
+ */
+ public void exitConstructor(int declarationEnd) {
+ exitMember(declarationEnd);
+ }
+
+ /**
+ */
+ public void exitField(int declarationEnd) {
+ exitMember(declarationEnd);
+ }
+
+ /**
+ */
+ public void exitInterface(int declarationEnd) {
+ exitType(declarationEnd);
+ }
+
+ /**
+ * Finishes the configuration of the member.
+ *
+ * @param declarationEnd - a source position corresponding to the end of the method
+ * declaration. This can include whitespace and comments following the closing bracket.
+ */
+ protected void exitMember(int declarationEnd) {
+ DOMMember m = (DOMMember) fStack.pop();
+ m.setSourceRangeEnd(declarationEnd);
+ fNode = m;
+ }
+
+ /**
+ */
+ public void exitMethod(int declarationEnd) {
+ exitMember(declarationEnd);
+ }
+
+ /**
+ * @see AbstractDOMBuilder#exitType
+ *
+ * @param declarationEnd - a source position corresponding to the end of the class
+ * declaration. This can include whitespace and comments following the closing bracket.
+ */
+ protected void exitType(int declarationEnd) {
+ exitType(declarationEnd, declarationEnd);
+ }
+
+ /**
+ * Creates a new parser.
+ */
+ protected SourceElementParser getParser() {
+ return new SourceElementParser(this, new NullProblemFactory());
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/lookup/ReferenceInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/lookup/ReferenceInfo.java
new file mode 100644
index 0000000000..d01827ad6a
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/lookup/ReferenceInfo.java
@@ -0,0 +1,63 @@
+package org.eclipse.jdt.internal.core.lookup;
+
+public class ReferenceInfo {
+
+ /**
+ * The reference names
+ */
+ protected char[][] fNames;
+
+ /**
+ * The reference kinds associated with each name
+ */
+ protected byte[] fKinds;
+
+ /**
+ * The kinds of references -- maskable
+ */
+ public static final byte REFTYPE_unknown = 0x01;
+ public static final byte REFTYPE_call = 0x02;
+ public static final byte REFTYPE_var = 0x04;
+ public static final byte REFTYPE_import = 0x08;
+ public static final byte REFTYPE_derive = 0x10;
+ public static final byte REFTYPE_type = 0x20;
+ public static final byte REFTYPE_class = 0x40;
+ public static final byte REFTYPE_constant = (byte) 0x80;
+ // public static final byte REFTYPE_label = 256;
+
+ /**
+ * Creates a new ReferenceInfo object. There should be one per compilation unit.
+ */
+ public ReferenceInfo(char[][] names, byte[] kinds) {
+ fNames = names;
+ fKinds = kinds;
+ }
+
+ /**
+ * Returns the reference kinds array.
+ */
+ public byte[] getKinds() {
+ return fKinds;
+ }
+
+ /**
+ * Returns the reference names array.
+ */
+ public char[][] getNames() {
+ return fNames;
+ }
+
+ /**
+ * For debugging only
+ */
+ public String toString() {
+ StringBuffer buf = new StringBuffer("ReferenceInfo(");
+ for (int i = 0; i < fNames.length; i++) {
+ buf.append(fNames[i]);
+ buf.append(" ");
+ }
+ buf.append(")");
+ return buf.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/AnonymousFileSource.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/AnonymousFileSource.java
new file mode 100644
index 0000000000..453602cf92
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/AnonymousFileSource.java
@@ -0,0 +1,134 @@
+package org.eclipse.jdt.internal.core.util;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+import java.net.*;
+
+/** An anonymous file source creates files in the given directory.
+ */
+public class AnonymousFileSource {
+ File fDirectory;
+ /**
+ * Creates an anonymous file source which creates files in the given directory.
+ */
+ public AnonymousFileSource(File directory) {
+ if (!directory.exists()) {
+ directory.mkdirs();
+ } else
+ if (!directory.isDirectory()) {
+ throw new IllegalArgumentException("Directory arguments should be a directory.");
+ }
+ fDirectory = directory;
+ }
+
+ /**
+ * Allocates and returns a RandomAccessFile in R/W mode on a new anonymous file.
+ * Guaranteed to be unallocated.
+ */
+ synchronized public RandomAccessFile allocateAnonymousFile()
+ throws IOException {
+
+ File file = getAnonymousFile();
+ return new RandomAccessFile(file, "rw");
+ }
+
+ /**
+ * Returns a URL on a newly allocated file with the given initial content.
+ * Guaranteed to be unallocated.
+ */
+ synchronized public URL allocateAnonymousURL(byte[] bytes) throws IOException {
+ try {
+ byte hasharray[] = java.security.MessageDigest.getInstance("SHA").digest(bytes);
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < hasharray.length; i++) {
+ sb.append(Character.forDigit((int) ((hasharray[i] >> 4) & 0x0F), 16));
+ sb.append(Character.forDigit((int) (hasharray[i] & 0x0F), 16));
+ }
+ sb.append(".jnk");
+ String fileName = sb.toString();
+ File file = fileForName(fileName);
+ if (!file.exists()) {
+ RandomAccessFile raf = new RandomAccessFile(file, "rw");
+ raf.write(bytes);
+ raf.close();
+ }
+ return convertFileToURL(file);
+ } catch (java.security.NoSuchAlgorithmException e) {
+ throw new IOException(e.getMessage());
+ }
+ }
+
+ /**
+ * Returns a URL using the "file" protocol corresponding to the given File.
+ */
+ static public URL convertFileToURL(File file) {
+ try {
+ String path = file.getCanonicalPath().replace(java.io.File.separatorChar, '/');
+ return new URL("file", "", "/" + path);
+ } catch (IOException ioe) {
+ throw new Error();
+ }
+ }
+
+ /**
+ * Answer a File to use for the given simple file name.
+ */
+ File fileForName(String fileName) {
+ File dir;
+ if (fileName.length() >= 1) {
+ String dirName = Integer.toHexString((fileName.hashCode() % 255) & 255);
+ dir = new File(fDirectory, dirName);
+ dir.mkdirs();
+ } else {
+ dir = fDirectory;
+ }
+ return new File(dir, fileName);
+ }
+
+ /**
+ * Returns a new anonymous file, but does not allocate it.
+ * Not guaranteed to be free when used since it is unallocated.
+ */
+ synchronized public File getAnonymousFile() {
+ File file;
+ file = fileForName(getAnonymousFileName());
+ while (file.exists()) {
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {
+ }
+ file = fileForName(getAnonymousFileName());
+ }
+ return file;
+ }
+
+ /**
+ * Returns a new anonymous file name.
+ * Not guaranteed to be free since its directory is unknown.
+ */
+ synchronized public String getAnonymousFileName() {
+ return getAnonymousFileName(System.currentTimeMillis());
+ }
+
+ /**
+ * Returns a new anonymous file name based on the given long.
+ * Not guaranteed to be free since its directory is unknown.
+ */
+ synchronized public String getAnonymousFileName(long l) {
+ if (l < 0)
+ l = -l;
+ StringBuffer sb = new StringBuffer();
+ sb.append(Character.forDigit((int) (l % 26 + 10), 36));
+ l /= 26;
+ while (l != 0) {
+ sb.append(Character.forDigit((int) (l % 36), 36));
+ l /= 36;
+ }
+ sb.append(".jnk");
+ return sb.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CharArrayBuffer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CharArrayBuffer.java
new file mode 100644
index 0000000000..8ee7839e1a
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CharArrayBuffer.java
@@ -0,0 +1,179 @@
+package org.eclipse.jdt.internal.core.util;
+
+public class CharArrayBuffer {
+ /**
+ * This is the buffer of char arrays which must be appended together
+ * during the getContents method.
+ */
+ protected char[][] fBuffer;
+
+ /**
+ * The default buffer size.
+ */
+ public static final int DEFAULT_BUFFER_SIZE = 10;
+
+ /**
+ * The end of the buffer
+ */
+ protected int fEnd;
+
+ /**
+ * The current size of the buffer.
+ */
+ protected int fSize;
+
+ /**
+ * A buffer of ranges which is maintained along with
+ * the buffer. Ranges are of the form {start, length}.
+ * Enables append(char[] array, int start, int end).
+ */
+ protected int[][] fRanges;
+ /**
+ * Creates a <code>CharArrayBuffer</code> with the default buffer size (10).
+ */
+ public CharArrayBuffer() {
+ this(null, DEFAULT_BUFFER_SIZE);
+ }
+
+ /**
+ * Creates a <code>CharArrayBuffer</code> with the default buffer size,
+ * and sets the first element in the buffer to be the given char[].
+ *
+ * @param first - the first element to be placed in the buffer, ignored if null
+ */
+ public CharArrayBuffer(char[] first) {
+ this(first, DEFAULT_BUFFER_SIZE);
+ }
+
+ /**
+ * Creates a <code>CharArrayBuffer</code> with the given buffer size,
+ * and sets the first element in the buffer to be the given char array.
+ *
+ * @param first - the first element of the buffer, ignored if null.
+ * @param size - the buffer size, if less than 1, set to the DEFAULT_BUFFER_SIZE.
+ */
+ public CharArrayBuffer(char[] first, int size) {
+ fSize = (size > 0) ? size : DEFAULT_BUFFER_SIZE;
+ fBuffer = new char[fSize][];
+ fRanges = new int[fSize][];
+ fEnd = 0;
+ if (first != null)
+ append(first, 0, first.length);
+ }
+
+ /**
+ * Creates a <code>CharArrayBuffer</code> with the given buffer size.
+ *
+ * @param size - the size of the buffer.
+ */
+ public CharArrayBuffer(int size) {
+ this(null, size);
+ }
+
+ /**
+ * Appends the entire given char array. Given for convenience.
+ *
+ * @param src - a char array which is appended to the end of the buffer.
+ */
+ public CharArrayBuffer append(char[] src) {
+ if (src != null)
+ append(src, 0, src.length);
+ return this;
+ }
+
+ /**
+ * Appends a sub array of the given array to the buffer.
+ *
+ * @param src - the next array of characters to be appended to the buffer, ignored if null
+ * @param start - the start index in the src array.
+ * @param length - the number of characters from start to be appended
+ *
+ * @throws ArrayIndexOutOfBoundsException - if arguments specify an array index out of bounds.
+ */
+ public CharArrayBuffer append(char[] src, int start, int length) {
+ if (start < 0)
+ throw new ArrayIndexOutOfBoundsException();
+ if (length < 0)
+ throw new ArrayIndexOutOfBoundsException();
+ if (src != null) {
+ int srcLength = src.length;
+ if (start > srcLength)
+ throw new ArrayIndexOutOfBoundsException();
+ if (length + start > srcLength)
+ throw new ArrayIndexOutOfBoundsException();
+ /** do length check here to allow exceptions to be thrown */
+ if (length > 0) {
+ if (fEnd == fSize) {
+ int size2 = fSize * 2;
+ System.arraycopy(fBuffer, 0, (fBuffer = new char[size2][]), 0, fSize);
+ System.arraycopy(fRanges, 0, (fRanges = new int[size2][]), 0, fSize);
+ fSize *= 2;
+ }
+ fBuffer[fEnd] = src;
+ fRanges[fEnd] = new int[] { start, length };
+ fEnd++;
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Appends the given char. Given for convenience.
+ *
+ * @param src - a char which is appended to the end of the buffer.
+ */
+ public CharArrayBuffer append(char c) {
+ append(new char[] { c }, 0, 1);
+ return this;
+ }
+
+ /**
+ * Appends the given String to the buffer. Given for convenience, use
+ * #append(char[]) if possible
+ *
+ * @param src - a char array which is appended to the end of the buffer.
+ */
+ public CharArrayBuffer append(String src) {
+ if (src != null)
+ append(src.toCharArray(), 0, src.length());
+ return this;
+ }
+
+ /**
+ * Returns the entire contents of the buffer as one
+ * char[] or null if nothing has been put in the buffer.
+ */
+ public char[] getContents() {
+ if (fEnd == 0)
+ return null;
+
+ // determine the size of the array
+ int size = 0;
+ for (int i = 0; i < fEnd; i++)
+ size += fRanges[i][1];
+
+ if (size > 0) {
+ char[] result = new char[size];
+ int current = 0;
+ // copy the results
+ for (int i = 0; i < fEnd; i++) {
+ int[] range = fRanges[i];
+ int length = range[1];
+ System.arraycopy(fBuffer[i], range[0], result, current, length);
+ current += length;
+ }
+ return result;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the contents of the buffer as a String, or
+ * <code>null</code> if the buffer is empty.
+ */
+ public String toString() {
+ char[] contents = getContents();
+ return (contents != null) ? new String(contents) : null;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CharArrayOps.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CharArrayOps.java
new file mode 100644
index 0000000000..4a883d89ba
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CharArrayOps.java
@@ -0,0 +1,138 @@
+package org.eclipse.jdt.internal.core.util;
+
+public class CharArrayOps {
+ /**
+ * Returns the char arrays as an array of Strings
+ */
+ public static String[] charcharToString(char[][] charchar) {
+ if (charchar == null) {
+ return null;
+ }
+ String[] strings = new String[charchar.length];
+ for (int i = 0; i < charchar.length; i++) {
+ strings[i] = new String(charchar[i]);
+ }
+ return strings;
+ }
+
+ /**
+ * Returns the char array as a String
+ */
+ public static String charToString(char[] chars) {
+ if (chars == null) {
+ return null;
+ } else {
+ return new String(chars);
+ }
+ }
+
+ /**
+ * Concatinates the two arrays into one big array.
+ * If the first array is null, returns the second array.
+ * If the second array is null, returns the first array.
+ *
+ * @param first - the array which the other array is concatinated onto
+ * @param second - the array which is to be concatinated onto the first array
+ */
+ public static char[] concat(char[] first, char[] second) {
+ if (first == null)
+ return second;
+ if (second == null)
+ return first;
+
+ int length1 = first.length;
+ int length2 = second.length;
+ char[] result = new char[length1 + length2];
+ System.arraycopy(first, 0, result, 0, length1);
+ System.arraycopy(second, 0, result, length1, length2);
+ return result;
+ }
+
+ /**
+ * Checks the two character arrays for equality.
+ *
+ * @param first - one of the arrays to be compared
+ * @param second - the other array which is to be compared
+ */
+ public static boolean equals(char[] first, char[] second) {
+ if (first == second)
+ return true;
+ if (first == null || second == null)
+ return false;
+ if (first.length != second.length)
+ return false;
+
+ for (int i = 0, length = first.length; i < length; i++)
+ if (first[i] != second[i])
+ return false;
+ return true;
+ }
+
+ /**
+ * Returns the index of the first occurrence of character in buffer,
+ * starting from offset, or -1 if not found.
+ */
+ public static int indexOf(char character, char[] buffer, int offset) {
+ for (int i = offset; i < buffer.length; i++) {
+ if (buffer[i] == character) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Extracts a sub-array from the given array, starting
+ * at the given startIndex and proceeding for length characters.
+ * Returns null if:
+ * 1. the src array is null
+ * 2. the start index is out of bounds
+ * 3. the length parameter specifies a end point which is out of bounds
+ * Does not return a copy of the array if possible, i.e. if start is zero
+ * and length equals the length of the src array.
+ *
+ * @param src - the array from which elements need to be copied
+ * @param start - the start index in the src array
+ * @param length - the number of characters to copy
+ */
+ public static char[] subarray(char[] src, int start, int length) {
+ if (src == null)
+ return null;
+ int srcLength = src.length;
+ if (start < 0 || start >= srcLength)
+ return null;
+ if (length < 0 || start + length > srcLength)
+ return null;
+ if (srcLength == length && start == 0)
+ return src;
+
+ char[] result = new char[length];
+ if (length > 0)
+ System.arraycopy(src, start, result, 0, length);
+ return result;
+ }
+
+ /**
+ * Extracts a substring from the given array, starting
+ * at the given startIndex and proceeding for length characters.
+ * Returns null if:
+ * 1. the src array is null
+ * 2. the start index is out of bounds
+ * 3. the length parameter specifies a end point which is out of bounds
+ * Does not return a copy of the array if possible, i.e. if start is zero
+ * and length equals the length of the src array.
+ *
+ * @param src - the array from which elements need to be copied
+ * @param start - the start index in the src array
+ * @param length - the number of characters to copy
+ */
+ public static String substring(char[] src, int start, int length) {
+ char[] chars = subarray(src, start, length);
+ if (chars != null) {
+ return new String(chars);
+ } else {
+ return null;
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DiskCache.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DiskCache.java
new file mode 100644
index 0000000000..c97ce31b08
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DiskCache.java
@@ -0,0 +1,793 @@
+package org.eclipse.jdt.internal.core.util;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+import java.util.*;
+
+/**
+ * A <code>DiskCache</code> is an on-disk cache of files with a configurable maximum size.
+ * It implements a Least-Recently-Used (LRU) policy.
+ * <p>
+ * Entries are keyed by string. The storage for an entry is written to a stream when an
+ * entry is added, but the size of the entry must be known a-priori.
+ * Extra information can optionally be associated with an entry.
+ * <p>
+ * Volatile state in the cache is saved periodically. The interval between saves can be
+ * set using <code>setPeriodicSaveInterval(int)</code>.
+ * <p>
+ * The disk cache must be explicitly closed using <code>close()</code> when it is no longer needed.
+ */
+public class DiskCache {
+
+ /**
+ * The directory containing the cache's files.
+ */
+ File fDirectory;
+
+ /**
+ * Max size of the cache in K.
+ */
+ int fSpaceLimit;
+
+ /**
+ * Used for creating cache entry files.
+ */
+ AnonymousFileSource fFileSource;
+
+ /**
+ * List of files to be deleted later, due to failures to delete
+ * or because file is still open.
+ */
+ Vector fFilesToBeDeleted = new Vector();
+
+ /**
+ * Extends the LRU cache entry to add extra fields needed by disk cache.
+ * We could avoided overriding the cache entry class by creating another object
+ * to hold these fields in the value field of a normal cache entry, but this way
+ * uses fewer objects.
+ * It is static because it doesn't require an outer instance.
+ */
+ protected static class Entry extends LRUCache.LRUCacheEntry {
+
+ long fLastAccess;
+ byte[] fExtraInfo;
+ int fFlags;
+ static final int F_COMPLETE = 1;
+
+ Entry(
+ String key,
+ int size,
+ String fileName,
+ long lastAccess,
+ byte[] extraInfo,
+ int flags) {
+ // use super's key, value and space fields for our key, fileName and size.
+ super(key, fileName, size);
+ fLastAccess = lastAccess;
+ fExtraInfo = extraInfo;
+ fFlags = flags;
+ }
+
+ DiskCacheEntry asDiskCacheEntry() {
+ return new DiskCacheEntry(
+ (String) _fKey,
+ _fSpace,
+ (String) _fValue,
+ fLastAccess,
+ fExtraInfo);
+ }
+ }
+
+ /**
+ * The maximum size of the cache, in number of K.
+ */
+ protected class EntryCache extends LRUCache {
+
+ /**
+ * Add a new entry.
+ */
+ void add(Entry entry) {
+ removeKey(entry._fKey);
+ makeSpace(entry._fSpace);
+ privateAddEntry(entry, false);
+ }
+
+ /**
+ * An item is being removed from the cache. Delete its file.
+ */
+ protected void privateNotifyDeletionFromCache(LRUCacheEntry entry) {
+ String fileName = (String) entry._fValue;
+ if ((((Entry) entry).fFlags & Entry.F_COMPLETE) != 0) {
+ /* Entry has been complete written, so we can delete it. */
+ boolean success = deleteFile(fileName);
+ if (success)
+ return;
+ /* If success == false, then it is inconsistent with the flag's
+ * F_COMPLETE mask. Something is wrong. */
+ }
+ /* Otherwise, or if file deletion failed (probably due to
+ * a stream on it still being open), mark the file for deletion later
+ * (at save or reload time) checking again to see if it's closed. */
+ rememberToDelete(fileName);
+ }
+
+ /**
+ * Lookup an entry. Expose the Entry object.
+ */
+ Entry get(String key) {
+ Entry entry = (Entry) fEntryTable.get(key);
+ if (entry == null) {
+ return null;
+ }
+ updateTimestamp(entry);
+ return entry;
+ }
+
+ /**
+ * Remove an entry. Return it if present.
+ */
+ Entry removeKey(String key) {
+ Entry entry = (Entry) fEntryTable.get(key);
+ if (entry == null) {
+ return null;
+ }
+ this.privateRemoveEntry(entry, false);
+ return entry;
+ }
+
+ /**
+ * Updates the timestamp for the given entry, ensuring that the queue is
+ * kept in correct order. The entry must exist
+ */
+ protected void updateTimestamp(LRUCacheEntry entry) {
+ ((Entry) entry).fLastAccess = System.currentTimeMillis();
+ super.updateTimestamp(entry);
+ }
+
+ /**
+ * Return the number of entries.
+ */
+ int getNumEntries() {
+ return fEntryTable.size();
+ }
+
+ /**
+ * Return an enumeration of the Entry objects in the cache
+ * in most-recently- to least-recently-used order.
+ */
+ public Enumeration getEntries() {
+ return new Enumeration() {
+
+ Entry current = (Entry) fEntryQueue;
+
+ public boolean hasMoreElements() {
+ return current != null;
+ }
+
+ public Object nextElement() {
+ if (current == null) {
+ throw new NoSuchElementException();
+ }
+ Entry result = current;
+ current = (Entry) current._fNext;
+ return result;
+ }
+ };
+ }
+ }
+
+ EntryCache fEntryCache;
+
+ static final String CONTENTS_FILE_NAME = "contents";
+ static final String TEMP_CONTENTS_FILE_NAME = "tempcont";
+ static final String CONTENTS_VERSION = "DiskCache.V1.0";
+
+ /**
+ * Set to true when cache is modified, cleared when saved.
+ */
+ boolean fIsDirty = false;
+
+ /**
+ * Thread for doing periodic saves. Created only if needed.
+ */
+ Thread fPeriodicSaveThread;
+
+ /**
+ * Interval for periodic save checks, in ms. 5 sec by default.
+ */
+ int fPeriodicSaveInterval = 60000;
+
+ /**
+ * Create a disk cache which uses the given filesystem directory
+ * and has the given space limit (in kilobytes).
+ */
+ public DiskCache(File directory, int spaceLimit) {
+ fDirectory = directory;
+ fFileSource = new AnonymousFileSource(directory);
+ fSpaceLimit = spaceLimit;
+ createEntryCache();
+ try {
+ read();
+ deleteFilesToBeDeleted();
+ } catch (IOException e) {
+ }
+ }
+
+ /**
+ * Add an entry to the cache. The size of the entry in bytes must be given.
+ * Extra information in the form of a byte array may optionally be associated
+ * with the entry (pass null if no extra info is needed).
+ * Returns an initially empty OutputStream to which the contents of the entry
+ * should be written immediately following this operation.
+ *
+ * @throws IOException if a file for the entry's contents could not be created
+ */
+ public OutputStream add(final String key, int size, byte[] extraInfo)
+ throws IOException {
+ if (size > fSpaceLimit * 1024) {
+ throw new IOException("Entry size greater than cache size");
+ }
+ final File file;
+ OutputStream output;
+ // Allocate the file first. If errors occur, no entry is added.
+ synchronized (fFileSource) {
+ file = fFileSource.getAnonymousFile();
+ output = new FileOutputStream(file);
+ }
+ long lastAccess = System.currentTimeMillis();
+ if (extraInfo != null && extraInfo.length == 0) {
+ extraInfo = null;
+ }
+ final Entry entry =
+ new Entry(key, size, file.getName(), lastAccess, extraInfo, 0);
+ synchronized (fEntryCache) {
+ // Only use the simple file name.
+ fEntryCache.add(entry);
+ }
+
+ // Mark as modified here, as well as when the entry is complete.
+ // Hopefully the content is received before the periodic save interval,
+ // so state is saved at most once for this entry.
+ modified();
+
+ // Return a filter stream which sets the complete flag when the stream is closed.
+ return new FilterOutputStream(output) {
+ public void write(byte b[], int off, int len) throws IOException {
+ out.write(b, off, len);
+ }
+
+ private void closeHelper() throws IOException {
+ super.close();
+ // Ensure entry is still valid.
+ // It may have been removed or replaced in the interim.
+ synchronized (fEntryCache) {
+ if (fEntryCache.get(key) != entry) {
+ String fileName = (String) entry._fValue;
+ boolean success = deleteFile(fileName);
+ if (!success) {
+ rememberToDelete(fileName);
+ }
+ }
+ }
+ modified();
+ }
+
+ public void close() throws IOException {
+ entry.fFlags |= Entry.F_COMPLETE;
+ closeHelper();
+ }
+
+ public void finalize() throws Throwable {
+ closeHelper();
+ super.finalize();
+ }
+
+ /* For debugging/testing ONLY. Do not use outside of test suites.*/
+ public String toString() {
+ return file.toString();
+ }
+ };
+ }
+
+ /**
+ * Clear the cache. All entries are removed and their associated files are deleted.
+ */
+ public void clearCache() {
+ synchronized (fEntryCache) {
+ fEntryCache.flush();
+ }
+ // Be sure to save the cleared contents.
+ modified();
+ }
+
+ /**
+ * Close the cache.
+ * Flush incomplete entries, save volatile state if needed, and halt periodic saves.
+ */
+ public synchronized void close() {
+ if (fIsDirty || flushIncompleteEntries()) {
+ try {
+ save();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ Thread thread = fPeriodicSaveThread;
+ if (thread != null) {
+ fPeriodicSaveThread = null;
+ // Interrupt its sleep.
+ thread.interrupt();
+ }
+ }
+
+ /**
+ * Internal - (Re)create the internal entry cache.
+ */
+ protected void createEntryCache() {
+ fEntryCache = new EntryCache();
+ fEntryCache.setSpaceLimit(fSpaceLimit * 1024);
+ }
+
+ /**
+ * Internal - Delete the file for an entry. Returns the
+ * "success flag" result from java.io.File's delete().
+ */
+ protected boolean deleteFile(String fileName) {
+ File fileToDelete = fFileSource.fileForName(fileName);
+ fileToDelete.delete();
+ // Could have already been deleted.
+ boolean success = !fileToDelete.exists();
+ if (success && fFilesToBeDeleted.contains(fileName))
+ fFilesToBeDeleted.removeElement(fileName);
+ return success;
+ }
+
+ /**
+ * Internal - Deletes the files that have been flagged for deletion. Returns
+ * the number of flagged files that remain undeleted.
+ */
+ public int deleteFilesToBeDeleted() {
+ synchronized (fFilesToBeDeleted) {
+ Vector clone = (Vector) fFilesToBeDeleted.clone();
+ Enumeration e = clone.elements();
+ while (e.hasMoreElements()) {
+ String fileName = (String) e.nextElement();
+ boolean success = deleteFile(fileName);
+ if (success)
+ fFilesToBeDeleted.removeElement(fileName);
+ }
+ return fFilesToBeDeleted.size();
+ }
+ }
+
+ /**
+ * Flush all incomplete entries from the cache.
+ * Returns true if some were flushed.
+ */
+ protected boolean flushIncompleteEntries() {
+ Vector v = new Vector();
+ for (Enumeration e = fEntryCache.getEntries(); e.hasMoreElements();) {
+ Entry entry = (Entry) e.nextElement();
+ if ((entry.fFlags & Entry.F_COMPLETE) == 0) {
+ v.addElement(entry._fKey);
+ }
+ }
+ for (int i = 0, size = v.size(); i < size; ++i) {
+ fEntryCache.removeKey((String) v.elementAt(i));
+ }
+ return v.size() > 0;
+ }
+
+ /**
+ * Returns the directory which holds the cache.
+ */
+ public File getDirectory() {
+ return fDirectory;
+ }
+
+ /**
+ * For debugging/testing purposes.
+ */
+ public int getNumberOfFilesToBeDeleted() {
+ return fFilesToBeDeleted.size();
+ }
+
+ /**
+ * Return the number of entries in the cache.
+ */
+ public int getNumEntries() {
+ return fEntryCache.getNumEntries();
+ }
+
+ /**
+ * Returns the delay in milliseconds between periodic saves.
+ */
+ public int getPeriodicSaveInterval() {
+ return fPeriodicSaveInterval;
+ }
+
+ /**
+ * Returns the space limit of the cache, in Kilobytes.
+ */
+ public int getSpaceLimit() {
+ return fSpaceLimit;
+ }
+
+ /**
+ * Returns the space used by the cache, in Kilobytes.
+ */
+ public int getSpaceUsed() {
+ synchronized (fEntryCache) {
+ return (fEntryCache.getCurrentSpace() + 1023) / 1024; // Take ceiling.
+ }
+ }
+
+ /**
+ * Returns an enumeration on the keys (Strings)
+ * of the entries in the cache.
+ */
+ public Enumeration keys() {
+ return fEntryCache.keys();
+ }
+
+ /**
+ * Look up an entry in the cache. Answer the entry if found, or null if not found.
+ * If the contents are to be retrieved, use the <code>open</code> method rather than
+ * directly referring to the file using the returned file name.
+ *
+ * @see DiskCache#open
+ */
+ public DiskCacheEntry lookup(String key) {
+ Entry entry;
+ synchronized (fEntryCache) {
+ entry = fEntryCache.get(key);
+ }
+ if (entry == null || (entry.fFlags & Entry.F_COMPLETE) == 0) {
+ return null;
+ } else {
+ // If the entry was found, then the contents should be
+ // resaved because the order of items in it has changed.
+ modified();
+ return entry.asDiskCacheEntry();
+ }
+ }
+
+ /**
+ * Internal - The cache has been modified. Remember to save the state.
+ * Method is synchronized to protect fPeriodicSaveThread from concurrent access.
+ */
+ protected synchronized void modified() {
+ fIsDirty = true;
+ if (fPeriodicSaveThread == null || !fPeriodicSaveThread.isAlive()) {
+ startPeriodicSaveThread();
+ }
+ }
+
+ /**
+ * Open an input stream on the contents of the given entry.
+ * The passed entry must be the result of a previous lookup operation.
+ * If the cache has been modified since the lookup operation, and the entry
+ * entry has since been flushed from the cache, this operation will fail.
+ *
+ * @throws FileNotFoundException if the entry is no longer in the cache
+ */
+ public InputStream open(DiskCacheEntry entry) throws FileNotFoundException {
+ final String key = entry.getKey();
+ final String fileName = entry.getFileName();
+
+ // Has the entry been removed or replaced since the lookup was done?
+ final Entry finalEntry = fEntryCache.get(key);
+ if (finalEntry == null || !fileName.equals((String) finalEntry._fValue)) {
+ throw new FileNotFoundException();
+ }
+
+ final File file = fFileSource.fileForName(fileName);
+
+ class DiskCachePrivateFileInputStream extends FileInputStream {
+ DiskCachePrivateFileInputStream(File file) throws FileNotFoundException {
+ super(file);
+ }
+ public void close() throws IOException {
+ super.close();
+ // Ensure entry is still valid.
+ // It may have been removed or replaced in the interim.
+ synchronized (fEntryCache) {
+ if (fEntryCache.get(key) != finalEntry) {
+ boolean success = deleteFile(fileName);
+ if (!success) {
+ rememberToDelete(fileName);
+ }
+ }
+ }
+ modified();
+ }
+ protected void finalize() throws IOException {
+ close();
+ super.finalize();
+ }
+ /* For debugging/testing ONLY. Do not use outside of test suites.*/
+ public String toString() {
+ return file.toString();
+ }
+ };
+ try {
+ return new DiskCachePrivateFileInputStream(file);
+ } catch (FileNotFoundException e) {
+ // If there's an error while opening the file,
+ // delete the entry and the file from the cache.
+ remove(key);
+
+ // Propagate the exception
+ throw e;
+ }
+ }
+
+ /**
+ * Read the cache state from persistent storage.
+ * Any undeleted entry files left at the last save the cach now tries to delete.
+ */
+ public void read() throws IOException {
+ File file = new File(fDirectory, CONTENTS_FILE_NAME);
+ if (!file.exists()) {
+ return;
+ }
+ DataInputStream in =
+ new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
+ try {
+ String sig = in.readUTF();
+ int spaceLimit = in.readInt(); /* Ignored -- use current limit */
+ int spaceUsed = in.readInt(); /* Ignored -- updated as entries are read */
+ int numEntries = in.readInt();
+ if (!sig.equals(CONTENTS_VERSION)) {
+ throw new IOException("Invalid format");
+ }
+
+ /* Read to a temp. array of entries. The entries are in most- to
+ * least-recently used order. */
+ Entry[] entries = new Entry[numEntries];
+ for (int i = 0; i < numEntries; ++i) {
+ entries[i] = readEntry(in);
+ }
+
+ createEntryCache();
+ /* Add entries in least- to most-recently used order, so that the order in
+ * the new cache is preserved. */
+ for (int i = numEntries - 1; i >= 0; --i) {
+ fEntryCache.add(entries[i]);
+ }
+
+ /* Read in names of files to be deleted. */
+ /* But first, check that we are not at the end of the file (which occurs
+ * in pre-existing file formats). Try reading an int to find this out. */
+ boolean moreToRead = false;
+ int numFilesToBeDeleted = -1;
+ try {
+ numFilesToBeDeleted = in.readInt();
+ moreToRead = true;
+ } catch (IOException ignoreMe) {
+ /* We're at the end of file, so it's a pre-existing format. */
+ }
+ if (moreToRead) {
+ fFilesToBeDeleted = new Vector();
+ for (int i = 0; i < numFilesToBeDeleted; i++) {
+ String fileName = in.readUTF();
+ fFilesToBeDeleted.addElement(fileName);
+ }
+ }
+
+ } finally {
+ in.close();
+ }
+ }
+
+ /**
+ * Internal - Read an entry from a stream. Returns an internal cache Entry.
+ */
+ protected Entry readEntry(DataInputStream in) throws IOException {
+ String key = in.readUTF();
+ int size = in.readInt();
+ String fileName = in.readUTF();
+ long lastAccess = in.readLong();
+ int flags = in.readInt();
+ byte[] extraInfo = null;
+ int extraLen = in.readInt();
+ if (extraLen > 0) {
+ extraInfo = new byte[extraLen];
+ in.readFully(extraInfo);
+ }
+ return new Entry(key, size, fileName, lastAccess, extraInfo, flags);
+ }
+
+ /**
+ * Internal - Remember to delete a file later.
+ */
+ protected void rememberToDelete(String fileName) {
+ if (!fFilesToBeDeleted.contains(fileName))
+ fFilesToBeDeleted.addElement(fileName);
+ }
+
+ /**
+ * Remove an entry from the cache and delete its contents.
+ * Answer the entry if found, or null if not found.
+ */
+ public DiskCacheEntry remove(String key) {
+ Entry entry;
+ synchronized (fEntryCache) {
+ entry = fEntryCache.removeKey(key);
+ }
+ if (entry == null) {
+ return null;
+ } else {
+ modified();
+ return entry.asDiskCacheEntry();
+ }
+ }
+
+ public synchronized void removeAll(Vector keys) {
+ Enumeration enum = keys.elements();
+ while (enum.hasMoreElements()) {
+ String key = (String) enum.nextElement();
+ remove(key);
+ }
+ }
+
+ /**
+ * Renames an entry in the cache.
+ * Returns true if the rename succeeded, false otherwise.
+ */
+ public boolean rename(String oldKey, String newKey) {
+ long lastAccess = System.currentTimeMillis();
+ synchronized (fEntryCache) {
+ Entry oldEntry = (Entry) fEntryCache.get(oldKey);
+ if (oldEntry == null) {
+ return false;
+ } else {
+ Entry newEntry =
+ new Entry(
+ newKey,
+ oldEntry._fSpace,
+ (String) oldEntry._fValue,
+ lastAccess,
+ oldEntry.fExtraInfo,
+ oldEntry.fFlags);
+ fEntryCache.add(newEntry);
+ }
+ }
+ modified();
+ return true;
+ }
+
+ /**
+ * Save all in-memory cache state to persistent storage.
+ * Tries to deleted undeleted entry files.
+ */
+ public synchronized void save() throws IOException {
+
+ /* Try deleting "files to be deleted". */
+ deleteFilesToBeDeleted();
+
+ /*
+ * Write the table of contents to a temporary file,
+ * rather than the actual file, to be more resilient in
+ * the face of errors such as disk full.
+ */
+ File tempFile = new File(fDirectory, TEMP_CONTENTS_FILE_NAME);
+ DataOutputStream out =
+ new DataOutputStream(new BufferedOutputStream(new FileOutputStream(tempFile)));
+ boolean ok = false;
+ try {
+ synchronized (fEntryCache) {
+ out.writeUTF(CONTENTS_VERSION);
+ out.writeInt(getSpaceLimit());
+ out.writeInt(getSpaceUsed());
+ int numEntries = fEntryCache.getNumEntries();
+ out.writeInt(numEntries);
+ for (Enumeration e = fEntryCache.getEntries(); e.hasMoreElements();) {
+ Entry entry = (Entry) e.nextElement();
+ writeEntry(entry, out);
+ }
+ int numFilesToBeDeleted = fFilesToBeDeleted.size();
+ out.writeInt(numFilesToBeDeleted);
+ Enumeration e = fFilesToBeDeleted.elements();
+ while (e.hasMoreElements()) {
+ String fileName = (String) e.nextElement();
+ out.writeUTF(fileName);
+ }
+ }
+ out.close();
+
+ /* Replace the old TOC (if any) with the temp file */
+ File contentsFile = new File(fDirectory, CONTENTS_FILE_NAME);
+ contentsFile.delete();
+ if (tempFile.renameTo(contentsFile)) {
+ ok = true;
+ fIsDirty = false;
+ }
+ } finally {
+ if (!ok) {
+ out.close();
+ tempFile.delete();
+ }
+ }
+ }
+
+ /**
+ * Sets the delay in milliseconds between periodic saves.
+ */
+ public void setPeriodicSaveInterval(int interval) {
+ fPeriodicSaveInterval = interval;
+ }
+
+ /**
+ * Sets the space limit of the cache, in Kilobytes.
+ */
+ public void setSpaceLimit(int limit) {
+ fSpaceLimit = limit;
+ synchronized (fEntryCache) {
+ fEntryCache.setSpaceLimit(limit * 1024);
+ }
+ }
+
+ /**
+ * Internal -
+ * Create and start a thread which checks every so often whether
+ * the cache needs to be saved.
+ * The thread should only run while there are modifications.
+ */
+ protected void startPeriodicSaveThread() {
+
+ fPeriodicSaveThread = new Thread() {
+ public void run() {
+ try {
+ Thread.sleep(fPeriodicSaveInterval);
+ } catch (InterruptedException e) {
+ }
+ for (;;) {
+ synchronized (DiskCache.this) {
+ if (fIsDirty) {
+ try {
+ save(); // clears dirty flag
+ } catch (IOException e) {
+ // Ignore
+ }
+ } else {
+ // drop ref to thread and terminate
+ fPeriodicSaveThread = null;
+ return;
+ }
+ }
+ try {
+ Thread.sleep(fPeriodicSaveInterval);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ };
+ fPeriodicSaveThread.setName("DiskCache periodic save");
+ fPeriodicSaveThread.start();
+
+ }
+
+ /**
+ * Internal - Write an internal cache Entry to a stream.
+ */
+ protected void writeEntry(Entry entry, DataOutputStream out)
+ throws IOException {
+ out.writeUTF((String) entry._fKey);
+ out.writeInt(entry._fSpace);
+ out.writeUTF((String) entry._fValue); // fileName
+ out.writeLong(entry.fLastAccess);
+ out.writeInt(entry.fFlags);
+ byte[] extraInfo = entry.fExtraInfo;
+ if (extraInfo == null) {
+ out.writeInt(0);
+ } else {
+ out.writeInt(extraInfo.length);
+ out.write(extraInfo);
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DiskCacheEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DiskCacheEntry.java
new file mode 100644
index 0000000000..16891ac971
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DiskCacheEntry.java
@@ -0,0 +1,66 @@
+package org.eclipse.jdt.internal.core.util;
+
+public class DiskCacheEntry {
+ String fKey;
+ int fSize;
+ String fFileName;
+ long fLastAccess;
+ byte[] fExtraInfo;
+ /**
+ * Create an entry.
+ */
+ DiskCacheEntry(
+ String key,
+ int size,
+ String fileName,
+ long lastAccess,
+ byte[] extraInfo) {
+ fKey = key;
+ fSize = size;
+ fFileName = fileName;
+ fLastAccess = lastAccess;
+ fExtraInfo = extraInfo;
+ }
+
+ /**
+ * Returns the extra info associated with this entry,
+ * or null if there is no extra info.
+ */
+ public byte[] getExtraInfo() {
+ return fExtraInfo;
+ }
+
+ /**
+ * Returns the file name of the entry.
+ * This name is assigned by the cache and is, strictly speaking,
+ * part of its internal representation. It is included in the API
+ * since a client may want to expose the file name for an element.
+ */
+ public String getFileName() {
+ return fFileName;
+ }
+
+ /**
+ * Returns the key for this entry.
+ * The key was used to look up this entry.
+ */
+ public String getKey() {
+ return fKey;
+ }
+
+ /**
+ * Returns the time that this entry was last accessed,
+ * in milliseconds since Jan 1, 1970.
+ */
+ public long getLastAccess() {
+ return fLastAccess;
+ }
+
+ /**
+ * Returns the size of the entry in bytes.
+ */
+ public int getSize() {
+ return fSize;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Dumper.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Dumper.java
new file mode 100644
index 0000000000..bbbed933ad
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Dumper.java
@@ -0,0 +1,319 @@
+package org.eclipse.jdt.internal.core.util;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+
+/**
+ * A dumper knows how to dump objects in a human-readable representation to a PrintWriter.
+ * Objects which implement IDumpable know how to dump themselves to a Dumper, otherwise
+ * the dumper just uses toString() on the object.
+ * Example:
+ * <pre>
+ * Dumper dumper = new Dumper(System.out);
+ * dumper.dump(myObject);
+ * dumper.flush();
+ * </pre>
+ *
+ * @see IDumpable
+ * @see PrintWriter
+ */
+public class Dumper {
+ int fTabLevel = 0;
+ PrintWriter fWriter;
+ /**
+ * Creates a dumper which sends output to System.out.
+ */
+ public Dumper() {
+ this(System.out);
+ }
+
+ /**
+ * Creates a dumper which sends output to the given OutputStream.
+ */
+ public Dumper(OutputStream out) {
+ this(new PrintWriter(out));
+ }
+
+ /**
+ * Creates a dumper which sends output to the given PrintWriter.
+ */
+ public Dumper(PrintWriter writer) {
+ fWriter = writer;
+ }
+
+ /**
+ * Returns the class name to use for the given object.
+ */
+ String classNameFor(Object val) {
+ String name = val.getClass().getName();
+ int i = name.lastIndexOf('.');
+ if (i != -1) {
+ name = name.substring(i + 1);
+ }
+ return name;
+ }
+
+ /**
+ * Dumps the given array.
+ * Prints a maximum of maxPerLine items per line.
+ */
+ public void dump(int[] val, int maxPerLine) {
+ int len = val.length;
+ boolean oneLine = (len <= maxPerLine);
+ if (!oneLine) {
+ ++fTabLevel;
+ }
+ fWriter.print("[");
+ for (int i = 0; i < len; ++i) {
+ if (!oneLine) {
+ if ((i % maxPerLine) == 0) {
+ fWriter.println();
+ tabIfNeeded();
+ fWriter.print(i);
+ fWriter.print(": ");
+ }
+ }
+ fWriter.print(val[i]);
+ if (i + 1 < len) {
+ fWriter.print(", ");
+ }
+ }
+ if (oneLine) {
+ fWriter.print("]");
+ fWriter.println();
+ } else {
+ fWriter.println();
+ --fTabLevel;
+ tabIfNeeded();
+ fWriter.print("]");
+ fWriter.println();
+ }
+ }
+
+ /**
+ * Dumps the given array.
+ */
+ public void dump(Object[] val) {
+ int len = val.length;
+ fWriter.print("[");
+ if (len > 0) {
+ fWriter.println();
+ ++fTabLevel;
+ for (int i = 0; i < len; ++i) {
+ dump(val[i]);
+ }
+ --fTabLevel;
+ tabIfNeeded();
+ }
+ fWriter.println("]");
+ }
+
+ /**
+ * Dumps the given array.
+ * Prints a maximum of maxPerLine items per line.
+ */
+ public void dump(String[] val, int maxPerLine) {
+ int len = val.length;
+ boolean oneLine = (len <= maxPerLine);
+ if (!oneLine) {
+ ++fTabLevel;
+ }
+ fWriter.print("[");
+ boolean newLine = !oneLine;
+ for (int i = 0; i < len; ++i) {
+ if (newLine) {
+ fWriter.println();
+ tabIfNeeded();
+ }
+ fWriter.print("\"" + val[i] + "\"");
+ if (i + 1 < len) {
+ fWriter.print(", ");
+ }
+ newLine = (i != 0 && (i % maxPerLine) == 0);
+ }
+ fWriter.print("]");
+ if (oneLine || newLine) {
+ fWriter.println();
+ }
+ if (!oneLine) {
+ --fTabLevel;
+ }
+ }
+
+ /**
+ * Dumps the given value.
+ */
+ public void dump(Object val) {
+ tabIfNeeded();
+ if (val instanceof IDumpable) {
+ IDumpable dumpable = (IDumpable) val;
+ fWriter.println(classNameFor(val) + " {");
+ int originalLevel = fTabLevel;
+ ++fTabLevel;
+ try {
+ dumpable.dump(this);
+ } catch (Throwable t) {
+ fWriter.println("*ERR*");
+ }
+ fTabLevel = originalLevel;
+ tabIfNeeded();
+ fWriter.println("}");
+ } else {
+ fWriter.println(val);
+ }
+ }
+
+ /**
+ * Dumps the given value, with the given name as a prefix.
+ */
+ public void dump(String name, int[] val) {
+ dump(name, val, 10);
+ }
+
+ /**
+ * Dumps the given array, with the given name as a prefix.
+ * Prints a maximum of maxPerLine items per line.
+ */
+ public void dump(String name, int[] val, int maxPerLine) {
+ prefix(name);
+ dump(val, maxPerLine);
+ }
+
+ /**
+ * Dumps the given value, with the given name as a prefix.
+ */
+ public void dump(String name, Object[] val) {
+ prefix(name);
+ dump(val);
+ }
+
+ /**
+ * Dumps the given value, with the given name as a prefix.
+ */
+ public void dump(String name, String[] val) {
+ prefix(name);
+ dump(val, 5);
+ }
+
+ /**
+ * Dumps the given value, with the given name as a prefix.
+ */
+ public void dump(String name, int val) {
+ prefix(name);
+ fWriter.println(val);
+ }
+
+ /**
+ * Dumps the given value, with the given name as a prefix.
+ */
+ public void dump(String name, Object val) {
+ prefix(name);
+ fWriter.println();
+ ++fTabLevel;
+ dump(val);
+ --fTabLevel;
+ }
+
+ /**
+ * Dumps the given value, with the given name as a prefix.
+ */
+ public void dump(String name, String val) {
+ prefix(name);
+ fWriter.println(val == null ? "null" : "\"" + val + "\"");
+ }
+
+ /**
+ * Dumps the given value, with the given name as a prefix.
+ */
+ public void dump(String name, boolean val) {
+ prefix(name);
+ fWriter.println(val);
+ }
+
+ /**
+ * Dumps the given message, with the given name as a prefix.
+ */
+ public void dumpMessage(String name, String msg) {
+ prefix(name);
+ fWriter.println(msg);
+ }
+
+ /**
+ * Flushes the output writer.
+ */
+ public void flush() {
+ fWriter.flush();
+ }
+
+ /**
+ * Returns the current tab level.
+ */
+ public int getTabLevel() {
+ return fTabLevel;
+ }
+
+ /**
+ * Returns the underlying PrintWriter.
+ */
+ public PrintWriter getWriter() {
+ return fWriter;
+ }
+
+ /**
+ * Increase the current tab level.
+ */
+ public void indent() {
+ ++fTabLevel;
+ }
+
+ /**
+ * Decrease the current tab level.
+ */
+ public void outdent() {
+ if (--fTabLevel < 0)
+ fTabLevel = 0;
+ }
+
+ /**
+ * Outputs the given prefix, tabbing first if needed.
+ */
+ void prefix(String name) {
+ tabIfNeeded();
+ fWriter.print(name);
+ fWriter.print(": ");
+ }
+
+ /**
+ * Print an object directly, without a newline.
+ */
+ public void print(Object obj) {
+ fWriter.print(obj);
+ }
+
+ /**
+ * Print a newline directly.
+ */
+ public void println() {
+ fWriter.println();
+ }
+
+ /**
+ * Print an object directly, with a newline.
+ */
+ public void println(Object obj) {
+ fWriter.println(obj);
+ }
+
+ /**
+ * Outputs tabs if needed.
+ */
+ void tabIfNeeded() {
+ for (int i = 0; i < fTabLevel; ++i) {
+ fWriter.print(" ");
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HackFinder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HackFinder.java
new file mode 100644
index 0000000000..13b616559c
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HackFinder.java
@@ -0,0 +1,16 @@
+package org.eclipse.jdt.internal.core.util;
+
+public class HackFinder {
+ /**
+ * Find stuff to revisit.
+ */
+ public static void fixMeLater(String arg) {
+ }
+
+ /**
+ * Find stuff to revisit.
+ */
+ public static void fixMeSoon(String arg) {
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ICacheEnumeration.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ICacheEnumeration.java
new file mode 100644
index 0000000000..9d5eacf9c7
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ICacheEnumeration.java
@@ -0,0 +1,33 @@
+package org.eclipse.jdt.internal.core.util;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.Enumeration;
+
+/**
+ * The <code>ICacheEnumeration</code> is used to iterate over both the keys
+ * and values in an LRUCache. The <code>getValue()</code> method returns the
+ * value of the last key to be retrieved using <code>nextElement()</code>.
+ * The <code>nextElement()</code> method must be called before the
+ * <code>getValue()</code> method.
+ *
+ * <p>The iteration can be made efficient by making use of the fact that values in
+ * the cache (instances of <code>LRUCacheEntry</code>), know their key. For this reason,
+ * Hashtable lookups don't have to be made at each step of the iteration.
+ *
+ * <p>Modifications to the cache must not be performed while using the
+ * enumeration. Doing so will lead to an illegal state.
+ *
+ * @see LRUCache
+ */
+public interface ICacheEnumeration extends Enumeration {
+ /**
+ * Returns the value of the previously accessed key in the enumeration.
+ * Must be called after a call to nextElement().
+ *
+ * @return Value of current cache entry
+ */
+ public Object getValue();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/IComparator.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/IComparator.java
new file mode 100644
index 0000000000..80b583db40
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/IComparator.java
@@ -0,0 +1,9 @@
+package org.eclipse.jdt.internal.core.util;
+
+public interface IComparator {
+ /**
+ * Returns an integer < 0 if o1 is less than o2, > 0 if o1 is greater
+ * than o2, and 0 if o1 equals o2.
+ */
+ int compare(Object o1, Object o2);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/IDumpable.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/IDumpable.java
new file mode 100644
index 0000000000..a6736eaa76
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/IDumpable.java
@@ -0,0 +1,21 @@
+package org.eclipse.jdt.internal.core.util;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+
+/**
+ * An interface useful for debugging.
+ * Implementors know how to dump their internal state in a human-readable way
+ * to a Dumper.
+ *
+ * @see Dumper
+ */
+public interface IDumpable {
+ /**
+ * Dumps the internal state of this object in a human-readable way.
+ */
+ public void dump(Dumper dumper);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ILRUCacheable.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ILRUCacheable.java
new file mode 100644
index 0000000000..e73634a8c7
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ILRUCacheable.java
@@ -0,0 +1,11 @@
+package org.eclipse.jdt.internal.core.util;
+
+public interface ILRUCacheable {
+ /**
+ * Returns the space the receiver consumes in an LRU Cache. The default space
+ * value is 1.
+ *
+ * @return int Amount of cache space taken by the receiver
+ */
+ public int getCacheFootprint();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/IProgressListener.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/IProgressListener.java
new file mode 100644
index 0000000000..d0c40368c7
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/IProgressListener.java
@@ -0,0 +1,26 @@
+package org.eclipse.jdt.internal.core.util;
+
+public interface IProgressListener {
+
+ /** Notifies that the main task is beginning.
+ @param name the name (or description) of the main task
+ @param totalWork the total number of work units into which
+ the main task is been subdivided
+ */
+ public void begin(String name, int totalWork);
+ /** Notifies that the work is done, the main task is completed.
+ */
+ public void done();
+ /** Notifies that a subtask of the main task is beginning.
+ Subtasks are optional; the main task might not have subtasks.
+ @param name the name (or description) of the subtask
+ */
+ public void nowDoing(String name);
+ /** Notifies that a given number of work unit of the main task
+ has been completed. Note that this amount represents an
+ installment, as opposed to a cumulative amount of work done
+ to date.
+ @param work the work units just completed
+ */
+ public void worked(int work);
+} // IProgressListener
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LRUCache.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LRUCache.java
new file mode 100644
index 0000000000..4738c559f3
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LRUCache.java
@@ -0,0 +1,518 @@
+package org.eclipse.jdt.internal.core.util;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+/**
+ * The <code>LRUCache</code> is a hashtable that stores a finite number of elements.
+ * When an attempt is made to add values to a full cache, the least recently used values
+ * in the cache are discarded to make room for the new values as necessary.
+ *
+ * <p>The data structure is based on the LRU virtual memory paging scheme.
+ *
+ * <p>Objects can take up a variable amount of cache space by implementing
+ * the <code>ILRUCacheable</code> interface.
+ *
+ * <p>This implementation is NOT thread-safe. Synchronization wrappers would
+ * have to be added to ensure atomic insertions and deletions from the cache.
+ *
+ * @see LRUCacheEntry
+ * @see ILRUCacheable
+ */
+public class LRUCache implements Cloneable {
+
+ /**
+ * This type is used internally by the LRUCache to represent entries
+ * stored in the cache.
+ * It is static because it does not require a pointer to the cache
+ * which contains it.
+ *
+ * @see LRUCache
+ */
+ protected static class LRUCacheEntry {
+
+ /**
+ * Hash table key
+ */
+ public Object _fKey;
+
+ /**
+ * Hash table value (an LRUCacheEntry object)
+ */
+ public Object _fValue;
+
+ /**
+ * Time value for queue sorting
+ */
+ public int _fTimestamp;
+
+ /**
+ * Cache footprint of this entry
+ */
+ public int _fSpace;
+
+ /**
+ * Previous entry in queue
+ */
+ public LRUCacheEntry _fPrevious;
+
+ /**
+ * Next entry in queue
+ */
+ public LRUCacheEntry _fNext;
+
+ /**
+ * Creates a new instance of the receiver with the provided values
+ * for key, value, and space.
+ */
+ public LRUCacheEntry(Object key, Object value, int space) {
+ _fKey = key;
+ _fValue = value;
+ _fSpace = space;
+ }
+
+ /**
+ * Returns a String that represents the value of this object.
+ */
+ public String toString() {
+
+ return "LRUCacheEntry [" + _fKey + "-->" + _fValue + "]";
+ }
+ }
+
+ /**
+ * Amount of cache space used so far
+ */
+ protected int fCurrentSpace;
+
+ /**
+ * Maximum space allowed in cache
+ */
+ protected int fSpaceLimit;
+
+ /**
+ * Counter for handing out sequential timestamps
+ */
+ protected int fTimestampCounter;
+
+ /**
+ * Hash table for fast random access to cache entries
+ */
+ protected Hashtable fEntryTable;
+
+ /**
+ * Start of queue (most recently used entry)
+ */
+ protected LRUCacheEntry fEntryQueue;
+
+ /**
+ * End of queue (least recently used entry)
+ */
+ protected LRUCacheEntry fEntryQueueTail;
+
+ /**
+ * Default amount of space in the cache
+ */
+ protected static final int DEFAULT_SPACELIMIT = 100;
+ /**
+ * Creates a new cache. Size of cache is defined by
+ * <code>DEFAULT_SPACELIMIT</code>.
+ */
+ public LRUCache() {
+
+ this(DEFAULT_SPACELIMIT);
+ }
+
+ /**
+ * Creates a new cache.
+ * @param size Size of Cache
+ */
+ public LRUCache(int size) {
+
+ fTimestampCounter = fCurrentSpace = 0;
+ fEntryQueue = fEntryQueueTail = null;
+ fEntryTable = new Hashtable(size);
+ fSpaceLimit = size;
+ }
+
+ /**
+ * Returns a new cache containing the same contents.
+ *
+ * @return New copy of object.
+ */
+ public Object clone() {
+
+ LRUCache newCache = newInstance(fSpaceLimit);
+ LRUCacheEntry qEntry;
+
+ /* Preserve order of entries by copying from oldest to newest */
+ qEntry = this.fEntryQueueTail;
+ while (qEntry != null) {
+ newCache.privateAdd(qEntry._fKey, qEntry._fValue, qEntry._fSpace);
+ qEntry = qEntry._fPrevious;
+ }
+ return newCache;
+ }
+
+ /**
+ * Flushes all entries from the cache.
+ */
+ public void flush() {
+
+ fCurrentSpace = 0;
+ LRUCacheEntry entry = fEntryQueueTail; // Remember last entry
+ fEntryTable = new Hashtable(); // Clear it out
+ fEntryQueue = fEntryQueueTail = null;
+ while (entry != null) { // send deletion notifications in LRU order
+ privateNotifyDeletionFromCache(entry);
+ entry = entry._fPrevious;
+ }
+ }
+
+ /**
+ * Flushes the given entry from the cache. Does nothing if entry does not
+ * exist in cache.
+ *
+ * @param key Key of object to flush
+ */
+ public void flush(Object key) {
+
+ LRUCacheEntry entry;
+
+ entry = (LRUCacheEntry) fEntryTable.get(key);
+
+ /* If entry does not exist, return */
+ if (entry == null)
+ return;
+
+ this.privateRemoveEntry(entry, false);
+ }
+
+ /**
+ * Answers the value in the cache at the given key.
+ * If the value is not in the cache, returns null
+ *
+ * @param key Hash table key of object to retrieve
+ * @return Retreived object, or null if object does not exist
+ */
+ public Object get(Object key) {
+
+ LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get(key);
+ if (entry == null) {
+ return null;
+ }
+
+ this.updateTimestamp(entry);
+ return entry._fValue;
+ }
+
+ /**
+ * Returns the amount of space that is current used in the cache.
+ */
+ public int getCurrentSpace() {
+ return fCurrentSpace;
+ }
+
+ /**
+ * Returns the maximum amount of space available in the cache.
+ */
+ public int getSpaceLimit() {
+ return fSpaceLimit;
+ }
+
+ /**
+ * Returns an Enumeration of the keys currently in the cache.
+ */
+ public Enumeration keys() {
+
+ return fEntryTable.keys();
+ }
+
+ /**
+ * Returns an enumeration that iterates over all the keys and values
+ * currently in the cache.
+ */
+ public ICacheEnumeration keysAndValues() {
+ return new ICacheEnumeration() {
+
+ Enumeration fValues = fEntryTable.elements();
+ LRUCacheEntry fEntry;
+
+ public boolean hasMoreElements() {
+ return fValues.hasMoreElements();
+ }
+
+ public Object nextElement() {
+ fEntry = (LRUCacheEntry) fValues.nextElement();
+ return fEntry._fKey;
+ }
+
+ public Object getValue() {
+ if (fEntry == null) {
+ throw new java.util.NoSuchElementException();
+ }
+ return fEntry._fValue;
+ }
+ };
+ }
+
+ /**
+ * Ensures there is the specified amount of free space in the receiver,
+ * by removing old entries if necessary. Returns true if the requested space was
+ * made available, false otherwise.
+ *
+ * @param space Amount of space to free up
+ */
+ protected boolean makeSpace(int space) {
+
+ int limit;
+
+ limit = this.getSpaceLimit();
+
+ /* if space is already available */
+ if (fCurrentSpace + space <= limit) {
+ return true;
+ }
+
+ /* if entry is too big for cache */
+ if (space > limit) {
+ return false;
+ }
+
+ /* Free up space by removing oldest entries */
+ while (fCurrentSpace + space > limit && fEntryQueueTail != null) {
+ this.privateRemoveEntry(fEntryQueueTail, false);
+ }
+ return true;
+ }
+
+ /**
+ * Returns a new LRUCache instance
+ */
+ protected LRUCache newInstance(int size) {
+ return new LRUCache(size);
+ }
+
+ /**
+ * Adds an entry for the given key/value/space.
+ */
+ protected void privateAdd(Object key, Object value, int space) {
+
+ LRUCacheEntry entry;
+
+ entry = new LRUCacheEntry(key, value, space);
+ this.privateAddEntry(entry, false);
+ }
+
+ /**
+ * Adds the given entry from the receiver.
+ * @param shuffle Indicates whether we are just shuffling the queue
+ * (i.e., the entry table is left alone).
+ */
+ protected void privateAddEntry(LRUCacheEntry entry, boolean shuffle) {
+
+ if (!shuffle) {
+ fEntryTable.put(entry._fKey, entry);
+ fCurrentSpace += entry._fSpace;
+ }
+
+ entry._fTimestamp = fTimestampCounter++;
+ entry._fNext = this.fEntryQueue;
+ entry._fPrevious = null;
+
+ if (fEntryQueue == null) {
+ /* this is the first and last entry */
+ fEntryQueueTail = entry;
+ } else {
+ fEntryQueue._fPrevious = entry;
+ }
+
+ fEntryQueue = entry;
+ }
+
+ /**
+ * An entry has been removed from the cache, for example because it has
+ * fallen off the bottom of the LRU queue.
+ * Subclasses could over-ride this to implement a persistent cache below the LRU cache.
+ */
+ protected void privateNotifyDeletionFromCache(LRUCacheEntry entry) {
+ // Default is NOP.
+ }
+
+ /**
+ * Removes the entry from the entry queue.
+ * @param shuffle indicates whether we are just shuffling the queue
+ * (i.e., the entry table is left alone).
+ */
+ protected void privateRemoveEntry(LRUCacheEntry entry, boolean shuffle) {
+
+ LRUCacheEntry previous, next;
+
+ previous = entry._fPrevious;
+ next = entry._fNext;
+
+ if (!shuffle) {
+ fEntryTable.remove(entry._fKey);
+ fCurrentSpace -= entry._fSpace;
+ privateNotifyDeletionFromCache(entry);
+ }
+
+ /* if this was the first entry */
+ if (previous == null) {
+ fEntryQueue = next;
+ } else {
+ previous._fNext = next;
+ }
+
+ /* if this was the last entry */
+ if (next == null) {
+ fEntryQueueTail = previous;
+ } else {
+ next._fPrevious = previous;
+ }
+ }
+
+ /**
+ * Sets the value in the cache at the given key. Returns the value.
+ *
+ * @param key Key of object to add.
+ * @param value Value of object to add.
+ * @return added value.
+ */
+ public Object put(Object key, Object value) {
+
+ int newSpace, oldSpace, newTotal;
+ LRUCacheEntry entry;
+
+ /* Check whether there's an entry in the cache */
+ newSpace = spaceFor(key, value);
+ entry = (LRUCacheEntry) fEntryTable.get(key);
+
+ if (entry != null) {
+
+ /**
+ * Replace the entry in the cache if it would not overflow
+ * the cache. Otherwise flush the entry and re-add it so as
+ * to keep cache within budget
+ */
+ oldSpace = entry._fSpace;
+ newTotal = getCurrentSpace() - oldSpace + newSpace;
+ if (newTotal <= getSpaceLimit()) {
+ updateTimestamp(entry);
+ entry._fValue = value;
+ entry._fSpace = newSpace;
+ this.fCurrentSpace = newTotal;
+ return value;
+ } else {
+ privateRemoveEntry(entry, false);
+ }
+ }
+ if (makeSpace(newSpace)) {
+ privateAdd(key, value, newSpace);
+ }
+ return value;
+ }
+
+ /**
+ * Removes and returns the value in the cache for the given key.
+ * If the key is not in the cache, returns null.
+ *
+ * @param key Key of object to remove from cache.
+ * @return Value removed from cache.
+ */
+ public Object removeKey(Object key) {
+
+ LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get(key);
+ if (entry == null) {
+ return null;
+ }
+ Object value = entry._fValue;
+ this.privateRemoveEntry(entry, false);
+ return value;
+ }
+
+ /**
+ * Sets the maximum amount of space that the cache can store
+ *
+ * @param limit Number of units of cache space
+ */
+ public void setSpaceLimit(int limit) {
+ if (limit < fSpaceLimit) {
+ makeSpace(fSpaceLimit - limit);
+ }
+ fSpaceLimit = limit;
+ }
+
+ /**
+ * Returns the space taken by the given key and value.
+ */
+ protected int spaceFor(Object key, Object value) {
+
+ if (value instanceof ILRUCacheable) {
+ return ((ILRUCacheable) value).getCacheFootprint();
+ } else {
+ return 1;
+ }
+ }
+
+ /**
+ * Returns a String that represents the value of this object. This method
+ * is for debugging purposes only.
+ */
+ public String toString() {
+ return "LRUCache "
+ + (fCurrentSpace * 100.0 / fSpaceLimit)
+ + "% full\n"
+ + this.toStringContents();
+ }
+
+ /**
+ * Returns a String that represents the contents of this object. This method
+ * is for debugging purposes only.
+ */
+ protected String toStringContents() {
+ StringBuffer result = new StringBuffer();
+ int length = fEntryTable.size();
+ Object[] unsortedKeys = new Object[length];
+ String[] unsortedToStrings = new String[length];
+ Enumeration e = this.keys();
+ for (int i = 0; i < length; i++) {
+ Object key = e.nextElement();
+ unsortedKeys[i] = key;
+ unsortedToStrings[i] =
+ (key instanceof org.eclipse.jdt.internal.core.JavaElement)
+ ? ((org.eclipse.jdt.internal.core.JavaElement) key).getElementName()
+ : key.toString();
+ }
+ ToStringSorter sorter = new ToStringSorter();
+ sorter.sort(unsortedKeys, unsortedToStrings);
+ for (int i = 0; i < length; i++) {
+ String toString = sorter.sortedStrings[i];
+ Object value = this.get(sorter.sortedObjects[i]);
+ result.append(toString);
+ result.append(" -> ");
+ result.append(value);
+ result.append("\n");
+ }
+ return result.toString();
+ }
+
+ /**
+ * Updates the timestamp for the given entry, ensuring that the queue is
+ * kept in correct order. The entry must exist
+ */
+ protected void updateTimestamp(LRUCacheEntry entry) {
+
+ entry._fTimestamp = fTimestampCounter++;
+ if (fEntryQueue != entry) {
+ this.privateRemoveEntry(entry, true);
+ this.privateAddEntry(entry, true);
+ }
+ return;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LookupTable.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LookupTable.java
new file mode 100644
index 0000000000..becc26dd04
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LookupTable.java
@@ -0,0 +1,544 @@
+package org.eclipse.jdt.internal.core.util;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.*;
+
+/**
+ * A lookup table whose keys and values are Objects.
+ * A lookup table is like a Hashtable, but uses linear probing to
+ * resolve collisions rather than a linked list of hash table entries.
+ */
+public class LookupTable extends Dictionary implements Cloneable {
+ protected int count;
+ protected float loadFactor;
+ protected int threshold;
+ protected Object[] keys;
+ protected Object[] values;
+ protected int modCount;
+
+ // Types of Enumeration
+ protected static final int KEYS = 0;
+ protected static final int VALUES = 1;
+
+ /**
+ * A lookup table enumerator class.
+ */
+ protected class Enumerator implements Enumeration {
+
+ protected int type;
+ protected Object[] table;
+ protected int index;
+ protected Object entry;
+
+ /**
+ * The modCount value that the enumeration believes that the backing
+ * lookup table should have. If this expectation is violated, the enumeration
+ * has detected concurrent modification.
+ */
+ protected int expectedModCount = modCount;
+
+ Enumerator(int type) {
+ this.type = type;
+ table = (type == KEYS ? keys : values);
+ index = table.length;
+ }
+
+ public boolean hasMoreElements() {
+ while (entry == null && index > 0)
+ entry = table[--index];
+ return entry != null;
+ }
+
+ public Object nextElement() {
+ if (modCount != expectedModCount)
+ throw new IllegalStateException();
+ while (entry == null && index > 0)
+ entry = table[--index];
+ if (entry != null) {
+ Object next = entry;
+ entry = null;
+ return next;
+ }
+ throw new NoSuchElementException("LookupTable Enumerator");
+ }
+ }
+
+ /**
+ * Constructs a new, empty LookupTable with a default capacity (11) and load
+ * factor (0.5).
+ */
+ public LookupTable() {
+ this(11, 0.5f);
+ }
+
+ /**
+ * Constructs a new, empty LookupTable with the specified initial capacity
+ * and default load factor (0.5).
+ *
+ * @param initialCapacity the initial capacity of the lookup table.
+ * @exception IllegalArgumentException if the initial capacity is less
+ * than zero.
+ */
+ public LookupTable(int initialCapacity) {
+ this(initialCapacity, 0.5f);
+ }
+
+ /**
+ * Constructs a new, empty LookupTable with the specified initial
+ * capacity and the specified load factor.
+ *
+ * @param initialCapacity the initial capacity of the lookup table.
+ * @param loadFactor the load factor of the lookup table.
+ * @exception IllegalArgumentException if the initial capacity is less
+ * than zero, or if the load factor is nonpositive.
+ */
+ public LookupTable(int initialCapacity, float loadFactor) {
+ if (initialCapacity < 0)
+ throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
+ if (loadFactor <= 0)
+ throw new IllegalArgumentException("Illegal Load: " + loadFactor);
+
+ if (initialCapacity == 0)
+ initialCapacity = 1;
+ this.loadFactor = loadFactor;
+ keys = new Object[initialCapacity];
+ values = new Object[initialCapacity];
+ threshold = (int) (initialCapacity * loadFactor);
+ }
+
+ /**
+ * Clears this lookup table so that it contains no keys.
+ */
+ public synchronized void clear() {
+ Object tab1[] = keys;
+ Object tab2[] = values;
+ modCount++;
+ for (int index = keys.length; --index >= 0;) {
+ tab1[index] = null;
+ tab2[index] = null;
+ }
+ count = 0;
+ }
+
+ /**
+ * Creates a shallow copy of this lookup table. All the structure of the
+ * lookup table itself is copied, but the keys and values are not cloned.
+ * This is a relatively expensive operation.
+ *
+ * @return a clone of the lookup table.
+ */
+ public synchronized Object clone() {
+ try {
+ LookupTable t = (LookupTable) super.clone();
+ int size = keys.length;
+ t.keys = new Object[size];
+ t.values = new Object[size];
+ System.arraycopy(keys, 0, t.keys, 0, size);
+ System.arraycopy(values, 0, t.values, 0, size);
+ t.modCount = 0;
+ return t;
+ } catch (CloneNotSupportedException e) {
+ // this shouldn't happen, since we are Cloneable
+ throw new InternalError();
+ }
+ }
+
+ /**
+ * Tests if some key maps into the specified value in this lookup table.
+ * This operation is more expensive than the <code>containsKey</code>
+ * method.<p>
+ *
+ * Note that this method is identical in functionality to containsValue,
+ * (which is part of the Map interface in the collections framework).
+ *
+ * @param value a value to search for.
+ * @return <code>true</code> if and only if some key maps to the
+ * <code>value</code> argument in this lookup table as
+ * determined by the <tt>equals</tt> method;
+ * <code>false</code> otherwise.
+ * @exception NullPointerException if the value is <code>null</code>.
+ * @see #containsKey(Object)
+ * @see #containsValue(Object)
+ * @see Map
+ */
+ public synchronized boolean contains(Object value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+
+ Object tab[] = values;
+ for (int i = tab.length; i-- > 0;) {
+ if (tab[i].equals(value)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Tests if the specified object is a key in this lookup table.
+ *
+ * @param key possible key.
+ * @return <code>true</code> if and only if the specified object
+ * is a key in this lookup table, as determined by the
+ * <tt>equals</tt> method; <code>false</code> otherwise.
+ * @see #contains(Object)
+ */
+ public synchronized boolean containsKey(Object key) {
+ Object[] tab = keys;
+ int size = tab.length;
+ int index = (key.hashCode() & 0x7FFFFFFF) % size;
+ for (int i = index; i < size; ++i) {
+ Object testKey = tab[i];
+ if (testKey == null)
+ return false;
+ if (testKey.equals(key))
+ return true;
+ }
+ for (int i = 0; i < index; ++i) {
+ Object testKey = tab[i];
+ if (testKey == null)
+ return false;
+ if (testKey.equals(key))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns an enumeration of the values in this lookup table.
+ * Use the Enumeration methods on the returned object to fetch the elements
+ * sequentially.
+ *
+ * @return an enumeration of the values in this lookup table.
+ * @see java.util.Enumeration
+ * @see #keys()
+ * @see #values()
+ * @see Map
+ */
+ public synchronized Enumeration elements() {
+ return new Enumerator(VALUES);
+ }
+
+ /**
+ * Increases the capacity of and internally reorganizes this
+ * lookup table, in order to accommodate and access its entries more
+ * efficiently. This method is called automatically when the
+ * number of keys in the lookup table exceeds this lookup table's capacity
+ * and load factor.
+ */
+ protected void expand() {
+ rehash(keys.length * 2 + 1);
+ }
+
+ /**
+ * Returns the value to which the specified key is mapped in this lookup table.
+ *
+ * @param key a key in the lookup table.
+ * @return the value to which the key is mapped in this lookup table;
+ * <code>null</code> if the key is not mapped to any value in
+ * this lookup table.
+ * @see #put(Object, Object)
+ */
+ public synchronized Object get(Object key) {
+ Object[] tab = keys;
+ int size = tab.length;
+ int index = (key.hashCode() & 0x7FFFFFFF) % size;
+ for (int i = index; i < size; ++i) {
+ Object testKey = tab[i];
+ if (testKey == null)
+ return null;
+ if (testKey.equals(key))
+ return values[i];
+ }
+ for (int i = 0; i < index; ++i) {
+ Object testKey = tab[i];
+ if (testKey == null)
+ return null;
+ if (testKey.equals(key))
+ return values[i];
+ }
+ return null;
+ }
+
+ /**
+ * Tests if this lookup table maps no keys to values.
+ *
+ * @return <code>true</code> if this lookup table maps no keys to values;
+ * <code>false</code> otherwise.
+ */
+ public boolean isEmpty() {
+ return count == 0;
+ }
+
+ /**
+ * Returns an enumeration of the keys in this lookup table.
+ *
+ * @return an enumeration of the keys in this lookup table.
+ * @see Enumeration
+ * @see #elements()
+ * @see #keySet()
+ * @see Map
+ */
+ public synchronized Enumeration keys() {
+ return new Enumerator(KEYS);
+ }
+
+ /**
+ * Maps the specified <code>key</code> to the specified
+ * <code>value</code> in this lookup table. Neither the key nor the
+ * value can be <code>null</code>. <p>
+ *
+ * The value can be retrieved by calling the <code>get</code> method
+ * with a key that is equal to the original key.
+ *
+ * @param key the lookup table key.
+ * @param value the value.
+ * @return the previous value of the specified key in this lookup table,
+ * or <code>null</code> if it did not have one.
+ * @exception NullPointerException if the key or value is
+ * <code>null</code>.
+ * @see Object#equals(Object)
+ * @see #get(Object)
+ */
+ public synchronized Object put(Object key, Object value) {
+ // Make sure the value is not null
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ Object[] tab = keys;
+ int size = tab.length;
+ int hashIndex = (key.hashCode() & 0x7FFFFFFF) % size;
+ for (int i = hashIndex; i < size; ++i) {
+ Object element = tab[i];
+ if (element == null) {
+ keys[i] = key;
+ values[i] = value;
+ if (++count > threshold) {
+ expand();
+ }
+ ++modCount;
+ return null;
+ }
+ if (element.equals(key)) {
+ Object oldValue = values[i];
+ values[i] = value;
+ return oldValue;
+ }
+ }
+ for (int i = 0; i < hashIndex; ++i) {
+ Object element = tab[i];
+ if (element == null) {
+ keys[i] = key;
+ values[i] = value;
+ if (++count > threshold) {
+ expand();
+ }
+ ++modCount;
+ return null;
+ }
+ if (element.equals(key)) {
+ Object oldValue = values[i];
+ values[i] = value;
+ return oldValue;
+ }
+ }
+ expand();
+ return put(key, value);
+ }
+
+ protected void rehash(int newSize) {
+ /*
+ System.out.println("LookupTable.rehash()");
+ System.out.println(" oldSize= " + keys.length);
+ System.out.println(" count= " + count);
+ System.out.println(" threshold= " + threshold);
+ System.out.println(" newSize= " + newSize);
+ */
+ Object[] newKeys = new Object[newSize];
+ Object[] newValues = new Object[newSize];
+ if (count > 0) {
+ Object[] oldKeys = keys;
+ Object[] oldValues = values;
+ for (int i = keys.length; i-- > 0;) {
+ Object key = oldKeys[i];
+ if (key != null) {
+ int hashIndex = (key.hashCode() & 0x7FFFFFFF) % newSize;
+ while (newKeys[hashIndex] != null) {
+ if (++hashIndex >= newSize)
+ hashIndex = 0;
+ }
+ newKeys[hashIndex] = key;
+ newValues[hashIndex] = oldValues[i];
+ }
+ }
+ }
+ keys = newKeys;
+ values = newValues;
+ threshold = (int) (newSize * loadFactor);
+
+ // sanityCheck("rehash");
+ }
+
+ /**
+ * The element at target has been removed. Move the elements
+ * to keep the receiver properly hashed.
+ */
+ protected void rehashTo(int index) {
+ int target = index;
+ Object[] tab = keys;
+ int size = tab.length;
+ for (;;) {
+ if (++index >= size)
+ index = 0;
+ Object element = tab[index];
+ if (element == null)
+ break;
+ int hashIndex = (element.hashCode() & 0x7FFFFFFF) % size;
+ if (index < target ? hashIndex <= target
+ && hashIndex > index : hashIndex <= target
+ || hashIndex > index) {
+ keys[target] = element;
+ values[target] = values[index];
+ target = index;
+ }
+ }
+ keys[target] = null;
+ values[target] = null;
+ }
+
+ /**
+ * Removes the key (and its corresponding value) from this
+ * lookup table. This method does nothing if the key is not in the lookup table.
+ *
+ * @param key the key that needs to be removed.
+ * @return the value to which the key had been mapped in this lookup table,
+ * or <code>null</code> if the key did not have a mapping.
+ */
+ public synchronized Object remove(Object key) {
+ Object[] tab = keys;
+ int size = tab.length;
+ int hashIndex = (key.hashCode() & 0x7FFFFFFF) % size;
+ for (int i = hashIndex; i < size; ++i) {
+ Object element = tab[i];
+ if (element == null)
+ return null;
+ if (element.equals(key)) {
+ Object oldValue = values[i];
+ rehashTo(i);
+ --count;
+ // sanityCheck("remove");
+ ++modCount;
+ return oldValue;
+ }
+ }
+ for (int i = 0; i < hashIndex; ++i) {
+ Object element = tab[i];
+ if (element == null)
+ return null;
+ if (element.equals(key)) {
+ Object oldValue = values[i];
+ rehashTo(i);
+ --count;
+ // sanityCheck("remove");
+ ++modCount;
+ return oldValue;
+ }
+ }
+ return null;
+ }
+
+ protected void sanityCheck(String where) {
+ int n = 0;
+ for (int i = 0; i < keys.length; ++i) {
+ if (keys[i] == null) {
+ if (values[i] != null) {
+ System.err.println(
+ "LookupTable sanity check in "
+ + where
+ + ": key is null, but value isn't at index "
+ + i);
+ throw new Error();
+ }
+ } else {
+ if (values[i] == null) {
+ System.err.println(
+ "LookupTable sanity check in "
+ + where
+ + ": value is null, but key isn't at index "
+ + i);
+ throw new Error();
+ } else {
+ ++n;
+ Object value = get(keys[i]);
+ if (value == null || value != values[i]) {
+ System.err.println(
+ "LookupTable sanity check in "
+ + where
+ + ": key doesn't hash to proper value: "
+ + keys[i]);
+ throw new Error();
+ }
+ }
+ }
+ }
+ if (n != count) {
+ System.err.println(
+ "LookupTable sanity check in "
+ + where
+ + ": count is "
+ + count
+ + " but there are "
+ + n
+ + " entries");
+ throw new Error();
+ }
+ }
+
+ /**
+ * Returns the number of keys in this LookupTable.
+ *
+ * @return the number of keys in this lookup table.
+ */
+ public int size() {
+ return count;
+ }
+
+ /**
+ * Returns a string representation of this <tt>LookupTable</tt> object
+ * in the form of a set of entries, enclosed in braces and separated
+ * by the ASCII characters "<tt>,&nbsp;</tt>" (comma and space). Each
+ * entry is rendered as the key, an equals sign <tt>=</tt>, and the
+ * associated element, where the <tt>toString</tt> method is used to
+ * convert the key and element to strings. <p>Overrides to
+ * <tt>toString</tt> method of <tt>Object</tt>.
+ *
+ * @return a string representation of this lookup table.
+ */
+ public synchronized String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("{");
+ boolean first = true;
+ for (int i = 0, max = keys.length; i < max; i++) {
+ if (keys[i] != null) {
+ if (first) {
+ first = false;
+ } else {
+ buf.append(", ");
+ }
+ if (buf.length() > 1000) {
+ buf.append("...");
+ break;
+ } else {
+ buf.append(keys[i]).append("=").append(values[i]);
+ }
+ }
+ }
+ buf.append("}");
+ return buf.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ReferenceInfoAdapter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ReferenceInfoAdapter.java
new file mode 100644
index 0000000000..b302950922
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ReferenceInfoAdapter.java
@@ -0,0 +1,58 @@
+package org.eclipse.jdt.internal.core.util;
+
+public abstract class ReferenceInfoAdapter {
+ /**
+ * Does nothing.
+ */
+ public void acceptConstructorReference(
+ char[] typeName,
+ int argCount,
+ int sourcePosition) {
+ }
+
+ /**
+ * Does nothing.
+ */
+ public void acceptFieldReference(char[] fieldName, int sourcePosition) {
+ }
+
+ /**
+ * Does nothing.
+ */
+ public void acceptMethodReference(
+ char[] methodName,
+ int argCount,
+ int sourcePosition) {
+ }
+
+ /**
+ * Does nothing.
+ */
+ public void acceptTypeReference(
+ char[][] typeName,
+ int sourceStart,
+ int sourceEnd) {
+ }
+
+ /**
+ * Does nothing.
+ */
+ public void acceptTypeReference(char[] typeName, int sourcePosition) {
+ }
+
+ /**
+ * Does nothing.
+ */
+ public void acceptUnknownReference(
+ char[][] name,
+ int sourceStart,
+ int sourceEnd) {
+ }
+
+ /**
+ * Does nothing.
+ */
+ public void acceptUnknownReference(char[] name, int sourcePosition) {
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/StringHashtableOfInt.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/StringHashtableOfInt.java
new file mode 100644
index 0000000000..6eeb2a1b3f
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/StringHashtableOfInt.java
@@ -0,0 +1,129 @@
+package org.eclipse.jdt.internal.core.util;
+
+public class StringHashtableOfInt {
+ // to avoid using Enumerations, walk the individual tables skipping nulls
+ public String[] keyTable;
+ public int[] valueTable;
+
+ int elementSize; // number of elements in the table
+ int threshold;
+ public StringHashtableOfInt() {
+ this(13);
+ }
+
+ public StringHashtableOfInt(int size) {
+ this.elementSize = 0;
+ this.threshold = size; // size represents the expected number of elements
+ int extraRoom = (int) (size * 1.75f);
+ if (this.threshold == extraRoom)
+ extraRoom++;
+ this.keyTable = new String[extraRoom];
+ this.valueTable = new int[extraRoom];
+ }
+
+ public boolean containsKey(String key) {
+ int index = (key.hashCode() & 0x7FFFFFFF) % valueTable.length;
+ String currentKey;
+ while ((currentKey = keyTable[index]) != null) {
+ if (currentKey.equals(key))
+ return true;
+ index = (index + 1) % keyTable.length;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the value at the given key.
+ * Returns -1 if not found.
+ */
+ public int get(String key) {
+ int index = (key.hashCode() & 0x7FFFFFFF) % valueTable.length;
+ String currentKey;
+ while ((currentKey = keyTable[index]) != null) {
+ if (currentKey.equals(key))
+ return valueTable[index];
+ index = (index + 1) % keyTable.length;
+ }
+ return -1;
+ }
+
+ public int put(String key, int value) {
+ int index = (key.hashCode() & 0x7FFFFFFF) % valueTable.length;
+ String currentKey;
+ while ((currentKey = keyTable[index]) != null) {
+ if (currentKey.equals(key))
+ return valueTable[index] = value;
+ index = (index + 1) % keyTable.length;
+ }
+ keyTable[index] = key;
+ valueTable[index] = value;
+
+ // assumes the threshold is never equal to the size of the table
+ if (++elementSize > threshold)
+ rehash();
+ return value;
+ }
+
+ private void rehash() {
+ StringHashtableOfInt newHashtable = new StringHashtableOfInt(elementSize * 2);
+ // double the number of expected elements
+ String currentKey;
+ for (int i = keyTable.length; --i >= 0;)
+ if ((currentKey = keyTable[i]) != null)
+ newHashtable.put(currentKey, valueTable[i]);
+
+ this.keyTable = newHashtable.keyTable;
+ this.valueTable = newHashtable.valueTable;
+ this.threshold = newHashtable.threshold;
+ }
+
+ public int size() {
+ return elementSize;
+ }
+
+ /**
+ * Return the keys sorted by their values.
+ */
+ public String[] sortedKeys(int maxValue) {
+ String[] result = new String[this.elementSize];
+
+ // compute a list of the end positions of each layer in result
+ int[] endPos = new int[maxValue + 1];
+ int length = this.keyTable.length;
+ for (int i = 0; i < length; i++) {
+ String key = this.keyTable[i];
+ if (key != null) {
+ for (int j = this.valueTable[i]; j <= maxValue; j++) {
+ endPos[j]++;
+ }
+ }
+ }
+
+ // store the keys in order of their values
+ for (int i = 0; i < length; i++) {
+ String key = this.keyTable[i];
+ if (key != null) {
+ int value = this.valueTable[i];
+ int index = --endPos[value];
+ result[index] = key;
+ }
+ }
+
+ return result;
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0, length = this.valueTable.length; i < length; i++) {
+ String key = this.keyTable[i];
+ if (key != null) {
+ buffer.append(key);
+ buffer.append(" -> ");
+ buffer.append(this.valueTable[i]);
+ buffer.append("\n");
+ }
+ }
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/StringMatcher.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/StringMatcher.java
new file mode 100644
index 0000000000..cf3c394fb2
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/StringMatcher.java
@@ -0,0 +1,412 @@
+package org.eclipse.jdt.internal.core.util;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.*;
+
+public class StringMatcher {
+ protected String fPattern;
+ protected int fLength; // pattern length
+ protected boolean fIgnoreWildCards;
+ protected boolean fIgnoreCase;
+ protected boolean fHasLeadingStar;
+ protected boolean fHasTrailingStar;
+ protected String fSegments[];
+ //the given pattern is split into * separated segments
+
+ /* boundary value beyond which we don't need to search in the text */
+ protected int fBound = 0;
+
+ protected static final char fSingleWildCard = '\u0000';
+
+ public static class Position {
+ int start; //inclusive
+ int end; //exclusive
+ public Position(int start, int end) {
+ this.start = start;
+ this.end = end;
+ }
+ public int getStart() {
+ return start;
+ }
+ public int getEnd() {
+ return end;
+ }
+ }
+
+ /**
+ * StringMatcher constructor takes in a String object that is a simple
+ * pattern which may contain ‘*’ for 0 and many characters and
+ * ‘?’ for exactly one character. Also takes as parameter a boolean object
+ * specifying if case should be ignored
+ * @deprecated Use StringMatcher(pattern, ignoreCase, ignoreWildCards).
+ */
+ public StringMatcher(String aPattern, boolean ignoreCase) {
+ this(aPattern, ignoreCase, false);
+ }
+
+ /**
+ * StringMatcher constructor takes in a String object that is a simple
+ * pattern which may contain ‘*’ for 0 and many characters and
+ * ‘?’ for exactly one character.
+ *
+ * Literal '*' and '?' characters must be escaped in the pattern
+ * e.g., "\*" means literal "*", etc.
+ *
+ * Escaping any other character (including the escape character itself),
+ * just results in that character in the pattern.
+ * e.g., "\a" means "a" and "\\" means "\"
+ *
+ * If invoking the StringMatcher with string literals in Java, don't forget
+ * escape characters are represented by "\\".
+ *
+ * @param aPattern the pattern to match text against
+ * @param ignoreCase if true, case is ignored
+ * @param ignoreWildCards if true, wild cards and their escape sequences are ignored
+ * (everything is taken literally).
+ */
+ public StringMatcher(
+ String aPattern,
+ boolean ignoreCase,
+ boolean ignoreWildCards) {
+ fIgnoreCase = ignoreCase;
+ fIgnoreWildCards = ignoreWildCards;
+ fLength = aPattern.length();
+
+ /* convert case */
+ if (fIgnoreCase) {
+ fPattern = aPattern.toUpperCase();
+ } else {
+ fPattern = aPattern;
+ }
+
+ if (fIgnoreWildCards) {
+ parseNoWildCards();
+ } else {
+ parseWildCards();
+ }
+ }
+
+ /**
+ * Find the first occurrence of the pattern between <code>start</code)(inclusive)
+ * and <code>end</code>(exclusive).
+ * @param <code>text</code>, the String object to search in
+ * @param <code>start</code>, the starting index of the search range, inclusive
+ * @param <code>end</code>, the ending index of the search range, exclusive
+ * @return an <code>StringMatcher.Position</code> object that keeps the starting
+ * (inclusive) and ending positions (exclusive) of the first occurrence of the
+ * pattern in the specified range of the text; return null if not found or subtext
+ * is empty (start==end). A pair of zeros is returned if pattern is empty string
+ * Note that for pattern like "*abc*" with leading and trailing stars, position of "abc"
+ * is returned. For a pattern like"*??*" in text "abcdf", (1,3) is returned
+ */
+
+ public StringMatcher.Position find(String text, int start, int end) {
+ if (fPattern == null || text == null)
+ throw new IllegalArgumentException();
+
+ int tlen = text.length();
+ if (start < 0)
+ start = 0;
+ if (end > tlen)
+ end = tlen;
+ if (end < 0 || start >= end)
+ return null;
+ if (fLength == 0)
+ return new Position(start, start);
+ if (fIgnoreWildCards) {
+ int x = posIn(text, start, end);
+ if (x < 0)
+ return null;
+ return new Position(x, x + fLength);
+ }
+
+ int segCount = fSegments.length;
+ if (segCount == 0) //pattern contains only '*'(s)
+ return new Position(start, end);
+
+ int curPos = start;
+ int matchStart = -1;
+ for (int i = 0; i < segCount && curPos < end; ++i) {
+ String current = fSegments[i];
+ int nextMatch = regExpPosIn(text, curPos, end, current);
+ if (nextMatch < 0)
+ return null;
+ if (i == 0)
+ matchStart = nextMatch;
+ curPos = nextMatch + current.length();
+ }
+ return new Position(matchStart, curPos);
+ }
+
+ /**
+ * match the given <code>text</code> with the pattern
+ * @return true if matched eitherwise false
+ * @param <code>text</code>, a String object
+ */
+ public boolean match(String text) {
+ return match(text, 0, text.length());
+ }
+
+ /**
+ * Given the starting (inclusive) and the ending (exclusive) poisitions in the
+ * <code>text</code>, determine if the given substring matches with aPattern
+ * @return true if the specified portion of the text matches the pattern
+ * @param String <code>text</code>, a String object that contains the substring to match
+ * @param int <code>start<code> marks the starting position (inclusive) of the substring
+ * @param int <code>end<code> marks the ending index (exclusive) of the substring
+ */
+ public boolean match(String text, int start, int end) {
+ if (null == fPattern || null == text)
+ throw new IllegalArgumentException();
+
+ if (start > end)
+ return false;
+
+ if (fIgnoreWildCards)
+ return fPattern.regionMatches(fIgnoreCase, 0, text, start, fLength);
+ int segCount = fSegments.length;
+ if (segCount == 0) //pattern contains only '*'(s) or empty pattern
+ return true;
+ if (start == end)
+ return fLength == 0;
+ if (fLength == 0)
+ return start == end;
+
+ int tlen = text.length();
+ if (start < 0)
+ start = 0;
+ if (end > tlen)
+ end = tlen;
+
+ int tCurPos = start;
+ int bound = end - fBound;
+ if (bound < 0)
+ return false;
+ int i = 0;
+ String current = fSegments[i];
+ int segLength = current.length();
+
+ /* process first segment */
+ if (!fHasLeadingStar) {
+ if (!regExpRegionMatches(text, start, current, 0, segLength)) {
+ return false;
+ } else {
+ ++i;
+ tCurPos = tCurPos + segLength;
+ }
+ }
+
+ /* process middle segments */
+ for (; i < segCount && tCurPos <= bound; ++i) {
+ current = fSegments[i];
+ int currentMatch;
+ int k = current.indexOf(fSingleWildCard);
+ if (k < 0) {
+ currentMatch = textPosIn(text, tCurPos, end, current);
+ if (currentMatch < 0)
+ return false;
+ } else {
+ currentMatch = regExpPosIn(text, tCurPos, end, current);
+ if (currentMatch < 0)
+ return false;
+ }
+ tCurPos = currentMatch + current.length();
+ }
+
+ /* process final segment */
+ if (!fHasTrailingStar && tCurPos != end) {
+ int clen = current.length();
+ return regExpRegionMatches(text, end - clen, current, 0, clen);
+ }
+ return i == segCount;
+ }
+
+ /**
+ * This method parses the given pattern into segments seperated by wildcard '*' characters.
+ * Since wildcards are not being used in this case, the pattern consists of a single segment.
+ */
+ private void parseNoWildCards() {
+ fSegments = new String[1];
+ fSegments[0] = fPattern;
+ fBound = fLength;
+ }
+
+ /**
+ * This method parses the given pattern into segments seperated by wildcard '*' characters.
+ * @param p, a String object that is a simple regular expression with ‘*’ and/or ‘?’
+ */
+ private void parseWildCards() {
+ if (fPattern.startsWith("*"))
+ fHasLeadingStar = true;
+ if (fPattern.endsWith("*")) {
+ /* make sure it's not an escaped wildcard */
+ if (fLength > 1 && fPattern.charAt(fLength - 2) != '\\') {
+ fHasTrailingStar = true;
+ }
+ }
+
+ Vector temp = new Vector();
+
+ int pos = 0;
+ StringBuffer buf = new StringBuffer();
+ while (pos < fLength) {
+ char c = fPattern.charAt(pos++);
+ switch (c) {
+ case '\\' :
+ if (pos >= fLength) {
+ buf.append(c);
+ } else {
+ char next = fPattern.charAt(pos++);
+ /* if it's an escape sequence */
+ if (next == '*' || next == '?' || next == '\\') {
+ buf.append(next);
+ } else {
+ /* not an escape sequence, just insert literally */
+ buf.append(c);
+ buf.append(next);
+ }
+ }
+ break;
+ case '*' :
+ if (buf.length() > 0) {
+ /* new segment */
+ temp.addElement(buf.toString());
+ fBound += buf.length();
+ buf.setLength(0);
+ }
+ break;
+ case '?' :
+ /* append special character representing single match wildcard */
+ buf.append(fSingleWildCard);
+ break;
+ default :
+ buf.append(c);
+ }
+ }
+
+ /* add last buffer to segment list */
+ if (buf.length() > 0) {
+ temp.addElement(buf.toString());
+ fBound += buf.length();
+ }
+
+ fSegments = new String[temp.size()];
+ temp.copyInto(fSegments);
+ }
+
+ /**
+ * @param <code>text</code>, a string which contains no wildcard
+ * @param <code>start</code>, the starting index in the text for search, inclusive
+ * @param <code>end</code>, the stopping point of search, exclusive
+ * @return the starting index in the text of the pattern , or -1 if not found
+ */
+ protected int posIn(
+ String text,
+ int start,
+ int end) { //no wild card in pattern
+ int max = end - fLength;
+
+ if (!fIgnoreCase) {
+ int i = text.indexOf(fPattern, start);
+ if (i == -1 || i > max)
+ return -1;
+ return i;
+ }
+
+ for (int i = start; i <= max; ++i) {
+ if (text.regionMatches(true, i, fPattern, 0, fLength))
+ return i;
+ }
+
+ return -1;
+ }
+
+ /**
+ * @param <code>text</code>, a simple regular expression that may only contain '?'(s)
+ * @param <code>start</code>, the starting index in the text for search, inclusive
+ * @param <code>end</code>, the stopping point of search, exclusive
+ * @param <code>p</code>, a simple regular expression that may contains '?'
+ * @param <code>caseIgnored</code>, wether the pattern is not casesensitive
+ * @return the starting index in the text of the pattern , or -1 if not found
+ */
+ protected int regExpPosIn(String text, int start, int end, String p) {
+ int plen = p.length();
+
+ int max = end - plen;
+ for (int i = start; i <= max; ++i) {
+ if (regExpRegionMatches(text, i, p, 0, plen))
+ return i;
+ }
+ return -1;
+ }
+
+ /**
+ *
+ * @return boolean
+ * @param <code>text</code>, a String to match
+ * @param <code>start</code>, int that indicates the starting index of match, inclusive
+ * @param <code>end</code> int that indicates the ending index of match, exclusive
+ * @param <code>p</code>, String, String, a simple regular expression that may contain '?'
+ * @param <code>ignoreCase</code>, boolean indicating wether code>p</code> is case sensitive
+ */
+ protected boolean regExpRegionMatches(
+ String text,
+ int tStart,
+ String p,
+ int pStart,
+ int plen) {
+ while (plen-- > 0) {
+ char tchar = text.charAt(tStart++);
+ char pchar = p.charAt(pStart++);
+
+ /* process wild cards */
+ if (!fIgnoreWildCards) {
+ /* skip single wild cards */
+ if (pchar == fSingleWildCard) {
+ continue;
+ }
+ }
+ if (pchar == tchar)
+ continue;
+ if (fIgnoreCase) {
+ char tc = Character.toUpperCase(tchar);
+ if (tc == pchar)
+ continue;
+ }
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @param <code>text</code>, the string to match
+ * @param <code>start</code>, the starting index in the text for search, inclusive
+ * @param <code>end</code>, the stopping point of search, exclusive
+ * @param code>p</code>, a string that has no wildcard
+ * @param <code>ignoreCase</code>, boolean indicating wether code>p</code> is case sensitive
+ * @return the starting index in the text of the pattern , or -1 if not found
+ */
+ protected int textPosIn(String text, int start, int end, String p) {
+
+ int plen = p.length();
+ int max = end - plen;
+
+ if (!fIgnoreCase) {
+ int i = text.indexOf(p, start);
+ if (i == -1 || i > max)
+ return -1;
+ return i;
+ }
+
+ for (int i = 0; i <= max; ++i) {
+ if (text.regionMatches(true, i, p, 0, plen))
+ return i;
+ }
+
+ return -1;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ToStringSorter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ToStringSorter.java
new file mode 100644
index 0000000000..4c242923a3
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ToStringSorter.java
@@ -0,0 +1,64 @@
+package org.eclipse.jdt.internal.core.util;
+
+public class ToStringSorter {
+ Object[] sortedObjects;
+ String[] sortedStrings;
+ /**
+ * Returns true if stringTwo is 'greater than' stringOne
+ * This is the 'ordering' method of the sort operation.
+ */
+ public boolean compare(String stringOne, String stringTwo) {
+ return stringOne.compareTo(stringTwo) < 0;
+ }
+
+ /**
+ * Sort the objects in sorted collection and return that collection.
+ */
+ private void quickSort(int left, int right) {
+ int originalLeft = left;
+ int originalRight = right;
+ int midIndex = (left + right) / 2;
+ Object mid = this.sortedObjects[midIndex];
+ String midToString = this.sortedStrings[midIndex];
+
+ do {
+ while (compare(this.sortedStrings[left], midToString))
+ left++;
+ while (compare(midToString, this.sortedStrings[right]))
+ right--;
+ if (left <= right) {
+ Object tmp = this.sortedObjects[left];
+ this.sortedObjects[left] = this.sortedObjects[right];
+ this.sortedObjects[right] = tmp;
+ String tmpToString = this.sortedStrings[left];
+ this.sortedStrings[left] = this.sortedStrings[right];
+ this.sortedStrings[right] = tmpToString;
+ left++;
+ right--;
+ }
+ }
+ while (left <= right);
+
+ if (originalLeft < right)
+ quickSort(originalLeft, right);
+ if (left < originalRight)
+ quickSort(left, originalRight);
+ }
+
+ /**
+ * Return a new sorted collection from this unsorted collection.
+ * Sort using quick sort.
+ */
+ public void sort(Object[] unSortedObjects, String[] unsortedStrings) {
+ int size = unSortedObjects.length;
+ this.sortedObjects = new Object[size];
+ this.sortedStrings = new String[size];
+
+ //copy the array so can return a new sorted collection
+ System.arraycopy(unSortedObjects, 0, this.sortedObjects, 0, size);
+ System.arraycopy(unsortedStrings, 0, this.sortedStrings, 0, size);
+ if (size > 1)
+ quickSort(0, size - 1);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/plugin.jars b/org.eclipse.jdt.core/plugin.jars
new file mode 100644
index 0000000000..c6ba09bf88
--- /dev/null
+++ b/org.eclipse.jdt.core/plugin.jars
@@ -0,0 +1,8 @@
+jdtcore.jar=\
+ Eclipse Java Batch Compiler,\
+ Eclipse Java Code Assist,\
+ Eclipse Java Formatter,\
+ Eclipse Java Compiler,\
+ Eclipse Java Evaluation,\
+ Eclipse Java Core Search,\
+ Eclipse Java Model
diff --git a/org.eclipse.jdt.core/plugin.xml b/org.eclipse.jdt.core/plugin.xml
new file mode 100644
index 0000000000..2e4de1fb7f
--- /dev/null
+++ b/org.eclipse.jdt.core/plugin.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0"?>
+
+<plugin
+ name = "Java Development Tools Core"
+ id = "org.eclipse.jdt.core"
+ version = "0.9"
+ vendor-name = "Object Technology International, Inc."
+ class="org.eclipse.jdt.core.JavaCore">
+
+
+<!-- =========================================================================== -->
+<!-- The Java Development Tools Core Plugin -->
+<!-- {purpose goes here} -->
+<!-- =========================================================================== -->
+
+<requires>
+ <import plugin="org.eclipse.core.resources"/>
+ <import plugin="org.apache.xerces"/>
+</requires>
+
+<runtime>
+ <library name="jdtcore.jar">
+ <export name = "*"/>
+ </library>
+</runtime>
+
+<extension
+ point="org.eclipse.core.resources.natures"
+ id="javanature"
+ name="Java Nature">
+ <runtime>
+ <run class="org.eclipse.jdt.internal.core.JavaProject">
+ </run>
+ </runtime>
+</extension>
+
+<extension
+ point="org.eclipse.core.resources.builders"
+ id="javabuilder"
+ name="Java Builder">
+ <builder>
+ <run class="org.eclipse.jdt.internal.core.builder.impl.JavaBuilder">
+ <!-- Debug Information. Local variable attribute. Generate|Do not generate -->
+ <parameter name="compilerOption1" value="0"/>
+
+ <!-- Debug Information. Line number attribute. Generate|Do not generate -->
+ <parameter name="compilerOption2" value="0"/>
+
+ <!-- Debug Information. Source file attribute. Generate|Do not generate -->
+ <parameter name="compilerOption3" value="0"/>
+
+ <!-- Code Generation. Preserve unused locals. Preserve|Optimize out -->
+ <parameter name="compilerOption4" value="0"/>
+
+ <!-- Optional Warnings. Unused local variable. Warn|Ignore -->
+ <parameter name="compilerOption11" value="1"/>
+
+ <!-- Optional Warnings. Unused parameter. Warn|Ignore -->
+ <parameter name="compilerOption12" value="1"/>
+ </run>
+ </builder>
+</extension>
+
+<extension id="problem" point="org.eclipse.core.resources.markers" name="Java Problem">
+ <super type="org.eclipse.core.resources.problemmarker"/>
+ <super type="org.eclipse.core.resources.textmarker"/>
+ <persistent value="true"/>
+ <attribute name="id"/>
+ <attribute name="flags"/>
+</extension>
+<extension id="transient_problem" point="org.eclipse.core.resources.markers" name="Transient Java Problem">
+ <super type="org.eclipse.core.resources.textmarker"/>
+ <persistent value="false"/>
+ <attribute name="id"/>
+ <attribute name="flags"/>
+ <attribute name="cycleDetected"/>
+</extension>
+
+</plugin>
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchConstants.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchConstants.java
new file mode 100644
index 0000000000..10adfef9b0
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchConstants.java
@@ -0,0 +1,125 @@
+package org.eclipse.jdt.core.search;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.search.processing.*;
+
+/**
+ * <p>
+ * This interface defines the constants used by the search engine.
+ * </p>
+ * <p>
+ * This interface declares constants only; it is not intended to be implemented.
+ * </p>
+ * @see org.eclipse.jdt.core.search.SearchEngine
+ */
+public interface IJavaSearchConstants {
+
+ /**
+ * The nature of searched element or the nature
+ * of match in unknown.
+ */
+ int UNKNOWN = -1;
+
+ /* Nature of searched element */
+
+ /**
+ * The searched element is a type.
+ */
+ int TYPE = 0;
+ /**
+ * The searched element is a method.
+ */
+ int METHOD = 1;
+ /**
+ * The searched element is a package.
+ */
+ int PACKAGE = 2;
+ /**
+ * The searched element is a constructor.
+ */
+ int CONSTRUCTOR = 3;
+ /**
+ * The searched element is a field.
+ */
+ int FIELD = 4;
+ /**
+ * The searched element is a class.
+ */
+ int CLASS = 5;
+ /**
+ * The searched element is an interface.
+ */
+ int INTERFACE = 6;
+
+ /* Nature of match */
+
+ /**
+ * The search result is a declaration.
+ */
+ int DECLARATIONS = 0;
+ /**
+ * The search result is a type that implements an interface.
+ */
+ int IMPLEMENTORS = 1;
+ /**
+ * The search result is a reference.
+ */
+ int REFERENCES = 2;
+ /**
+ * The search result is a declaration, a reference, or an implementor
+ * of an interface.
+ */
+ int ALL_OCCURRENCES = 3;
+
+ /* Syntactic match modes */
+
+ /**
+ * The search pattern matches exactly the search result,
+ * i.e. the source of the search result equals the search pattern.
+ */
+ int EXACT_MATCH = 0;
+ /**
+ * The search pattern is a prefix of the search result.
+ */
+ int PREFIX_MATCH = 1;
+ /**
+ * The search pattern contains one or more wild-cards ('*') where a
+ * wild-card can replace 0 or more characters in the search result.
+ */
+ int PATTERN_MATCH = 2;
+
+ /* Case sensitivity */
+
+ /**
+ * The search pattern matches the search result only
+ * if case are the same.
+ */
+ boolean CASE_SENSITIVE = true;
+ /**
+ * The search pattern ignores cases in the search result.
+ */
+ boolean CASE_INSENSITIVE = false;
+
+ /* Waiting policies */
+
+ /**
+ * The search operation starts immediately, even if the underlying indexer
+ * has not finished indexing the workspace. Results will more likely
+ * not contain all the matches.
+ */
+ int FORCE_IMMEDIATE_SEARCH = IJobConstants.ForceImmediate;
+ /**
+ * The search operation throws an <code>org.eclipse.core.runtime.OperationCanceledException</code>
+ * if the underlying indexer has not finished indexing the workspace.
+ */
+ int CANCEL_IF_NOT_READY_TO_SEARCH = IJobConstants.CancelIfNotReady;
+ /**
+ * The search operation waits for the underlying indexer to finish indexing
+ * the workspace before starting the search.
+ */
+ int WAIT_UNTIL_READY_TO_SEARCH = IJobConstants.WaitUntilReady;
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchResultCollector.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchResultCollector.java
new file mode 100644
index 0000000000..8c06406f97
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchResultCollector.java
@@ -0,0 +1,84 @@
+package org.eclipse.jdt.core.search;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.JavaModelException;
+
+/**
+ * A <code>IJavaSearchResultCollector<code> collects search results from a <code>search</code>
+ * query to a <code>SearchEngine</code>. Clients must implement this interface and pass
+ * an instance to the <code>search(...)</code> methods. When a search starts, the <code>aboutToStart()</code>
+ * method is called, then 0 or more call to <code>accept(...)</code> are done, finally the
+ * <code>done()</code> method is called.
+ * <p>
+ * Results provided to this collector may be accurate - in this case they have an <code>EXACT_MATCH</code> accuracy -
+ * or they might be potential matches only - they have a <code>POTENTIAL_MATCH</code> accuracy. This last
+ * case can occur when a problem prevented the <code>SearchEngine</code> from resolving the match.
+ * </p>
+ * <p>
+ * The <code>IJavaSearchResultCollector<code> is also used to provide a progress monitor to the
+ * <code>SearchEngine</code>.
+ * </p>
+ * <p>
+ * Clients may implement this interface.
+ * </p>
+ *
+ * @see SearchEngine#search
+ */
+public interface IJavaSearchResultCollector {
+ /**
+ * The search result corresponds exactly to the search pattern.
+ */
+ int EXACT_MATCH = 0;
+
+ /**
+ * The search result is potentially a match for the search pattern,
+ * but a problem prevented the search engine from being more accurate
+ * (typically because of the classpath was not correctly set).
+ */
+ int POTENTIAL_MATCH = 1;
+
+ /**
+ * Called before the actual search starts.
+ */
+ public void aboutToStart();
+ /**
+ * Accepts the given search result.
+ *
+ * @param resource the resource in which the match has been found
+ * @param start the start position of the match, -1 if it is unknown
+ * @param end the end position of the match, -1 if it is unknown;
+ * the ending offset is exclusive, meaning that the actual range of characters
+ * covered is <code>[start, end]</code>
+ * @param enclosingElement the Java element that contains the character range
+ * <code>[start, end]</code>; the value can be <code>null</code> indicating that
+ * no enclosing Java element has been found
+ * @param accuracy the level of accuracy the search result has; either
+ * <code>EXACT_MATCH</code> or <code>POTENTIAL_MATCH</code>
+ * @exception CoreException if this collector had a problem accepting the search result
+ */
+ public void accept(
+ IResource resource,
+ int start,
+ int end,
+ IJavaElement enclosingElement,
+ int accuracy)
+ throws CoreException;
+ /**
+ * Called when the search has ended.
+ */
+ public void done();
+ /**
+ * Returns the progress monitor used to setup and report progress.
+ *
+ * @return a progress monitor or null if no progress monitor is provided
+ */
+ public IProgressMonitor getProgressMonitor();
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchScope.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchScope.java
new file mode 100644
index 0000000000..4ff51a164a
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchScope.java
@@ -0,0 +1,78 @@
+package org.eclipse.jdt.core.search;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.internal.core.index.impl.JarFileEntryDocument;
+
+/**
+ * An <code>IJavaSearchScope</code> defines where search result should be found by a
+ * <code>SearchEngine</code>. Clients must pass an instance of this interface
+ * to the <code>search(...)</code> methods. Such an instance can be created using the
+ * following factory methods on <code>SearchEngine</code>: <code>createHierarchyScope(IType)</code>,
+ * <code>createJavaSearchScope(IResource[])</code>, <code>createWorkspaceScope()</code>, or
+ * clients may choose to implement this interface.
+ */
+public interface IJavaSearchScope {
+ /**
+ * This constant defines the separator the resourcePath string of the <code>encloses(String)</code>
+ * method. If present in the string, it separates the path to the jar file from the path
+ * to the .class file in the jar.
+ */
+ String JAR_FILE_ENTRY_SEPARATOR = JarFileEntryDocument.JAR_FILE_ENTRY_SEPARATOR;
+ /**
+ * Checks whether the resource at the given path is enclosed by this scope.
+ *
+ * @param resourcePath if the resource is contained in
+ * a JAR file, the path is composed of 2 paths separated
+ * by <code>JAR_FILE_ENTRY_SEPARATOR</code>: the first path is the full OS path
+ * to the JAR, the second path is the path to the resource inside the JAR.
+ * @return whether the resourse is enclosed by this scope
+ */
+ public boolean encloses(String resourcePath);
+ /**
+ * Checks whether this scope encloses the given element.
+ *
+ * @param the element
+ * @return <code>true</code> if the element is in this scope
+ */
+ public boolean encloses(IJavaElement element);
+ /**
+ * Returns the paths to the enclosing projects and JARs for this search scope.
+ *
+ * @return an array of paths to the enclosing projects and JARS. A project path is
+ * the full path to the project. A JAR path is the full OS path to the JAR file.
+ */
+ IPath[] enclosingProjectsAndJars();
+ /**
+ * Returns whether this scope contains any <code>.class</code> files (either
+ * in folders or within JARs).
+ *
+ * @return whether this scope contains any <code>.class</code> files
+ */
+ boolean includesBinaries();
+ /**
+ * Returns whether this scope includes classpaths defined by
+ * the projects of the resources of this search scope.
+ *
+ * @return whether this scope includes classpaths
+ */
+ boolean includesClasspaths();
+ /**
+ * Sets whether this scope contains any <code>.class</code> files (either
+ * in folders or within JARs).
+ *
+ * @param includesBinaries whether this scope contains any <code>.class</code> files
+ */
+ public void setIncludesBinaries(boolean includesBinaries);
+ /**
+ * Sets whether this scope includes the classpaths defined by
+ * the projects of the resources of this search scope.
+ *
+ * @return includesClasspaths whether this scope includes classpaths
+ */
+ public void setIncludesClasspaths(boolean includesClasspaths);
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ISearchPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ISearchPattern.java
new file mode 100644
index 0000000000..ff7c7ddea1
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ISearchPattern.java
@@ -0,0 +1,16 @@
+package org.eclipse.jdt.core.search;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.core.*;
+
+/**
+ * A search pattern defines how search results are found. Use <code>SearchEngine.createSearchPattern</code>
+ * to create a search pattern.
+ *
+ * @see SearchEngine#createSearchPattern
+ */
+public interface ISearchPattern {
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ITypeNameRequestor.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ITypeNameRequestor.java
new file mode 100644
index 0000000000..9d8a9688a7
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ITypeNameRequestor.java
@@ -0,0 +1,42 @@
+package org.eclipse.jdt.core.search;
+
+public interface ITypeNameRequestor {
+ /**
+ * Accepts a top-level or a member class.
+ *
+ * @param packageName the dot-separated name of the package of the class
+ * @param simpleTypeName the simple name of the class
+ * @param enclosingTypeNames if the class is a member type,
+ * the simple names of the enclosing types from the outer-most to the
+ * direct parent of the class (e.g. if the class is x.y.A$B$C then
+ * the enclosing types are [A, B]. This is an empty array if the class
+ * is a top-level type.
+ * @param path the full path to the resource containing the class. If the resource is a .class file
+ * or a .java file, this is the full path in the workspace to this resource. If the
+ * resource is a .zip or .jar file, this is the full OS path to this file.
+ */
+ void acceptClass(
+ char[] packageName,
+ char[] simpleTypeName,
+ char[][] enclosingTypeNames,
+ String path);
+ /**
+ * Accepts a top-level or a member interface.
+ *
+ * @param packageName the dot-separated name of the package of the interface
+ * @param simpleTypeName the simple name of the interface
+ * @param enclosingTypeNames if the interface is a member type,
+ * the simple names of the enclosing types from the outer-most to the
+ * direct parent of the interface (e.g. if the interface is x.y.A$B$I then
+ * the enclosing types are [A, B]. This is an empty array if the interface
+ * is a top-level type.
+ * @param path the full path to the resource containing the interface. If the resource is a .class file
+ * or a .java file, this is the full path in the workspace to this resource. If the
+ * resource is a .zip or .jar file, this is the full OS path to this file.
+ */
+ void acceptInterface(
+ char[] packageName,
+ char[] simpleTypeName,
+ char[][] enclosingTypeNames,
+ String path);
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchEngine.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchEngine.java
new file mode 100644
index 0000000000..b2e9c50fcc
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchEngine.java
@@ -0,0 +1,634 @@
+package org.eclipse.jdt.core.search;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.core.*;
+import org.eclipse.jdt.internal.core.search.HierarchyScope;
+import org.eclipse.jdt.internal.core.search.IndexSearchAdapter;
+import org.eclipse.jdt.internal.core.search.IIndexSearchRequestor;
+import org.eclipse.jdt.internal.core.search.IInfoConstants;
+import org.eclipse.jdt.internal.core.search.JavaSearchScope;
+import org.eclipse.jdt.internal.core.search.JavaWorkspaceScope;
+import org.eclipse.jdt.internal.core.search.PatternSearchJob;
+import org.eclipse.jdt.internal.core.search.PathCollector;
+import org.eclipse.jdt.internal.core.search.indexing.*;
+import org.eclipse.jdt.internal.core.search.matching.*;
+
+import java.util.*;
+
+/**
+ * A <code>SearchEngine</code> searches for java elements following a search pattern.
+ * The search can be limited to a search scope.
+ * <p>
+ * Various search patterns can be created using the factory methods
+ * <code>createSearchPattern(String, int, int, boolean)</code>, <code>createSearchPattern(IJavaElement, int)</code>,
+ * <code>createOrSearchPattern(ISearchPattern, ISearchPattern)</code>.
+ * </p>
+ * <p>For example, one can search for references to a method in the hierarchy of a type,
+ * or one can search for the declarations of types starting with "Abstract" in a project.
+ * </p>
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ */
+public class SearchEngine {
+ /**
+ * Returns a java search scope limited to the hierarchy of the given type.
+ * The java elements resulting from a search with this scope will
+ * be types in this hierarchy, or members of the types in this hierarchy.
+ *
+ * @param type the focus of the hierarchy scope
+ * @return a new hierarchy scope
+ * @exception JavaModelException if the hierarchy could not be computed on the given type
+ */
+ public static IJavaSearchScope createHierarchyScope(IType type)
+ throws JavaModelException {
+ return new HierarchyScope(type);
+ }
+
+ /**
+ * Returns a java search scope limited to the given resources.
+ * The java elements resulting from a search with this scope will
+ * have their underlying resource included in or equals to one of the given
+ * resources.
+ * <p>
+ * Resources must not overlap, e.g. one cannot include a folder and its children.
+ * </p>
+ *
+ * @param resources the resources the scope is limited to
+ * @return a new java search scope
+ */
+ public static IJavaSearchScope createJavaSearchScope(IResource[] resources) {
+ JavaSearchScope scope = new JavaSearchScope();
+ for (int i = 0, length = resources.length; i < length; i++) {
+ scope.add(resources[i]);
+ }
+ return scope;
+ }
+
+ /**
+ * Returns a search pattern that combines the given two patterns into a "or" pattern.
+ * The search result will match either the left pattern or the right pattern.
+ *
+ * @param leftPattern the left pattern
+ * @param rightPattern the right pattern
+ * @return a "or" pattern
+ */
+ public static ISearchPattern createOrSearchPattern(
+ ISearchPattern leftPattern,
+ ISearchPattern rightPattern) {
+ return new OrPattern((SearchPattern) leftPattern, (SearchPattern) rightPattern);
+ }
+
+ /**
+ * Returns a search pattern based on a given string pattern. The string patterns support '*' wild-cards.
+ * The remaining parameters are used to narrow down the type of expected results.
+ *
+ * <p>
+ * Examples:
+ * <ul>
+ * <li>search for case insensitive references to <code>Object</code>:
+ * <code>createSearchPattern("Object", TYPE, REFERENCES, false);</code>
+ * <li>search for case sensitive references to exact <code>Object()</code> constructor:
+ * <code>createSearchPattern("java.lang.Object()", CONSTRUCTOR, REFERENCES, true);</code>
+ * <li>search for implementors of <code>java.lang.Runnable</code>:
+ * <code>createSearchPattern("java.lang.Runnable", TYPE, IMPLEMENTORS, true);</code>
+ * @param searchFor determines the nature of the searched elements
+ * <ul>
+ * <li><code>IJavaSearchConstants.CLASS</code>: only look for classes
+ * <li><code>IJavaSearchConstants.INTERFACE</code>: only look for interfaces
+ * <li><code>IJavaSearchConstants.TYPE</code>: look for both classes and interfaces
+ * <li><code>IJavaSearchConstants.FIELD</code>: look for fields
+ * <li><code>IJavaSearchConstants.METHOD</code>: look for methods
+ * <li><code>IJavaSearchConstants.CONSTRUCTOR</code>: look for constructors
+ * <li><code>IJavaSearchConstants.PACKAGE</code>: look for packages
+ * </ul>
+ * @param limitTo determines the nature of the expected matches
+ * <ul>
+ * <li><code>IJavaSearchConstants.DECLARATIONS</code>: will search declarations matching with the corresponding
+ * element. In case the element is a method, declarations of matching methods in subtypes will also
+ * be found, allowing to find declarations of abstract methods, etc.
+ *
+ * <li><code>IJavaSearchConstants.REFERENCES</code>: will search references to the given element.
+ *
+ * <li><code>IJavaSearchConstants.ALL_OCCURRENCES</code>: will search for either declarations or references as specified
+ * above.
+ *
+ * <li><code>IJavaSearchConstants.IMPLEMENTORS</code>: for interface, will find all types which implements a given interface.
+ * </ul>
+ *
+ * @param isCaseSensitive indicates whether the search is case sensitive or not.
+ * @return a search pattern on the given string pattern, or <code>null</code> if the string pattern is ill-formed.
+ */
+ public static ISearchPattern createSearchPattern(
+ String stringPattern,
+ int searchFor,
+ int limitTo,
+ boolean isCaseSensitive) {
+
+ return SearchPattern.createPattern(
+ stringPattern,
+ searchFor,
+ limitTo,
+ IJavaSearchConstants.PATTERN_MATCH,
+ isCaseSensitive);
+ }
+
+ /**
+ * Returns a search pattern based on a given Java element.
+ * The pattern is used to trigger the appropriate search, and can be parameterized as follows:
+ *
+ * @param element the java element the search pattern is based on
+ * @param limitTo determines the nature of the expected matches
+ * <ul>
+ * <li><code>IJavaSearchConstants.DECLARATIONS</code>: will search declarations matching with the corresponding
+ * element. In case the element is a method, declarations of matching methods in subtypes will also
+ * be found, allowing to find declarations of abstract methods, etc.
+ *
+ * <li><code>IJavaSearchConstants.REFERENCES</code>: will search references to the given element.
+ *
+ * <li><code>IJavaSearchConstants.ALL_OCCURRENCES</code>: will search for either declarations or references as specified
+ * above.
+ *
+ * <li><code>IJavaSearchConstants.IMPLEMENTORS</code>: for interface, will find all types which implements a given interface.
+ * </ul>
+ * @return a search pattern for a java element or <code>null</code> if the given element is ill-formed
+ */
+ public static ISearchPattern createSearchPattern(
+ IJavaElement element,
+ int limitTo) {
+
+ return SearchPattern.createPattern(element, limitTo);
+ }
+
+ /**
+ * Returns a java search scope with the workspace as the only limit.
+ *
+ * @return a new workspace scope
+ */
+ public static IJavaSearchScope createWorkspaceScope() {
+ return new JavaWorkspaceScope();
+ }
+
+ /**
+ * Searches for the Java element determined by the given signature. The signature
+ * can be incomplete. For example, a call like
+ * <code>search(ws,"run()",METHOD,REFERENCES,col)</code>
+ * searchs for all references to the method <code>run</code>.
+ *
+ * @param workspace the workspace
+ * @param pattern the pattern to be searched for
+ * @param searchFor a hint what kind of Java element the string pattern represents.
+ * Look into <code>IJavaSearchConstants</code> for valid values
+ * @param limitTo one of the following values:
+ * <ul>
+ * <li><code>IJavaSearchConstants.DECLARATIONS</code>: search
+ * for declarations only </li>
+ * <li><code>IJavaSearchConstants.REFERENCES</code>: search
+ * for all references </li>
+ * <li><code>IJavaSearchConstants.ALL_OCCURENCES</code>: search
+ * for both declarations and all references </li>
+ * <li><code>IJavaSearchConstants.IMPLEMENTORS</code>: search for
+ * all implementors of an interface; the value is only valid if
+ * the Java element represents an interface
+ * </ul>
+ * @param scope the search result has to be limited to the given scope
+ * @param resultCollector a callback object to which each match is reported
+ * @exception JavaModelException if the search failed. Reasons include:
+ * <ul>
+ * <li>the classpath is incorrectly set
+ * </ul>
+ */
+ public void search(
+ IWorkspace workspace,
+ String patternString,
+ int searchFor,
+ int limitTo,
+ IJavaSearchScope scope,
+ IJavaSearchResultCollector resultCollector)
+ throws JavaModelException {
+
+ search(
+ workspace,
+ createSearchPattern(patternString, searchFor, limitTo, true),
+ scope,
+ resultCollector);
+ }
+
+ /**
+ * Searches for the given Java element.
+ *
+ * @param workspace the workspace
+ * @param element the Java element to be searched for
+ * @param limitTo one of the following values:
+ * <ul>
+ * <li><code>IJavaSearchConstants.DECLARATIONS</code>: search
+ * for declarations only </li>
+ * <li><code>IJavaSearchConstants.REFERENCES</code>: search
+ * for all references </li>
+ * <li><code>IJavaSearchConstants.ALL_OCCURENCES</code>: search
+ * for both declarations and all references </li>
+ * <li><code>IJavaSearchConstants.IMPLEMENTORS</code>: search for
+ * all implementors of an interface; the value is only valid if
+ * the Java element represents an interface
+ * </ul>
+ * @param scope the search result has to be limited to the given scope
+ * @param resultCollector a callback object to which each match is reported
+ * @exception JavaModelException if the search failed. Reasons include:
+ * <ul>
+ * <li>the element doesn't exist
+ * <li>the classpath is incorrectly set
+ * </ul>
+ */
+ public void search(
+ IWorkspace workspace,
+ IJavaElement element,
+ int limitTo,
+ IJavaSearchScope scope,
+ IJavaSearchResultCollector resultCollector)
+ throws JavaModelException {
+
+ search(
+ workspace,
+ createSearchPattern(element, limitTo),
+ scope,
+ resultCollector);
+ }
+
+ /**
+ * Searches for matches of a given search pattern. Search patterns can be created using helper
+ * methods (from a String pattern or a Java element) and encapsulate the description of what is
+ * being searched (e.g. search method declarations in a case sensitive way).
+ *
+ * @param workspace the workspace
+ * @param searchPattern the pattern to be searched for
+ * @param scope the search result has to be limited to the given scope
+ * @param resultCollector a callback object to which each match is reported
+ * @exception JavaModelException if the search failed. Reasons include:
+ * <ul>
+ * <li>the classpath is incorrectly set
+ * </ul>
+ */
+ public void search(
+ IWorkspace workspace,
+ ISearchPattern searchPattern,
+ IJavaSearchScope scope,
+ IJavaSearchResultCollector resultCollector)
+ throws JavaModelException {
+
+ /* search is starting */
+ resultCollector.aboutToStart();
+
+ try {
+ if (searchPattern == null)
+ return;
+
+ /* initialize progress monitor */
+ IProgressMonitor progressMonitor = resultCollector.getProgressMonitor();
+ if (progressMonitor != null) {
+ progressMonitor.beginTask("Searching...", 105);
+ // 5 for getting paths, 100 for locating matches
+ }
+
+ /* index search */
+ PathCollector pathCollector = new PathCollector();
+
+ IndexManager indexManager =
+ ((JavaModelManager) JavaModelManager.getJavaModelManager()).getIndexManager();
+ int detailLevel = IInfoConstants.PathInfo | IInfoConstants.PositionInfo;
+ MatchLocator matchLocator =
+ new MatchLocator(
+ (SearchPattern) searchPattern,
+ detailLevel,
+ resultCollector,
+ scope);
+ if (indexManager != null) {
+ indexManager.performConcurrentJob(
+ new PatternSearchJob(
+ (SearchPattern) searchPattern,
+ scope,
+ detailLevel,
+ pathCollector,
+ indexManager,
+ progressMonitor),
+ IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
+ progressMonitor);
+
+ if (progressMonitor != null) {
+ progressMonitor.worked(5);
+ }
+
+ /* eliminating false matches and locating them */
+ if (progressMonitor != null && progressMonitor.isCanceled())
+ throw new OperationCanceledException();
+ matchLocator.locateMatches(pathCollector.getPaths(), workspace);
+ }
+
+ if (progressMonitor != null) {
+ progressMonitor.done();
+ }
+
+ matchLocator.locatePackageDeclarations(workspace);
+ } finally {
+ /* search has ended */
+ resultCollector.done();
+ }
+ }
+
+ /**
+ * Searches for all top-level types and member types in the given scope.
+ * The search can be selecting specific types (given a package or a type name
+ * prefix and match modes).
+ *
+ * @param workspace the workspace to search in
+ * @param packageName the full name of the package of the searched types, or a prefix for this
+ * package, or a wild-carded string for this package.
+ * @param typeName the dot-separated qualied name of the searched type (the qualification include
+ * the enclosing types if the searched type is a member type), or a prefix
+ * for this type, or a wild-carded string for this type.
+ * @param matchMode one of
+ * <ul>
+ * <li><code>IJavaSearchConstants.EXACT_MATCH</code> if the package name and type name are the full names
+ * of the searched types.
+ * <li><code>IJavaSearchConstants.PREFIX_MATCH</code> if the package name and type name are prefixes of the names
+ * of the searched types.
+ * <li><code>IJavaSearchConstants.PATTERN_MATCH</code> if the package name and type name contain wild-cards.
+ * </ul>
+ * @param isCaseSensitive whether the search should be case senistive
+ * @param searchFor one of
+ * <ul>
+ * <li><code>IJavaSearchConstants.CLASS</code> if searching for classes only
+ * <li><code>IJavaSearchConstants.INTERFACE</code> if searching for interfaces only
+ * <li><code>IJavaSearchConstants.TYPE</code> if searching for both classes and interfaces
+ * </ul>
+ * @param scope the scope to search in
+ * @param nameRequestor the requestor that collects the results of the search
+ * @param waitingPolicy one of
+ * <ul>
+ * <li><code>IJavaSearchConstants.FORCE_IMMEDIATE_SEARCH</code> if the search should start immediately
+ * <li><code>IJavaSearchConstants.CANCEL_IF_NOT_READY_TO_SEARCH</code> if the search should be canceled if the
+ * underlying indexer has not finished indexing the workspace
+ * <li><code>IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH</code> if the search should wait for the
+ * underlying indexer to finish indexing the workspace
+ * </ul>
+ * @param progressMonitor the progress monitor to report progress to, or <code>null</code> if no progress
+ * monitor is provided
+ * @exception JavaModelException if the search failed. Reasons include:
+ * <ul>
+ * <li>the classpath is incorrectly set
+ * </ul>
+ */
+ public void searchAllTypeNames(
+ IWorkspace workspace,
+ char[] packageName,
+ char[] typeName,
+ int matchMode,
+ boolean isCaseSensitive,
+ int searchFor,
+ IJavaSearchScope scope,
+ final ITypeNameRequestor nameRequestor,
+ int waitingPolicy,
+ IProgressMonitor progressMonitor)
+ throws JavaModelException {
+
+ IndexManager indexManager =
+ ((JavaModelManager) JavaModelManager.getJavaModelManager()).getIndexManager();
+ if (indexManager == null)
+ return;
+
+ char classOrInterface;
+ switch (searchFor) {
+ case IJavaSearchConstants.CLASS :
+ classOrInterface = IIndexConstants.CLASS_SUFFIX;
+ break;
+ case IJavaSearchConstants.INTERFACE :
+ classOrInterface = IIndexConstants.INTERFACE_SUFFIX;
+ break;
+ default :
+ classOrInterface = IIndexConstants.TYPE_SUFFIX;
+ break;
+ }
+ SearchPattern pattern =
+ new TypeDeclarationPattern(packageName, null, // do find member types
+ typeName, classOrInterface, matchMode, isCaseSensitive);
+
+ IIndexSearchRequestor searchRequestor = new IndexSearchAdapter() {
+ public void acceptClassDeclaration(
+ String resourcePath,
+ char[] simpleTypeName,
+ char[][] enclosingTypeNames,
+ char[] packageName) {
+ nameRequestor.acceptClass(
+ packageName,
+ simpleTypeName,
+ enclosingTypeNames,
+ resourcePath);
+ }
+ public void acceptInterfaceDeclaration(
+ String resourcePath,
+ char[] simpleTypeName,
+ char[][] enclosingTypeNames,
+ char[] packageName) {
+ nameRequestor.acceptInterface(
+ packageName,
+ simpleTypeName,
+ enclosingTypeNames,
+ resourcePath);
+ }
+ };
+
+ indexManager.performConcurrentJob(
+ new PatternSearchJob(
+ pattern,
+ scope,
+ IInfoConstants.NameInfo | IInfoConstants.PathInfo,
+ searchRequestor,
+ indexManager,
+ progressMonitor),
+ waitingPolicy,
+ progressMonitor);
+ }
+
+ /**
+ * Searches for all declarations of the fields accessed in the given element.
+ * The element can be a compilation unit, a type, or a method.
+ * Reports the field declarations using the given collector.
+ * <p>
+ * Consider the following code:
+ * <code>
+ * <pre>
+ * class A {
+ * int field1;
+ * }
+ * class B extends A {
+ * String value;
+ * }
+ * class X {
+ * void test() {
+ * B b = new B();
+ * System.out.println(b.value + b.field1);
+ * };
+ * }
+ * </pre>
+ * </code>
+ * then searching for declarations of accessed fields in method
+ * <code>X.test()</code> would collect the fields
+ * <code>B.value</code> and <code>A.field1</code>.
+ * </p>
+ *
+ * @param workspace the workspace
+ * @param enclosingElement the method, type, or compilation unit to be searched in
+ * @param resultCollector a callback object to which each match is reported
+ * @exception JavaModelException if the search failed. Reasons include:
+ * <ul>
+ * <li>the element doesn't exist
+ * <li>the classpath is incorrectly set
+ * </ul>
+ */
+ public void searchDeclarationsOfAccessedFields(
+ IWorkspace workspace,
+ IJavaElement enclosingElement,
+ IJavaSearchResultCollector resultCollector)
+ throws JavaModelException {
+ MatchLocator locator =
+ new MatchLocator(
+ (SearchPattern) createSearchPattern("*",
+ IJavaSearchConstants.FIELD,
+ IJavaSearchConstants.REFERENCES,
+ true),
+ IInfoConstants.DeclarationInfo,
+ resultCollector,
+ new JavaWorkspaceScope());
+ // TBD: limit search to type or method by passing start and end of enclosing element
+ locator.locateMatches(
+ new String[] {
+ enclosingElement.getUnderlyingResource().getFullPath().toString()},
+ workspace);
+ }
+
+ /**
+ * Searches for all declarations of the types referenced in the given element.
+ * The element can be a compilation unit, a type, or a method.
+ * Reports the type declarations using the given collector.
+ * <p>
+ * Consider the following code:
+ * <code>
+ * <pre>
+ * class A {
+ * }
+ * class B extends A {
+ * }
+ * interface I {
+ * int VALUE = 0;
+ * }
+ * class X {
+ * void test() {
+ * B b = new B();
+ * this.foo(b, I.VALUE);
+ * };
+ * }
+ * </pre>
+ * <code>
+ * then searching for declarations of referenced types in method <code>X.test()</code>
+ * would collect the class <code>B</code> and the interface <code>I</code>.
+ * </p>
+ *
+ * @param workspace the workspace
+ * @param enclosingElement the method, type, or compilation unit to be searched in
+ * @param resultCollector a callback object to which each match is reported
+ * @exception JavaModelException if the search failed. Reasons include:
+ * <ul>
+ * <li>the element doesn't exist
+ * <li>the classpath is incorrectly set
+ * </ul>
+ */
+ public void searchDeclarationsOfReferencedTypes(
+ IWorkspace workspace,
+ IJavaElement enclosingElement,
+ IJavaSearchResultCollector resultCollector)
+ throws JavaModelException {
+ MatchLocator locator =
+ new MatchLocator(
+ (SearchPattern) createSearchPattern("*",
+ IJavaSearchConstants.TYPE,
+ IJavaSearchConstants.REFERENCES,
+ true),
+ IInfoConstants.DeclarationInfo,
+ resultCollector,
+ new JavaWorkspaceScope());
+ // TBD: limit search to type or method by passing start and end of enclosing element
+ locator.locateMatches(
+ new String[] {
+ enclosingElement.getUnderlyingResource().getFullPath().toString()},
+ workspace);
+ }
+
+ /**
+ * Searches for all declarations of the methods invoked in the given element.
+ * The element can be a compilation unit, a type, or a method.
+ * Reports the method declarations using the given collector.
+ * <p>
+ * Consider the following code:
+ * <code>
+ * <pre>
+ * class A {
+ * void foo() {};
+ * void bar() {};
+ * }
+ * class B extends A {
+ * void foo() {};
+ * }
+ * class X {
+ * void test() {
+ * A a = new B();
+ * a.foo();
+ * B b = (B)a;
+ * b.bar();
+ * };
+ * }
+ * </pre>
+ * </code>
+ * then searching for declarations of sent messages in method
+ * <code>X.test()</code> would collect the methods
+ * <code>A.foo()</code>, <code>B.foo()</code>, and <code>A.bar()</code>.
+ * </p>
+ *
+ * @param workspace the workspace
+ * @param enclosingElement the method, type, or compilation unit to be searched in
+ * @param resultCollector a callback object to which each match is reported
+ * @exception JavaModelException if the search failed. Reasons include:
+ * <ul>
+ * <li>the element doesn't exist
+ * <li>the classpath is incorrectly set
+ * </ul>
+ */
+ public void searchDeclarationsOfSentMessages(
+ IWorkspace workspace,
+ IJavaElement enclosingElement,
+ IJavaSearchResultCollector resultCollector)
+ throws JavaModelException {
+ MatchLocator locator =
+ new MatchLocator(
+ (SearchPattern) createSearchPattern("*",
+ IJavaSearchConstants.METHOD,
+ IJavaSearchConstants.REFERENCES,
+ true),
+ IInfoConstants.DeclarationInfo,
+ resultCollector,
+ new JavaWorkspaceScope());
+ // TBD: limit search to type or method by passing start and end of enclosing element
+ locator.locateMatches(
+ new String[] {
+ enclosingElement.getUnderlyingResource().getFullPath().toString()},
+ workspace);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DocumentFactory.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DocumentFactory.java
new file mode 100644
index 0000000000..622cf10c5d
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DocumentFactory.java
@@ -0,0 +1,23 @@
+package org.eclipse.jdt.internal.core.index;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.internal.core.index.impl.*;
+
+import java.io.*;
+
+public class DocumentFactory {
+
+ public static IDocument newDocument(File file) {
+ return new FileDocument(file);
+ }
+
+ public static IDocument newDocument(IFile file) {
+ return new IFileDocument(file);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IDocument.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IDocument.java
new file mode 100644
index 0000000000..4fe20fa362
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IDocument.java
@@ -0,0 +1,54 @@
+package org.eclipse.jdt.internal.core.index;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.IOException;
+
+/**
+ * An <code>IDocument</code> represent a data source, e.g. a <code>File</code> (<code>FileDocument</code>),
+ * an <code>IFile</code> (<code>IFileDocument</code>),
+ * or other kinds of data sources (URL, ...). An <code>IIndexer</code> indexes an<code>IDocument</code>.
+ * <br>
+ * A document has a set of properties, saved in the index file (so one does not need to open the document
+ * to obtain basic information as: date of creation of the document, sum up, ...). A property is a String
+ * (called property) associated to a value (String). Example: "date_creation"->"02/08/2000".
+ */
+
+public interface IDocument {
+ /**
+ * Returns the content of the document, in a byte array.
+ */
+ byte[] getByteContent() throws IOException;
+ /**
+ * Returns the content of the document, in a char array.
+ */
+ char[] getCharContent() throws IOException;
+ /**
+ * returns the name of the document (e.g. its path for a <code>File</code>, or its relative path
+ * in the workbench for an <code>IFile</code>).
+ */
+ String getName();
+ /**
+ * returns the value of the given property, or null if this document does not have
+ * such a property.
+ */
+ String getProperty(String property);
+ /**
+ * Returns an enumeration of the names of the properties the document has.
+ */
+ java.util.Enumeration getPropertyNames();
+ /**
+ * Returns the content of the document, as a String.
+ */
+ public String getStringContent() throws IOException;
+ /**
+ * Returns the type of the document.
+ */
+ String getType();
+ /**
+ * Sets the given property of the document to the given value.
+ */
+ void setProperty(String attribute, String value);
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IEntryResult.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IEntryResult.java
new file mode 100644
index 0000000000..d5c54fda63
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IEntryResult.java
@@ -0,0 +1,6 @@
+package org.eclipse.jdt.internal.core.index;
+
+public interface IEntryResult {
+ public int[] getFileReferences();
+ public char[] getWord();
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IIndex.java
new file mode 100644
index 0000000000..8e8b4be005
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IIndex.java
@@ -0,0 +1,67 @@
+package org.eclipse.jdt.internal.core.index;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+
+/**
+ * An IIndex is the interface used to generate an index file, and to make queries on
+ * this index.
+ */
+
+public interface IIndex {
+ /**
+ * Adds the given document to the index.
+ */
+ void add(IDocument document, IIndexer indexer) throws IOException;
+ /**
+ * Empties the index.
+ */
+ void empty() throws IOException;
+ /**
+ * Returns the index file on the disk.
+ */
+ File getIndexFile();
+ /**
+ * Returns the number of documents indexed.
+ */
+ int getNumDocuments() throws IOException;
+ /**
+ * Returns the number of unique words indexed.
+ */
+ int getNumWords() throws IOException;
+ /**
+ * Returns the path corresponding to a given document number
+ */
+ String getPath(int documentNumber) throws IOException;
+ /**
+ * Ansers true if has some changes to save.
+ */
+ boolean hasChanged();
+ /**
+ * Returns the paths of the documents containing the given word.
+ */
+ IQueryResult[] query(String word) throws IOException;
+ /**
+ * Returns all entries for a given word.
+ */
+ IEntryResult[] queryEntries(char[] pattern) throws IOException;
+ /**
+ * Returns the paths of the documents whose names contain the given word.
+ */
+ IQueryResult[] queryInDocumentNames(String word) throws IOException;
+ /**
+ * Returns the paths of the documents containing the given word prefix.
+ */
+ IQueryResult[] queryPrefix(char[] prefix) throws IOException;
+ /**
+ * Removes the corresponding document from the index.
+ */
+ void remove(String documentName) throws IOException;
+ /**
+ * Saves the index on the disk.
+ */
+ void save() throws IOException;
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IIndexer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IIndexer.java
new file mode 100644
index 0000000000..dcd5ac90ce
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IIndexer.java
@@ -0,0 +1,28 @@
+package org.eclipse.jdt.internal.core.index;
+
+public interface IIndexer {
+ /**
+ * Returns the file types the <code>IIndexer</code> handles.
+ */
+
+ String[] getFileTypes();
+ /**
+ * Indexes the given document, adding the document name and the word references
+ * to this document to the given <code>IIndex</code>.The caller should use
+ * <code>shouldIndex()</code> first to determine whether this indexer handles
+ * the given type of file, and only call this method if so.
+ */
+
+ void index(IDocument document, IIndexerOutput output)
+ throws java.io.IOException;
+ /**
+ * Sets the document types the <code>IIndexer</code> handles.
+ */
+
+ public void setFileTypes(String[] fileTypes);
+ /**
+ * Returns whether the <code>IIndexer</code> can index the given document or not.
+ */
+
+ public boolean shouldIndex(IDocument document);
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IIndexerOutput.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IIndexerOutput.java
new file mode 100644
index 0000000000..337098c3f3
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IIndexerOutput.java
@@ -0,0 +1,19 @@
+package org.eclipse.jdt.internal.core.index;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+import java.util.Vector;
+
+/**
+ * This class represents the output from an indexer to an index
+ * for a single document.
+ */
+
+public interface IIndexerOutput {
+ public void addDocument(IDocument document);
+ public void addRef(char[] word);
+ public void addRef(String word);
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IQueryResult.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IQueryResult.java
new file mode 100644
index 0000000000..901a98a33b
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IQueryResult.java
@@ -0,0 +1,8 @@
+package org.eclipse.jdt.internal.core.index;
+
+public interface IQueryResult {
+ String getPath();
+ String getProperty(String propertyName);
+ java.util.Enumeration getPropertyNames();
+ String propertiesToString();
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IndexFactory.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IndexFactory.java
new file mode 100644
index 0000000000..d8c83e3301
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IndexFactory.java
@@ -0,0 +1,30 @@
+package org.eclipse.jdt.internal.core.index;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.index.impl.*;
+import java.io.*;
+
+public class IndexFactory {
+
+ public static IIndex newIndex(File indexDirectory) throws IOException {
+ return new Index(indexDirectory);
+ }
+
+ public static IIndex newIndex(File indexDirectory, String indexName)
+ throws IOException {
+ return new Index(indexDirectory, indexName);
+ }
+
+ public static IIndex newIndex(String indexName) throws IOException {
+ return new Index(indexName);
+ }
+
+ public static IIndex newIndex(String indexName, String toString)
+ throws IOException {
+ return new Index(indexName, toString);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Block.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Block.java
new file mode 100644
index 0000000000..5a18cda102
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Block.java
@@ -0,0 +1,59 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+
+/**
+ * A block is a container that can hold information (a list of file names, a list of
+ * words, ...), be saved on the disk and loaded in memory.
+ */
+
+public abstract class Block {
+ /**
+ * Size of the block
+ */
+ protected int blockSize;
+
+ /**
+ * Field in which the information is stored
+ */
+ protected Field field;
+
+ public Block(int blockSize) {
+ this.blockSize = blockSize;
+ field = new Field(blockSize);
+ }
+
+ /**
+ * Empties the block.
+ */
+ public void clear() {
+ field.clear();
+ }
+
+ /**
+ * Flushes the block
+ */
+ public void flush() {
+ }
+
+ /**
+ * Loads the block with the given number in memory, reading it from a RandomAccessFile.
+ */
+ public void read(RandomAccessFile raf, int blockNum) throws IOException {
+ raf.seek(blockNum * (long) blockSize);
+ raf.readFully(field.buffer());
+ }
+
+ /**
+ * Writes the block in a RandomAccessFile, giving it a block number.
+ */
+ public void write(RandomAccessFile raf, int blockNum) throws IOException {
+ raf.seek(blockNum * (long) blockSize);
+ raf.write(field.buffer());
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/BlocksIndexInput.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/BlocksIndexInput.java
new file mode 100644
index 0000000000..e715a14c26
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/BlocksIndexInput.java
@@ -0,0 +1,428 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * This input is used for reading indexes saved using a BlocksIndexOutput.
+ */
+public class BlocksIndexInput extends IndexInput {
+ public static final int CACHE_SIZE = 16;
+ // Cache 16 blocks of 8K each, for a cache size of 128K
+ protected FileListBlock currentFileListBlock;
+ protected int currentFileListBlockNum;
+ protected int currentIndexBlockNum;
+ protected IndexBlock currentIndexBlock;
+ private RandomAccessFile raf;
+ protected File indexFile;
+ protected LRUCache blockCache;
+ protected boolean opened = false;
+ protected IndexSummary summary;
+
+ public BlocksIndexInput(File inputFile) {
+ this.indexFile = inputFile;
+ blockCache = new LRUCache(CACHE_SIZE);
+ }
+
+ /**
+ * @see IndexInput#clearCache
+ */
+ public void clearCache() {
+ blockCache = new LRUCache(CACHE_SIZE);
+ }
+
+ /**
+ * @see IndexInput#close
+ */
+
+ public void close() throws IOException {
+ if (opened) {
+ raf.close();
+ summary = null;
+ opened = false;
+ }
+ }
+
+ /**
+ * @see IndexInput#getCurrentFile
+ */
+
+ public IndexedFile getCurrentFile() throws IOException {
+ if (!hasMoreFiles())
+ return null;
+ IndexedFile file = null;
+ if ((file = currentFileListBlock.getFile(filePosition)) == null) {
+ currentFileListBlockNum = summary.getBlockNumForFileNum(filePosition);
+ currentFileListBlock = getFileListBlock(currentFileListBlockNum);
+ file = currentFileListBlock.getFile(filePosition);
+ }
+ return file;
+ }
+
+ /**
+ * Returns the entry corresponding to the given word.
+ */
+
+ protected WordEntry getEntry(char[] word) throws IOException {
+ int blockNum = summary.getBlockNumForWord(word);
+ if (blockNum == -1)
+ return null;
+ IndexBlock block = getIndexBlock(blockNum);
+ return block.findExactEntry(word);
+ }
+
+ /**
+ * Returns the FileListBlock with the given number.
+ */
+
+ protected FileListBlock getFileListBlock(int blockNum) throws IOException {
+ Integer key = new Integer(blockNum);
+ Block block = (Block) blockCache.get(key);
+ if (block != null && block instanceof FileListBlock)
+ return (FileListBlock) block;
+ FileListBlock fileListBlock = new FileListBlock(IIndexConstants.BLOCK_SIZE);
+ fileListBlock.read(raf, blockNum);
+ blockCache.put(key, fileListBlock);
+ return fileListBlock;
+ }
+
+ /**
+ * Returns the IndexBlock (containing words) with the given number.
+ */
+
+ protected IndexBlock getIndexBlock(int blockNum) throws IOException {
+ Integer key = new Integer(blockNum);
+ Block block = (Block) blockCache.get(key);
+ if (block != null && block instanceof IndexBlock)
+ return (IndexBlock) block;
+ IndexBlock indexBlock =
+ new GammaCompressedIndexBlock(IIndexConstants.BLOCK_SIZE);
+ indexBlock.read(raf, blockNum);
+ blockCache.put(key, indexBlock);
+ return indexBlock;
+ }
+
+ /**
+ * @see IndexInput#getIndexedFile
+ */
+ public IndexedFile getIndexedFile(int fileNum) throws IOException {
+ int blockNum = summary.getBlockNumForFileNum(fileNum);
+ if (blockNum == -1)
+ return null;
+ FileListBlock block = getFileListBlock(blockNum);
+ return block.getFile(fileNum);
+ }
+
+ /**
+ * @see IndexInput#getIndexedFile
+ */
+ public IndexedFile getIndexedFile(IDocument document)
+ throws java.io.IOException {
+ setFirstFile();
+ String name = document.getName();
+ while (hasMoreFiles()) {
+ IndexedFile file = getCurrentFile();
+ String path = file.getPath();
+ if (path.equals(name))
+ return file;
+ moveToNextFile();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the list of numbers of files containing the given word.
+ */
+
+ protected int[] getMatchingFileNumbers(char[] word) throws IOException {
+ int blockNum = summary.getBlockNumForWord(word);
+ if (blockNum == -1)
+ return new int[0];
+ IndexBlock block = getIndexBlock(blockNum);
+ WordEntry entry = block.findExactEntry(word);
+ return entry == null ? new int[0] : entry.getRefs();
+ }
+
+ /**
+ * @see IndexInput#getNumFiles
+ */
+ public int getNumFiles() {
+ return summary.getNumFiles();
+ }
+
+ /**
+ * @see IndexInput#getNumWords
+ */
+ public int getNumWords() {
+ return summary.getNumWords();
+ }
+
+ /**
+ * @see IndexInput#getSource
+ */
+ public Object getSource() {
+ return indexFile;
+ }
+
+ /**
+ * Initialises the blocksIndexInput
+ */
+ protected void init() throws IOException {
+ clearCache();
+ setFirstFile();
+ setFirstWord();
+ }
+
+ /**
+ * @see IndexInput#moveToNextFile
+ */
+ public void moveToNextFile() throws IOException {
+ filePosition++;
+ }
+
+ /**
+ * @see IndexInput#moveToNextEntry
+ */
+ public void moveToNextWordEntry() throws IOException {
+ wordPosition++;
+ if (!hasMoreWords()) {
+ return;
+ }
+ //if end of the current block, we load the next one.
+ boolean endOfBlock = !currentIndexBlock.nextEntry(currentWordEntry);
+ if (endOfBlock) {
+ currentIndexBlock = getIndexBlock(++currentIndexBlockNum);
+ currentIndexBlock.nextEntry(currentWordEntry);
+ }
+ }
+
+ /**
+ * @see IndexInput#open
+ */
+
+ public void open() throws IOException {
+ if (!opened) {
+ raf = new SafeRandomAccessFile(indexFile, "r");
+ String sig = raf.readUTF();
+ if (!sig.equals(IIndexConstants.SIGNATURE))
+ throw new IOException("Wrong format");
+ int summaryBlockNum = raf.readInt();
+ raf.seek(summaryBlockNum * (long) IIndexConstants.BLOCK_SIZE);
+ summary = new IndexSummary();
+ summary.read(raf);
+ init();
+ opened = true;
+ }
+ }
+
+ /**
+ * @see IndexInput#query
+ */
+ public IQueryResult[] query(String word) throws IOException {
+ open();
+ int[] fileNums = getMatchingFileNumbers(word.toCharArray());
+ int size = fileNums.length;
+ IQueryResult[] files = new IQueryResult[size];
+ for (int i = 0; i < size; ++i) {
+ files[i] = getIndexedFile(fileNums[i]);
+ }
+ return files;
+ }
+
+ /**
+ * If no prefix is provided in the pattern, then this operation will have to walk
+ * all the entries of the whole index.
+ */
+ public IEntryResult[] queryEntriesMatching(char[] pattern /*, boolean isCaseSensitive*/)
+ throws IOException {
+ open();
+
+ if (pattern == null || pattern.length == 0)
+ return null;
+ int[] blockNums = null;
+ int firstStar = CharOperation.indexOf('*', pattern);
+ switch (firstStar) {
+ case -1 :
+ WordEntry entry = getEntry(pattern);
+ if (entry == null)
+ return null;
+ return new IEntryResult[] { new EntryResult(entry.getWord(), entry.getRefs())};
+ case 0 :
+ blockNums = summary.getAllBlockNums();
+ break;
+ default :
+ char[] prefix = CharOperation.subarray(pattern, 0, firstStar);
+ blockNums = summary.getBlockNumsForPrefix(prefix);
+ }
+ if (blockNums == null || blockNums.length == 0)
+ return null;
+
+ IEntryResult[] entries = new IEntryResult[5];
+ int count = 0;
+ for (int i = 0, max = blockNums.length; i < max; i++) {
+ IndexBlock block = getIndexBlock(blockNums[i]);
+ block.reset();
+ boolean found = false;
+ WordEntry entry = new WordEntry();
+ while (block.nextEntry(entry)) {
+ if (CharOperation.match(entry.getWord(), pattern, true)) {
+ if (count == entries.length) {
+ System.arraycopy(entries, 0, entries = new IEntryResult[count * 2], 0, count);
+ }
+ entries[count++] = new EntryResult(entry.getWord(), entry.getRefs());
+ found = true;
+ } else {
+ if (found)
+ break;
+ }
+ }
+ }
+ if (count != entries.length) {
+ System.arraycopy(entries, 0, entries = new IEntryResult[count], 0, count);
+ }
+ return entries;
+ }
+
+ public IEntryResult[] queryEntriesPrefixedBy(char[] prefix /*, boolean isCaseSensitive*/)
+ throws IOException {
+ open();
+
+ int blockLoc = summary.getFirstBlockLocationForPrefix(prefix);
+ if (blockLoc < 0)
+ return null;
+
+ IEntryResult[] entries = new IEntryResult[5];
+ int count = 0;
+ while (blockLoc >= 0) {
+ IndexBlock block = getIndexBlock(summary.getBlockNum(blockLoc));
+ block.reset();
+ boolean found = false;
+ WordEntry entry = new WordEntry();
+ while (block.nextEntry(entry)) {
+ if (CharOperation.prefixEquals(prefix, entry.getWord() /*, isCaseSensitive*/
+ )) {
+ if (count == entries.length) {
+ System.arraycopy(entries, 0, entries = new IEntryResult[count * 2], 0, count);
+ }
+ entries[count++] = new EntryResult(entry.getWord(), entry.getRefs());
+ found = true;
+ } else {
+ if (found)
+ break;
+ }
+ }
+ /* consider next block ? */
+ blockLoc = summary.getNextBlockLocationForPrefix(prefix, blockLoc);
+ }
+ if (count == 0)
+ return null;
+ if (count != entries.length) {
+ System.arraycopy(entries, 0, entries = new IEntryResult[count], 0, count);
+ }
+ return entries;
+ }
+
+ public IQueryResult[] queryFilesReferringToPrefix(char[] prefix)
+ throws IOException {
+ open();
+
+ int blockLoc = summary.getFirstBlockLocationForPrefix(prefix);
+ if (blockLoc < 0)
+ return null;
+
+ IEntryResult[] entries = new IEntryResult[5];
+
+ // each filename must be returned already once
+ org.eclipse.jdt.internal.compiler.util.HashtableOfInt fileMatches =
+ new org.eclipse.jdt.internal.compiler.util.HashtableOfInt(20);
+ int count = 0;
+ while (blockLoc >= 0) {
+ IndexBlock block = getIndexBlock(summary.getBlockNum(blockLoc));
+ block.reset();
+ boolean found = false;
+ WordEntry entry = new WordEntry();
+ while (block.nextEntry(entry)) {
+ if (CharOperation.prefixEquals(prefix, entry.getWord() /*, isCaseSensitive*/
+ )) {
+ int[] refs = entry.getRefs();
+ for (int i = 0, max = refs.length; i < max; i++) {
+ int ref = refs[i];
+ if (!fileMatches.containsKey(ref)) {
+ count++;
+ fileMatches.put(ref, getIndexedFile(ref));
+ }
+ }
+ found = true;
+ } else {
+ if (found)
+ break;
+ }
+ }
+ /* consider next block ? */
+ blockLoc = summary.getNextBlockLocationForPrefix(prefix, blockLoc);
+ }
+ /* extract indexed files */
+ IQueryResult[] files = new IQueryResult[count];
+ Object[] indexedFiles = fileMatches.valueTable;
+ for (int i = 0, index = 0, max = indexedFiles.length; i < max; i++) {
+ IndexedFile indexedFile = (IndexedFile) indexedFiles[i];
+ if (indexedFile != null) {
+ files[index++] = indexedFile;
+ }
+ }
+ return files;
+ }
+
+ /**
+ * @see IndexInput#query
+ */
+ public IQueryResult[] queryInDocumentNames(String word) throws IOException {
+ open();
+ Vector matches = new Vector();
+ setFirstFile();
+ while (hasMoreFiles()) {
+ IndexedFile file = getCurrentFile();
+ if (file.getPath().indexOf(word) != -1)
+ matches.addElement(file);
+ moveToNextFile();
+ }
+ IQueryResult[] match = new IQueryResult[matches.size()];
+ matches.copyInto(match);
+ return match;
+ }
+
+ /**
+ * @see IndexInput#setFirstFile
+ */
+
+ protected void setFirstFile() throws IOException {
+ filePosition = 1;
+ if (getNumFiles() > 0) {
+ currentFileListBlockNum = summary.getBlockNumForFileNum(1);
+ currentFileListBlock = getFileListBlock(currentFileListBlockNum);
+ }
+ }
+
+ /**
+ * @see IndexInput#setFirstWord
+ */
+
+ protected void setFirstWord() throws IOException {
+ wordPosition = 1;
+ if (getNumWords() > 0) {
+ currentIndexBlockNum = summary.getFirstWordBlockNum();
+ currentIndexBlock = getIndexBlock(currentIndexBlockNum);
+ currentWordEntry = new WordEntry();
+ currentIndexBlock.reset();
+ currentIndexBlock.nextEntry(currentWordEntry);
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/BlocksIndexOutput.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/BlocksIndexOutput.java
new file mode 100644
index 0000000000..e18e594a15
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/BlocksIndexOutput.java
@@ -0,0 +1,168 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+
+/**
+ * A blocksIndexOutput is used to save an index in a file with the given structure:<br>
+ * - Signature of the file;<br>
+ * - FileListBlocks;<br>
+ * - IndexBlocks;<br>
+ * - Summary of the index.
+ */
+
+public class BlocksIndexOutput extends IndexOutput {
+ protected RandomAccessFile indexOut;
+ protected int blockNum;
+ protected boolean opened = false;
+ protected File indexFile;
+ protected FileListBlock fileListBlock;
+ protected IndexBlock indexBlock;
+ protected int numWords = 0;
+ protected IndexSummary summary;
+ protected int numFiles = 0;
+ protected boolean firstInBlock;
+ protected boolean firstIndexBlock;
+ protected boolean firstFileListBlock;
+
+ public BlocksIndexOutput(File indexFile) {
+ this.indexFile = indexFile;
+ summary = new IndexSummary();
+ blockNum = 1;
+ firstInBlock = true;
+ firstIndexBlock = true;
+ firstFileListBlock = true;
+ }
+
+ /**
+ * @see IndexOutput#addFile
+ */
+ public void addFile(IndexedFile indexedFile) throws IOException {
+ if (firstFileListBlock) {
+ firstInBlock = true;
+ fileListBlock = new FileListBlock(IIndexConstants.BLOCK_SIZE);
+ firstFileListBlock = false;
+ }
+ if (fileListBlock.addFile(indexedFile)) {
+ if (firstInBlock) {
+ summary.addFirstFileInBlock(indexedFile, blockNum);
+ firstInBlock = false;
+ }
+ numFiles++;
+ } else {
+ if (fileListBlock.isEmpty()) {
+ return;
+ }
+ flushFiles();
+ addFile(indexedFile);
+ }
+ }
+
+ /**
+ * @see IndexOutput#addWord
+ */
+ public void addWord(WordEntry entry) throws IOException {
+ if (firstIndexBlock) {
+ indexBlock = new GammaCompressedIndexBlock(IIndexConstants.BLOCK_SIZE);
+ firstInBlock = true;
+ firstIndexBlock = false;
+ }
+ if (entry.getNumRefs() == 0)
+ return;
+ if (indexBlock.addEntry(entry)) {
+ if (firstInBlock) {
+ summary.addFirstWordInBlock(entry.getWord(), blockNum);
+ firstInBlock = false;
+ }
+ numWords++;
+ } else {
+ if (indexBlock.isEmpty()) {
+ return;
+ }
+ flushWords();
+ addWord(entry);
+ }
+ }
+
+ /**
+ * @see IndexOutput#close
+ */
+ public void close() throws IOException {
+ if (opened) {
+ indexOut.close();
+ summary = null;
+ numFiles = 0;
+ opened = false;
+ }
+ }
+
+ /**
+ * @see IndexOutput#flush
+ */
+ public void flush() throws IOException {
+
+ summary.setNumFiles(numFiles);
+ summary.setNumWords(numWords);
+ indexOut.seek(blockNum * (long) IIndexConstants.BLOCK_SIZE);
+ summary.write(indexOut);
+ indexOut.seek(0);
+ indexOut.writeUTF(IIndexConstants.SIGNATURE);
+ indexOut.writeInt(blockNum);
+ }
+
+ /**
+ * Writes the current fileListBlock on the disk and initialises it
+ * (when it's full or it's the end of the index).
+ */
+ protected void flushFiles() throws IOException {
+ if (!firstFileListBlock && fileListBlock != null) {
+ fileListBlock.flush();
+ fileListBlock.write(indexOut, blockNum++);
+ fileListBlock.clear();
+ firstInBlock = true;
+ }
+ }
+
+ /**
+ * Writes the current indexBlock on the disk and initialises it
+ * (when it's full or it's the end of the index).
+ */
+ protected void flushWords() throws IOException {
+ if (!firstInBlock
+ && indexBlock != null) {
+ // could have added a document without any indexed word, no block created yet
+ indexBlock.flush();
+ indexBlock.write(indexOut, blockNum++);
+ indexBlock.clear();
+ firstInBlock = true;
+ }
+ }
+
+ /**
+ * @see IndexOutput#getDestination
+ */
+ public Object getDestination() {
+ return indexFile;
+ }
+
+ /**
+ * @see IndexOutput#open
+ */
+ public void open() throws IOException {
+ if (!opened) {
+ summary = new IndexSummary();
+ numFiles = 0;
+ numWords = 0;
+ blockNum = 1;
+ firstInBlock = true;
+ firstIndexBlock = true;
+ firstFileListBlock = true;
+ indexOut = new SafeRandomAccessFile(this.indexFile, "rw");
+ opened = true;
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/CodeByteStream.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/CodeByteStream.java
new file mode 100644
index 0000000000..9eb46bca13
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/CodeByteStream.java
@@ -0,0 +1,397 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+
+public class CodeByteStream {
+ protected byte[] bytes;
+ protected int byteOffset = 0;
+ protected int bitOffset = 0;
+ protected int markByteOffset = -1;
+ protected int markBitOffset = -1;
+
+ public CodeByteStream() {
+ this(16);
+ }
+
+ public CodeByteStream(byte[] bytes) {
+ this.bytes = bytes;
+ }
+
+ public CodeByteStream(int initialByteLength) {
+ bytes = new byte[initialByteLength];
+ }
+
+ public int byteLength() {
+ return (bitOffset + 7) / 8 + byteOffset;
+ }
+
+ public byte[] getBytes(int startOffset, int endOffset) {
+ int byteLength = byteLength();
+ if (startOffset > byteLength
+ || endOffset > byteLength
+ || startOffset > endOffset)
+ throw new IndexOutOfBoundsException();
+ int length = endOffset - startOffset;
+ byte[] result = new byte[length];
+ System.arraycopy(bytes, startOffset, result, 0, length);
+ if (endOffset == byteLength && bitOffset != 0) {
+ int mask = (1 << bitOffset) - 1;
+ result[length - 1] &= (mask << 8 - bitOffset);
+ }
+ return result;
+ }
+
+ protected void grow() {
+ byte[] newBytes = new byte[bytes.length * 2 + 1];
+ System.arraycopy(bytes, 0, newBytes, 0, bytes.length);
+ bytes = newBytes;
+ }
+
+ public void mark() {
+ markByteOffset = byteOffset;
+ markBitOffset = bitOffset;
+ }
+
+ /**
+ * Reads a single bit (value == 0 or == 1).
+ */
+ public int readBit() {
+ int value = (bytes[byteOffset] >> (7 - bitOffset)) & 1;
+ if (++bitOffset >= 8) {
+ bitOffset = 0;
+ ++byteOffset;
+ }
+ return value;
+ }
+
+ /**
+ * Read up to 32 bits from the stream.
+ */
+ public int readBits(int numBits) {
+ int value = 0;
+ while (numBits > 0) {
+ int bitsToRead = 8 - bitOffset;
+ if (bitsToRead > numBits)
+ bitsToRead = numBits;
+ int mask = (1 << bitsToRead) - 1;
+ value |= ((bytes[byteOffset] >> (8 - bitOffset - bitsToRead)) & mask)
+ << (numBits - bitsToRead);
+ numBits -= bitsToRead;
+ bitOffset += bitsToRead;
+ if (bitOffset >= 8) {
+ bitOffset -= 8;
+ byteOffset += 1;
+ }
+ }
+ return value;
+ }
+
+ public final int readByte() {
+
+ // no need to rebuild byte value from bit sequences
+ if (bitOffset == 0)
+ return bytes[byteOffset++] & 255;
+
+ int value = 0;
+ int numBits = 8;
+ while (numBits > 0) {
+ int bitsToRead = 8 - bitOffset;
+ if (bitsToRead > numBits)
+ bitsToRead = numBits;
+ int mask = (1 << bitsToRead) - 1;
+ value |= ((bytes[byteOffset] >> (8 - bitOffset - bitsToRead)) & mask)
+ << (numBits - bitsToRead);
+ numBits -= bitsToRead;
+ bitOffset += bitsToRead;
+ if (bitOffset >= 8) {
+ bitOffset -= 8;
+ byteOffset += 1;
+ }
+ }
+ return value;
+ }
+
+ /**
+ * Reads a value using Gamma coding.
+ */
+ public int readGamma() {
+ int numBits = readUnary();
+ return readBits(numBits - 1) | (1 << (numBits - 1));
+ }
+
+ public char[] readSmallUTF() throws UTFDataFormatException {
+ int utflen = readByte();
+ char str[] = new char[utflen];
+ int count = 0;
+ int strlen = 0;
+ while (count < utflen) {
+ int c = readByte();
+ int char2, char3;
+ switch (c >> 4) {
+ case 0 :
+ case 1 :
+ case 2 :
+ case 3 :
+ case 4 :
+ case 5 :
+ case 6 :
+ case 7 :
+ // 0xxxxxxx
+ count++;
+ str[strlen++] = (char) c;
+ break;
+ case 12 :
+ case 13 :
+ // 110x xxxx 10xx xxxx
+ count += 2;
+ if (count > utflen)
+ throw new UTFDataFormatException();
+ char2 = readByte();
+ if ((char2 & 0xC0) != 0x80)
+ throw new UTFDataFormatException();
+ str[strlen++] = (char) (((c & 0x1F) << 6) | (char2 & 0x3F));
+ break;
+ case 14 :
+ // 1110 xxxx 10xx xxxx 10xx xxxx
+ count += 3;
+ if (count > utflen)
+ throw new UTFDataFormatException();
+ char2 = readByte();
+ char3 = readByte();
+ if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
+ throw new UTFDataFormatException();
+ str[strlen++] =
+ (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
+ break;
+ default :
+ // 10xx xxxx, 1111 xxxx
+ throw new UTFDataFormatException();
+ }
+ }
+ if (strlen < utflen)
+ System.arraycopy(str, 0, str = new char[strlen], 0, strlen);
+ return str;
+ }
+
+ /**
+ * Reads a value in unary.
+ */
+ public int readUnary() {
+ int value = 1;
+ int mask = 1 << (7 - bitOffset);
+ while ((bytes[byteOffset] & mask) != 0) {
+ ++value;
+ if (++bitOffset >= 8) {
+ bitOffset = 0;
+ ++byteOffset;
+ mask = 0x80;
+ } else {
+ mask >>>= 1;
+ }
+ }
+ // skip the 0 bit
+ if (++bitOffset >= 8) {
+ bitOffset = 0;
+ ++byteOffset;
+ }
+ return value;
+ }
+
+ public void reset() {
+ byteOffset = bitOffset = 0;
+ markByteOffset = markBitOffset = -1;
+ }
+
+ public void reset(byte[] bytes) {
+ this.bytes = bytes;
+ reset();
+ }
+
+ public void reset(byte[] bytes, int byteOffset) {
+ reset(bytes);
+ this.byteOffset = byteOffset;
+ }
+
+ public boolean resetToMark() {
+ if (markByteOffset == -1)
+ return false;
+ byteOffset = markByteOffset;
+ bitOffset = markBitOffset;
+ markByteOffset = markBitOffset = -1;
+ return true;
+ }
+
+ public void skipBits(int numBits) {
+ int newOffset = byteOffset * 8 + bitOffset + numBits;
+ if (newOffset < 0 || (newOffset + 7) / 8 >= bytes.length)
+ throw new IllegalArgumentException();
+ byteOffset = newOffset / 8;
+ bitOffset = newOffset % 8;
+ }
+
+ public byte[] toByteArray() {
+ return getBytes(0, byteLength());
+ }
+
+ /**
+ * Writes a single bit (value == 0 or == 1).
+ */
+ public void writeBit(int value) {
+ bytes[byteOffset] |= (value & 1) << (7 - bitOffset);
+ if (++bitOffset >= 8) {
+ bitOffset = 0;
+ if (++byteOffset >= bytes.length)
+ grow();
+ }
+ }
+
+ /**
+ * Write up to 32 bits to the stream.
+ * The least significant numBits bits of value are written.
+ */
+ public void writeBits(int value, int numBits) {
+ while (numBits > 0) {
+ int bitsToWrite = 8 - bitOffset;
+ if (bitsToWrite > numBits)
+ bitsToWrite = numBits;
+ int shift = 8 - bitOffset - bitsToWrite;
+ int mask = ((1 << bitsToWrite) - 1) << shift;
+ bytes[byteOffset] =
+ (byte) ((bytes[byteOffset] & ~mask)
+ | (((value >>> (numBits - bitsToWrite)) << shift) & mask));
+ numBits -= bitsToWrite;
+ bitOffset += bitsToWrite;
+ if (bitOffset >= 8) {
+ bitOffset -= 8;
+ if (++byteOffset >= bytes.length)
+ grow();
+ }
+ }
+ }
+
+ public void writeByte(int value) {
+ writeBits(value, 8);
+ }
+
+ /**
+ * Writes the given value using Gamma coding, in which positive integer x
+ * is represented by coding floor(log2(x) in unary followed by the value
+ * of x - 2**floor(log2(x)) in binary.
+ * The value must be >= 1.
+ */
+ public void writeGamma(int value) {
+ if (value < 1)
+ throw new IllegalArgumentException();
+ int temp = value;
+ int numBits = 0;
+ while (temp != 0) {
+ temp >>>= 1;
+ ++numBits;
+ }
+ writeUnary(numBits);
+ writeBits(value, numBits - 1);
+ }
+
+ public void writeSmallUTF(char[] str) {
+ writeSmallUTF(str, 0, str.length);
+ }
+
+ public void writeSmallUTF(char[] str, int start, int end) {
+ int utflen = 0;
+ for (int i = start; i < end; i++) {
+ int c = str[i];
+ if ((c >= 0x0001) && (c <= 0x007F)) {
+ utflen++;
+ } else
+ if (c > 0x07FF) {
+ utflen += 3;
+ } else {
+ utflen += 2;
+ }
+ }
+ if (utflen > 255)
+ throw new IllegalArgumentException();
+ writeByte(utflen & 0xFF);
+ for (int i = start; i < end; i++) {
+ int c = str[i];
+ if ((c >= 0x0001) && (c <= 0x007F)) {
+ writeByte(c);
+ } else
+ if (c > 0x07FF) {
+ writeByte(0xE0 | ((c >> 12) & 0x0F));
+ writeByte(0x80 | ((c >> 6) & 0x3F));
+ writeByte(0x80 | ((c >> 0) & 0x3F));
+ } else {
+ writeByte(0xC0 | ((c >> 6) & 0x1F));
+ writeByte(0x80 | ((c >> 0) & 0x3F));
+ }
+ }
+ }
+
+ /**
+ * Write the given value in unary. The value must be >= 1.
+ */
+ public void writeUnary(int value) {
+ if (value < 1)
+ throw new IllegalArgumentException();
+ int mask = 1 << (7 - bitOffset);
+ // write N-1 1-bits
+ while (--value > 0) {
+ bytes[byteOffset] |= mask;
+ if (++bitOffset >= 8) {
+ bitOffset = 0;
+ if (++byteOffset >= bytes.length)
+ grow();
+ mask = 0x80;
+ } else {
+ mask >>>= 1;
+ }
+ }
+ // write a 0-bit
+ bytes[byteOffset] &= ~mask;
+ if (++bitOffset >= 8) {
+ bitOffset = 0;
+ if (++byteOffset >= bytes.length)
+ grow();
+ }
+ }
+
+ public void writeUTF(char[] str) {
+ int strlen = str.length;
+ int utflen = 0;
+ for (int i = 0; i < strlen; i++) {
+ int c = str[i];
+ if ((c >= 0x0001) && (c <= 0x007F)) {
+ utflen++;
+ } else
+ if (c > 0x07FF) {
+ utflen += 3;
+ } else {
+ utflen += 2;
+ }
+ }
+ if (utflen > 65535)
+ throw new IllegalArgumentException();
+ writeByte((utflen >>> 8) & 0xFF);
+ writeByte((utflen >>> 0) & 0xFF);
+ for (int i = 0; i < strlen; i++) {
+ int c = str[i];
+ if ((c >= 0x0001) && (c <= 0x007F)) {
+ writeByte(c);
+ } else
+ if (c > 0x07FF) {
+ writeByte(0xE0 | ((c >> 12) & 0x0F));
+ writeByte(0x80 | ((c >> 6) & 0x3F));
+ writeByte(0x80 | ((c >> 0) & 0x3F));
+ } else {
+ writeByte(0xC0 | ((c >> 6) & 0x1F));
+ writeByte(0x80 | ((c >> 0) & 0x3F));
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/EntryResult.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/EntryResult.java
new file mode 100644
index 0000000000..7112194bcb
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/EntryResult.java
@@ -0,0 +1,71 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public class EntryResult implements IEntryResult {
+ private char[] word;
+ private int[] fileRefs;
+
+ public EntryResult(char[] word, int[] refs) {
+ this.word = word;
+ this.fileRefs = refs;
+ }
+
+ public boolean equals(Object anObject) {
+
+ if (this == anObject) {
+ return true;
+ }
+ if ((anObject != null) && (anObject instanceof EntryResult)) {
+ EntryResult anEntryResult = (EntryResult) anObject;
+ if (!CharOperation.equals(this.word, anEntryResult.word))
+ return false;
+
+ int length;
+ int[] refs, otherRefs;
+ if ((length = (refs = this.fileRefs).length)
+ != (otherRefs = anEntryResult.fileRefs).length)
+ return false;
+ for (int i = 0; i < length; i++) {
+ if (refs[i] != otherRefs[i])
+ return false;
+ }
+ return true;
+ }
+ return false;
+
+ }
+
+ public int[] getFileReferences() {
+ return fileRefs;
+ }
+
+ public char[] getWord() {
+ return word;
+ }
+
+ public int hashCode() {
+ return CharOperation.hashCode(word);
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer(word.length * 2);
+ buffer.append("EntryResult: word=");
+ buffer.append(word);
+ buffer.append(", refs={");
+ for (int i = 0; i < fileRefs.length; i++) {
+ if (i > 0)
+ buffer.append(',');
+ buffer.append(' ');
+ buffer.append(fileRefs[i]);
+ }
+ buffer.append(" }");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Field.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Field.java
new file mode 100644
index 0000000000..db4c1606d1
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Field.java
@@ -0,0 +1,445 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+
+public class Field {
+ protected byte[] buffer; // contents
+ protected int offset; // offset of the field within the byte array
+ protected int length; // length of the field
+
+ /**
+ * ByteSegment constructor comment.
+ */
+ public Field(byte[] bytes) {
+ this.buffer = bytes;
+ this.offset = 0;
+ this.length = bytes.length;
+ }
+
+ /**
+ * ByteSegment constructor comment.
+ */
+ public Field(byte[] bytes, int length) {
+ this.buffer = bytes;
+ this.offset = 0;
+ this.length = length;
+ }
+
+ /**
+ * ByteSegment constructor comment.
+ */
+ public Field(byte[] bytes, int offset, int length) {
+ this.buffer = bytes;
+ this.offset = offset;
+ this.length = length;
+ }
+
+ /**
+ * Creates a new field containing an empty buffer of the given length.
+ */
+ public Field(int length) {
+ this.buffer = new byte[length];
+ this.offset = 0;
+ this.length = length;
+ }
+
+ public byte[] buffer() {
+ return buffer;
+ }
+
+ public Field buffer(byte[] buffer) {
+ this.buffer = buffer;
+ return this;
+ }
+
+ public Field clear() {
+ clear(buffer, offset, length);
+ return this;
+ }
+
+ protected static void clear(byte[] buffer, int offset, int length) {
+ int n = offset;
+ for (int i = 0; i < length; i++) {
+ buffer[n] = 0;
+ n++;
+ }
+ }
+
+ public Field clear(int length) {
+ clear(buffer, offset, length);
+ return this;
+ }
+
+ public Field clear(int offset, int length) {
+ clear(buffer, this.offset + offset, length);
+ return this;
+ }
+
+ protected static int compare(
+ byte[] buffer1,
+ int offset1,
+ int length1,
+ byte[] buffer2,
+ int offset2,
+ int length2) {
+ int n = Math.min(length1, length2);
+ for (int i = 0; i < n; i++) {
+ int j1 = buffer1[offset1 + i] & 255;
+ int j2 = buffer2[offset2 + i] & 255;
+ if (j1 > j2)
+ return 1;
+ if (j1 < j2)
+ return -1;
+ }
+ if (length1 > n) {
+ for (int i = n; i < length1; i++)
+ if (buffer1[offset1 + i] != 0)
+ return 1;
+ return 0;
+ }
+ for (int i = n; i < length2; i++)
+ if (buffer2[offset2 + i] != 0)
+ return -1;
+ return 0;
+ }
+
+ public static int compare(Field f1, Field f2) {
+ return compare(
+ f1.buffer,
+ f1.offset,
+ f1.length,
+ f2.buffer,
+ f2.offset,
+ f2.length);
+ }
+
+ // copy bytes from one offset to another within the field
+ public Field copy(int fromOffset, int toOffset, int length) {
+ System.arraycopy(
+ buffer,
+ offset + fromOffset,
+ buffer,
+ offset + toOffset,
+ length);
+ return this;
+ }
+
+ public Field dec(int n) {
+ offset -= n;
+ return this;
+ }
+
+ public byte[] get() {
+ byte[] result = new byte[length];
+ System.arraycopy(buffer, offset, result, 0, length);
+ return result;
+ }
+
+ public byte[] get(int offset, int length) {
+ byte[] result = new byte[length];
+ System.arraycopy(buffer, this.offset + offset, result, 0, length);
+ return result;
+ }
+
+ public Field getField(int offset, int length) {
+ return new Field(buffer, this.offset + offset, length);
+ }
+
+ public int getInt1() {
+ return buffer[this.offset];
+ }
+
+ public int getInt1(int offset) {
+ return buffer[this.offset + offset];
+ }
+
+ public int getInt2() {
+ int i = this.offset;
+ int v = buffer[i++];
+ v = (v << 8) | (buffer[i++] & 255);
+ return v;
+ }
+
+ public int getInt2(int offset) {
+ int i = this.offset + offset;
+ int v = buffer[i++];
+ v = (v << 8) | (buffer[i++] & 255);
+ return v;
+ }
+
+ public int getInt3() {
+ int i = this.offset;
+ int v = buffer[i++];
+ v = (v << 8) | (buffer[i++] & 255);
+ v = (v << 8) | (buffer[i++] & 255);
+ return v;
+ }
+
+ public int getInt3(int offset) {
+ int i = this.offset + offset;
+ int v = buffer[i++];
+ v = (v << 8) | (buffer[i++] & 255);
+ v = (v << 8) | (buffer[i++] & 255);
+ return v;
+ }
+
+ public int getInt4() {
+ int i = this.offset;
+ int v = buffer[i++];
+ v = (v << 8) | (buffer[i++] & 255);
+ v = (v << 8) | (buffer[i++] & 255);
+ v = (v << 8) | (buffer[i++] & 255);
+ return v;
+ }
+
+ public int getInt4(int offset) {
+ int i = this.offset + offset;
+ int v = buffer[i++];
+ v = (v << 8) | (buffer[i++] & 255);
+ v = (v << 8) | (buffer[i++] & 255);
+ v = (v << 8) | (buffer[i++] & 255);
+ return v;
+ }
+
+ public int getUInt1() {
+ return buffer[this.offset] & 255;
+ }
+
+ public int getUInt1(int offset) {
+ return buffer[this.offset + offset] & 255;
+ }
+
+ public int getUInt2() {
+ int i = this.offset;
+ int v = (buffer[i++] & 255);
+ v = (v << 8) | (buffer[i++] & 255);
+ return v;
+ }
+
+ public int getUInt2(int offset) {
+ int i = this.offset + offset;
+ int v = (buffer[i++] & 255);
+ v = (v << 8) | (buffer[i++] & 255);
+ return v;
+ }
+
+ public int getUInt3() {
+ int i = this.offset;
+ int v = (buffer[i++] & 255);
+ v = (v << 8) | (buffer[i++] & 255);
+ v = (v << 8) | (buffer[i++] & 255);
+ return v;
+ }
+
+ public int getUInt3(int offset) {
+ int i = this.offset + offset;
+ int v = (buffer[i++] & 255);
+ v = (v << 8) | (buffer[i++] & 255);
+ v = (v << 8) | (buffer[i++] & 255);
+ return v;
+ }
+
+ public char[] getUTF(int offset) throws UTFDataFormatException {
+ int pos = this.offset + offset;
+ int utflen = getUInt2(pos);
+ pos += 2;
+ char str[] = new char[utflen];
+ int count = 0;
+ int strlen = 0;
+ while (count < utflen) {
+ int c = buffer[pos++] & 0xFF;
+ int char2, char3;
+ switch (c >> 4) {
+ case 0 :
+ case 1 :
+ case 2 :
+ case 3 :
+ case 4 :
+ case 5 :
+ case 6 :
+ case 7 :
+ // 0xxxxxxx
+ count++;
+ str[strlen++] = (char) c;
+ break;
+ case 12 :
+ case 13 :
+ // 110x xxxx 10xx xxxx
+ count += 2;
+ if (count > utflen)
+ throw new UTFDataFormatException();
+ char2 = buffer[pos++] & 0xFF;
+ if ((char2 & 0xC0) != 0x80)
+ throw new UTFDataFormatException();
+ str[strlen++] = (char) (((c & 0x1F) << 6) | (char2 & 0x3F));
+ break;
+ case 14 :
+ // 1110 xxxx 10xx xxxx 10xx xxxx
+ count += 3;
+ if (count > utflen)
+ throw new UTFDataFormatException();
+ char2 = buffer[pos++] & 0xFF;
+ char3 = buffer[pos++] & 0xFF;
+ if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
+ throw new UTFDataFormatException();
+ str[strlen++] =
+ (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
+ break;
+ default :
+ // 10xx xxxx, 1111 xxxx
+ throw new UTFDataFormatException();
+ }
+ }
+ if (strlen < utflen)
+ System.arraycopy(str, 0, str = new char[strlen], 0, strlen);
+ return str;
+ }
+
+ public Field inc(int n) {
+ offset += n;
+ return this;
+ }
+
+ public int length() {
+ return length;
+ }
+
+ public Field length(int length) {
+ this.length = length;
+ return this;
+ }
+
+ /**
+ Returns the offset into the underlying byte array that this field is defined over.
+ */
+ public int offset() {
+ return offset;
+ }
+
+ public Field offset(int offset) {
+ this.offset = offset;
+ return this;
+ }
+
+ public Field pointTo(int offset) {
+ return new Field(buffer, this.offset + offset, 0);
+ }
+
+ public Field put(byte[] b) {
+ return put(0, b);
+ }
+
+ public Field put(int offset, byte[] b) {
+ System.arraycopy(b, 0, buffer, this.offset + offset, b.length);
+ return this;
+ }
+
+ public Field put(int offset, Field f) {
+ System.arraycopy(f.buffer, f.offset, buffer, this.offset + offset, f.length);
+ return this;
+ }
+
+ public Field put(Field f) {
+ System.arraycopy(f.buffer, f.offset, buffer, offset, f.length);
+ return this;
+ }
+
+ public Field putInt1(int n) {
+ buffer[offset] = (byte) (n);
+ return this;
+ }
+
+ public Field putInt1(int offset, int n) {
+ buffer[this.offset + offset] = (byte) (n);
+ return this;
+ }
+
+ public Field putInt2(int n) {
+ int i = offset;
+ buffer[i++] = (byte) (n >> 8);
+ buffer[i++] = (byte) (n >> 0);
+ return this;
+ }
+
+ public Field putInt2(int offset, int n) {
+ int i = this.offset + offset;
+ buffer[i++] = (byte) (n >> 8);
+ buffer[i++] = (byte) (n >> 0);
+ return this;
+ }
+
+ public Field putInt3(int n) {
+ int i = offset;
+ buffer[i++] = (byte) (n >> 16);
+ buffer[i++] = (byte) (n >> 8);
+ buffer[i++] = (byte) (n >> 0);
+ return this;
+ }
+
+ public Field putInt3(int offset, int n) {
+ int i = this.offset + offset;
+ buffer[i++] = (byte) (n >> 16);
+ buffer[i++] = (byte) (n >> 8);
+ buffer[i++] = (byte) (n >> 0);
+ return this;
+ }
+
+ public Field putInt4(int n) {
+ int i = offset;
+ buffer[i++] = (byte) (n >> 24);
+ buffer[i++] = (byte) (n >> 16);
+ buffer[i++] = (byte) (n >> 8);
+ buffer[i++] = (byte) (n >> 0);
+ return this;
+ }
+
+ public Field putInt4(int offset, int n) {
+ int i = this.offset + offset;
+ buffer[i++] = (byte) (n >> 24);
+ buffer[i++] = (byte) (n >> 16);
+ buffer[i++] = (byte) (n >> 8);
+ buffer[i++] = (byte) (n >> 0);
+ return this;
+ }
+
+ public int putUTF(int offset, char[] str) {
+ int strlen = str.length;
+ int utflen = 0;
+ for (int i = 0; i < strlen; i++) {
+ int c = str[i];
+ if ((c >= 0x0001) && (c <= 0x007F)) {
+ utflen++;
+ } else
+ if (c > 0x07FF) {
+ utflen += 3;
+ } else {
+ utflen += 2;
+ }
+ }
+ if (utflen > 65535)
+ throw new IllegalArgumentException();
+ int pos = this.offset + offset;
+ buffer[pos++] = (byte) ((utflen >>> 8) & 0xFF);
+ buffer[pos++] = (byte) ((utflen >>> 0) & 0xFF);
+ for (int i = 0; i < strlen; i++) {
+ int c = str[i];
+ if ((c >= 0x0001) && (c <= 0x007F)) {
+ buffer[pos++] = ((byte) c);
+ } else
+ if (c > 0x07FF) {
+ buffer[pos++] = ((byte) (0xE0 | ((c >> 12) & 0x0F)));
+ buffer[pos++] = ((byte) (0x80 | ((c >> 6) & 0x3F)));
+ buffer[pos++] = ((byte) (0x80 | ((c >> 0) & 0x3F)));
+ } else {
+ buffer[pos++] = ((byte) (0xC0 | ((c >> 6) & 0x1F)));
+ buffer[pos++] = ((byte) (0x80 | ((c >> 0) & 0x3F)));
+ }
+ }
+ return 2 + utflen;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/FileDocument.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/FileDocument.java
new file mode 100644
index 0000000000..14ba1a9e96
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/FileDocument.java
@@ -0,0 +1,62 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+import org.eclipse.jdt.internal.core.index.*;
+
+/**
+ * A <code>FileDocument</code> represents a java.io.File.
+ */
+
+public class FileDocument extends PropertyDocument {
+ File file;
+
+ public FileDocument(File file) {
+ super();
+ this.file = file;
+ }
+
+ /**
+ * @see IDocument#getByteContent
+ */
+ public byte[] getByteContent() throws IOException {
+ return Util.getFileByteContent(file);
+ }
+
+ /**
+ * @see IDocument#getCharContent
+ */
+ public char[] getCharContent() throws IOException {
+ return Util.getFileCharContent(file);
+ }
+
+ /**
+ * @see IDocument#getName
+ */
+ public String getName() {
+ return file.getAbsolutePath().replace(
+ File.separatorChar,
+ IIndexConstants.FILE_SEPARATOR);
+ }
+
+ /**
+ * @see IDocument#getStringContent
+ */
+ public String getStringContent() throws IOException {
+ return new String(getCharContent());
+ }
+
+ /**
+ * @see IDocument#getType
+ */
+ public String getType() {
+ int lastDot = file.getPath().lastIndexOf('.');
+ if (lastDot == -1)
+ return "";
+ return file.getPath().substring(lastDot + 1);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/FileListBlock.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/FileListBlock.java
new file mode 100644
index 0000000000..8a113082db
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/FileListBlock.java
@@ -0,0 +1,111 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+import java.util.*;
+
+public class FileListBlock extends Block {
+
+ protected int offset = 0;
+ protected String prevPath = null;
+ protected String[] paths = null;
+
+ public FileListBlock(int blockSize) {
+ super(blockSize);
+ }
+
+ /**
+ * add the name of the indexedfile to the buffr of the field.
+ * The name is not the entire name of the indexedfile, but the
+ * difference between its name and the name of the previous indexedfile ...
+ */
+ public boolean addFile(IndexedFile indexedFile) {
+ int offset = this.offset;
+ if (isEmpty()) {
+ field.putInt4(offset, indexedFile.getFileNumber());
+ offset += 4;
+ }
+ String path = indexedFile.getPath() + indexedFile.propertiesToString();
+ int prefixLen = prevPath == null ? 0 : Util.prefixLength(prevPath, path);
+ int sizeEstimate = 2 + 2 + (path.length() - prefixLen) * 3;
+ if (offset + sizeEstimate > blockSize - 2)
+ return false;
+ field.putInt2(offset, prefixLen);
+ offset += 2;
+ char[] chars = new char[path.length() - prefixLen];
+ path.getChars(prefixLen, path.length(), chars, 0);
+ offset += field.putUTF(offset, chars);
+ this.offset = offset;
+ prevPath = path;
+ return true;
+ }
+
+ public void clear() {
+ reset();
+ super.clear();
+ }
+
+ public void flush() {
+ if (offset > 0) {
+ field.putInt2(offset, 0);
+ field.putInt2(offset + 2, 0);
+ offset = 0;
+ }
+ }
+
+ public IndexedFile getFile(int fileNum) throws IOException {
+ IndexedFile resp = null;
+ try {
+ String[] paths = getPaths();
+ int i = fileNum - field.getInt4(0);
+ resp = new IndexedFile(paths[i], fileNum);
+ } catch (Exception e) {
+ //fileNum too big
+ }
+ return resp;
+ }
+
+ /**
+ * Creates a vector of paths reading the buffer of the field.
+ */
+ protected String[] getPaths() throws IOException {
+ if (paths == null) {
+ Vector v = new Vector();
+ int offset = 4;
+ char[] prevPath = null;
+ for (;;) {
+ int prefixLen = field.getUInt2(offset);
+ offset += 2;
+ int utfLen = field.getUInt2(offset);
+ char[] path = field.getUTF(offset);
+ offset += 2 + utfLen;
+ if (prefixLen != 0) {
+ char[] temp = new char[prefixLen + path.length];
+ System.arraycopy(prevPath, 0, temp, 0, prefixLen);
+ System.arraycopy(path, 0, temp, prefixLen, path.length);
+ path = temp;
+ }
+ if (path.length == 0)
+ break;
+ v.addElement(new String(path));
+ prevPath = path;
+ }
+ paths = new String[v.size()];
+ v.copyInto(paths);
+ }
+ return paths;
+ }
+
+ public boolean isEmpty() {
+ return offset == 0;
+ }
+
+ public void reset() {
+ offset = 0;
+ prevPath = null;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/GammaCompressedIndexBlock.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/GammaCompressedIndexBlock.java
new file mode 100644
index 0000000000..a9aeaf0c3c
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/GammaCompressedIndexBlock.java
@@ -0,0 +1,121 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+
+/**
+ * Uses prefix coding on words, and gamma coding of document numbers differences.
+ */
+public class GammaCompressedIndexBlock extends IndexBlock {
+ CodeByteStream writeCodeStream = new CodeByteStream();
+ CodeByteStream readCodeStream;
+ char[] prevWord = null;
+ int offset = 0;
+
+ public GammaCompressedIndexBlock(int blockSize) {
+ super(blockSize);
+ readCodeStream = new CodeByteStream(field.buffer());
+ }
+
+ /**
+ * @see IndexBlock#addEntry
+ */
+ public boolean addEntry(WordEntry entry) {
+ writeCodeStream.reset();
+ encodeEntry(entry, prevWord, writeCodeStream);
+ if (offset + writeCodeStream.byteLength() > this.blockSize - 2) {
+ return false;
+ }
+ byte[] bytes = writeCodeStream.toByteArray();
+ field.put(offset, bytes);
+ offset += bytes.length;
+ prevWord = entry.getWord();
+ return true;
+ }
+
+ protected void encodeEntry(
+ WordEntry entry,
+ char[] prevWord,
+ CodeByteStream codeStream) {
+ char[] word = entry.getWord();
+ int prefixLen = prevWord == null ? 0 : Util.prefixLength(prevWord, word);
+ codeStream.writeByte(prefixLen);
+ codeStream.writeSmallUTF(word, prefixLen, word.length);
+ int n = entry.getNumRefs();
+ codeStream.writeGamma(n);
+ int prevRef = 0;
+ for (int i = 0; i < n; ++i) {
+ int ref = entry.getRef(i);
+ if (ref <= prevRef)
+ throw new IllegalArgumentException();
+ codeStream.writeGamma(ref - prevRef);
+ prevRef = ref;
+ }
+ }
+
+ /**
+ * @see IndexBlock#flush
+ */
+ public void flush() {
+ if (offset > 0) {
+ field.putInt2(offset, 0);
+ offset = 0;
+ prevWord = null;
+ }
+ }
+
+ /**
+ * @see IndexBlock#isEmpty
+ */
+ public boolean isEmpty() {
+ return offset == 0;
+ }
+
+ /**
+ * @see IndexBlock#nextEntry
+ */
+ public boolean nextEntry(WordEntry entry) {
+ try {
+ readCodeStream.reset(field.buffer(), offset);
+ int prefixLength = readCodeStream.readByte();
+ char[] word = readCodeStream.readSmallUTF();
+ if (prevWord != null && prefixLength > 0) {
+ char[] temp = new char[prefixLength + word.length];
+ System.arraycopy(prevWord, 0, temp, 0, prefixLength);
+ System.arraycopy(word, 0, temp, prefixLength, word.length);
+ word = temp;
+ }
+ if (word.length == 0) {
+ return false;
+ }
+ entry.reset(word);
+ int n = readCodeStream.readGamma();
+ int prevRef = 0;
+ for (int i = 0; i < n; ++i) {
+ int ref = prevRef + readCodeStream.readGamma();
+ if (ref < prevRef)
+ throw new InternalError();
+ entry.addRef(ref);
+ prevRef = ref;
+ }
+ offset = readCodeStream.byteLength();
+ prevWord = word;
+ return true;
+ } catch (UTFDataFormatException e) {
+ return false;
+ }
+ }
+
+ /**
+ * @see IndexBlock#reset
+ */
+ public void reset() {
+ super.reset();
+ offset = 0;
+ prevWord = null;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/HashtableOfObject.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/HashtableOfObject.java
new file mode 100644
index 0000000000..7b4614d918
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/HashtableOfObject.java
@@ -0,0 +1,101 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public final class HashtableOfObject {
+ // to avoid using Enumerations, walk the individual tables skipping nulls
+ public char[] keyTable[];
+ public Object valueTable[];
+
+ public int elementSize; // number of elements in the table
+ int threshold;
+ public HashtableOfObject() {
+ this(13);
+ }
+
+ public HashtableOfObject(int size) {
+ this.elementSize = 0;
+ this.threshold = size; // size represents the expected number of elements
+ int extraRoom = (int) (size * 1.75f);
+ if (this.threshold == extraRoom)
+ extraRoom++;
+ this.keyTable = new char[extraRoom][];
+ this.valueTable = new Object[extraRoom];
+ }
+
+ public boolean containsKey(char[] key) {
+ int index = CharOperation.hashCode(key) % valueTable.length;
+ int keyLength = key.length;
+ char[] currentKey;
+ while ((currentKey = keyTable[index]) != null) {
+ if (currentKey.length == keyLength
+ && CharOperation.prefixEquals(currentKey, key))
+ return true;
+ index = (index + 1) % keyTable.length;
+ }
+ return false;
+ }
+
+ public Object get(char[] key) {
+ int index = CharOperation.hashCode(key) % valueTable.length;
+ int keyLength = key.length;
+ char[] currentKey;
+ while ((currentKey = keyTable[index]) != null) {
+ if (currentKey.length == keyLength
+ && CharOperation.prefixEquals(currentKey, key))
+ return valueTable[index];
+ index = (index + 1) % keyTable.length;
+ }
+ return null;
+ }
+
+ public Object put(char[] key, Object value) {
+ int index = CharOperation.hashCode(key) % valueTable.length;
+ int keyLength = key.length;
+ char[] currentKey;
+ while ((currentKey = keyTable[index]) != null) {
+ if (currentKey.length == keyLength
+ && CharOperation.prefixEquals(currentKey, key))
+ return valueTable[index] = value;
+ index = (index + 1) % keyTable.length;
+ }
+ keyTable[index] = key;
+ valueTable[index] = value;
+
+ // assumes the threshold is never equal to the size of the table
+ if (++elementSize > threshold)
+ rehash();
+ return value;
+ }
+
+ private void rehash() {
+ HashtableOfObject newHashtable = new HashtableOfObject(elementSize * 2);
+ // double the number of expected elements
+ char[] currentKey;
+ for (int i = keyTable.length; --i >= 0;)
+ if ((currentKey = keyTable[i]) != null)
+ newHashtable.put(currentKey, valueTable[i]);
+
+ this.keyTable = newHashtable.keyTable;
+ this.valueTable = newHashtable.valueTable;
+ this.threshold = newHashtable.threshold;
+ }
+
+ public int size() {
+ return elementSize;
+ }
+
+ public String toString() {
+ String s = "";
+ Object object;
+ for (int i = 0, length = valueTable.length; i < length; i++)
+ if ((object = valueTable[i]) != null)
+ s += new String(keyTable[i]) + " -> " + object.toString() + "\n";
+ return s;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/ICacheEnumeration.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/ICacheEnumeration.java
new file mode 100644
index 0000000000..191ed2e5ac
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/ICacheEnumeration.java
@@ -0,0 +1,33 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.Enumeration;
+
+/**
+ * The <code>ICacheEnumeration</code> is used to iterate over both the keys
+ * and values in an LRUCache. The <code>getValue()</code> method returns the
+ * value of the last key to be retrieved using <code>nextElement()</code>.
+ * The <code>nextElement()</code> method must be called before the
+ * <code>getValue()</code> method.
+ *
+ * <p>The iteration can be made efficient by making use of the fact that values in
+ * the cache (instances of <code>LRUCacheEntry</code>), know their key. For this reason,
+ * Hashtable lookups don't have to be made at each step of the iteration.
+ *
+ * <p>Modifications to the cache must not be performed while using the
+ * enumeration. Doing so will lead to an illegal state.
+ *
+ * @see LRUCache
+ */
+public interface ICacheEnumeration extends Enumeration {
+ /**
+ * Returns the value of the previously accessed key in the enumeration.
+ * Must be called after a call to nextElement().
+ *
+ * @return Value of current cache entry
+ */
+ public Object getValue();
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IFileDocument.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IFileDocument.java
new file mode 100644
index 0000000000..468561f91a
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IFileDocument.java
@@ -0,0 +1,85 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+import org.eclipse.core.resources.*;
+
+/**
+ * An <code>IFileDocument</code> represents an IFile.
+ */
+
+public class IFileDocument extends PropertyDocument {
+ protected IFile file;
+
+ // cached contents if needed - only one of them is used at a time
+ protected char[] charContents;
+ protected byte[] byteContents;
+ /**
+ * IFileDocument constructor comment.
+ */
+ public IFileDocument(IFile file) {
+ this(file, (char[]) null);
+ }
+
+ /**
+ * IFileDocument constructor comment.
+ */
+ public IFileDocument(IFile file, byte[] byteContents) {
+ this.file = file;
+ this.byteContents = byteContents;
+ }
+
+ /**
+ * IFileDocument constructor comment.
+ */
+ public IFileDocument(IFile file, char[] charContents) {
+ this.file = file;
+ this.charContents = charContents;
+ }
+
+ /**
+ * @see IDocument#getByteContent
+ */
+ public byte[] getByteContent() throws IOException {
+ if (byteContents != null)
+ return byteContents;
+ return byteContents = Util.getFileByteContent(file.getLocation().toFile());
+ }
+
+ /**
+ * @see IDocument#getCharContent
+ */
+ public char[] getCharContent() throws IOException {
+ if (charContents != null)
+ return charContents;
+ return charContents = Util.getFileCharContent(file.getLocation().toFile());
+ }
+
+ /**
+ * @see IDocument#getName
+ */
+ public String getName() {
+ return file.getFullPath().toString();
+ }
+
+ /**
+ * @see IDocument#getStringContent
+ */
+ public String getStringContent() throws java.io.IOException {
+ return new String(getCharContent());
+ }
+
+ /**
+ * @see IDocument#getType
+ */
+ public String getType() {
+ String extension = file.getFileExtension();
+ if (extension == null)
+ return "";
+ return extension;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IIndexConstants.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IIndexConstants.java
new file mode 100644
index 0000000000..2eaf770f04
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IIndexConstants.java
@@ -0,0 +1,16 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+public interface IIndexConstants {
+ /**
+ * The signature of the index file.
+ */
+ public static final String SIGNATURE = "INDEX FILE 0.001";
+ /**
+ * The signature of the index file.
+ */
+ public static final char FILE_SEPARATOR = '/';
+ /**
+ * The size of a block for a <code>Block</code>.
+ */
+ public static final int BLOCK_SIZE = 8192;
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/ILRUCacheable.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/ILRUCacheable.java
new file mode 100644
index 0000000000..81dff3e24c
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/ILRUCacheable.java
@@ -0,0 +1,11 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+public interface ILRUCacheable {
+ /**
+ * Returns the space the receiver consumes in an LRU Cache. The default space
+ * value is 1.
+ *
+ * @return int Amount of cache space taken by the receiver
+ */
+ public int getCacheFootprint();
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/InMemoryIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/InMemoryIndex.java
new file mode 100644
index 0000000000..805a265249
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/InMemoryIndex.java
@@ -0,0 +1,254 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+import java.util.*;
+import org.eclipse.jdt.internal.core.index.*;
+
+/**
+ * This index stores the document names in an <code>ObjectVector</code>, and the words in
+ * an <code>HashtableOfObjects</code>.
+ */
+
+public class InMemoryIndex {
+
+ /**
+ * hashtable of WordEntrys = words+numbers of the files they appear in.
+ */
+ protected HashtableOfObject words = new HashtableOfObject(1023);
+
+ /**
+ * Vector of IndexedFiles = file name + a unique number.
+ */
+ protected ObjectVector files = new ObjectVector();
+
+ /**
+ * Number of references in the index (not the number of actual words).
+ */
+ protected int wordCount = 0;
+
+ /**
+ * Size of the index.
+ */
+ protected long footprint = 0;
+
+ protected long indexFileSize;
+ private char[][] sortedWords;
+ private IndexedFile[] sortedFiles;
+ public InMemoryIndex() {
+ super();
+ }
+
+ /**
+ * @see IIndex#addFile
+ */
+ public IndexedFile addDocument(IDocument document) {
+ IndexedFile indexedFile = new IndexedFile(document, this.files.size + 1);
+ this.files.add(indexedFile);
+ this.footprint += indexedFile.footprint() + 4;
+ this.sortedFiles = null;
+ return indexedFile;
+ }
+
+ /**
+ * Adds the references of the word to the index (reference = number of the file the word belongs to).
+ */
+ protected void addRef(char[] word, int[] references) {
+ int size = references.length;
+ int i = 0;
+ while (i < size) {
+ if (references[i] != 0)
+ addRef(word, references[i]);
+ i++;
+ }
+ }
+
+ /**
+ * Looks if the word already exists in the index and add the fileNum to this word.
+ * If the word does not exist, it adds it in the index.
+ */
+ protected void addRef(char[] word, int fileNum) {
+ word = preprocessWord(word);
+ WordEntry entry = (WordEntry) this.words.get(word);
+ if (entry == null) {
+ entry = new WordEntry(word);
+ entry.addRef(fileNum);
+ this.words.put(word, entry);
+ this.sortedWords = null;
+ this.footprint += entry.footprint();
+ } else {
+ this.footprint += entry.addRef(fileNum);
+ }
+ ++this.wordCount;
+ }
+
+ /**
+ * @see IIndex#addRef
+ */
+ public void addRef(IndexedFile indexedFile, char[] word) {
+ addRef(word, indexedFile.getFileNumber());
+ }
+
+ /**
+ * @see IIndex#addRef
+ */
+ public void addRef(IndexedFile indexedFile, String word) {
+ addRef(word.toCharArray(), indexedFile.getFileNumber());
+ }
+
+ /**
+ * Returns the footprint of the index.
+ */
+
+ public long getFootprint() {
+ return this.footprint;
+ }
+
+ /**
+ * Returns the indexed file with the given path, or null if such file does not exist.
+ */
+ public IndexedFile getIndexedFile(String path) {
+ for (int i = files.size; i > 0; i--) {
+ IndexedFile file = (IndexedFile) files.elementAt(i - 1);
+ if (file.getPath().equals(path))
+ return file;
+ }
+ return null;
+ }
+
+ /**
+ * @see IIndex#getNumFiles
+ */
+ public int getNumFiles() {
+ return files.size;
+ }
+
+ /**
+ * @see IIndex#getNumWords
+ */
+ public int getNumWords() {
+ return words.elementSize;
+ }
+
+ /**
+ * Returns the words contained in the hashtable of words, sorted by alphabetical order.
+ */
+ protected IndexedFile[] getSortedFiles() {
+ if (this.sortedFiles == null) {
+ IndexedFile[] indexedfiles = new IndexedFile[files.size];
+ for (int i = 0; i < indexedfiles.length; i++)
+ indexedfiles[i] = (IndexedFile) files.elementAt(i);
+ Util.sort(indexedfiles);
+ this.sortedFiles = indexedfiles;
+ }
+ return this.sortedFiles;
+ }
+
+ /**
+ * Returns the words contained in the hashtable of words, sorted by alphabetical order.
+ */
+ protected char[][] getSortedWords() {
+ if (this.sortedWords == null) {
+ char[][] words = new char[this.words.size()][];
+ int numWords = 0;
+ char[][] keys = this.words.keyTable;
+ for (int i = keys.length; i-- > 0;) {
+ if (keys[i] != null) {
+ words[numWords++] = keys[i];
+ }
+ }
+ Util.sort(words);
+ this.sortedWords = words;
+ }
+ return this.sortedWords;
+ }
+
+ /**
+ * Returns the word entry corresponding to the given word.
+ */
+ protected WordEntry getWordEntry(char[] word) {
+ return (WordEntry) words.get(word);
+ }
+
+ /**
+ * Initialises the fields of the index
+ */
+ public void init() {
+ words = new HashtableOfObject(1023);
+ files = new ObjectVector();
+ wordCount = 0;
+ footprint = 0;
+ sortedWords = null;
+ sortedFiles = null;
+ }
+
+ protected char[] preprocessWord(char[] word) {
+ if (word.length > 255) {
+ System.arraycopy(word, 0, word = new char[255], 0, 255);
+ }
+ return word;
+ }
+
+ /**
+ * Saves the index in the given file.
+ * Structure of the saved Index :
+ * - IndexedFiles in sorted order.
+ * + example:
+ * "c:/com/Test.java 1"
+ * "c:/com/UI.java 2"
+ * - References with the words in sorted order
+ * + example:
+ * "classDecl/Test 1"
+ * "classDecl/UI 2"
+ * "ref/String 1 2"
+ */
+
+ public void save(File file) throws IOException {
+ BlocksIndexOutput output = new BlocksIndexOutput(file);
+ save(output);
+ }
+
+ /**
+ * Saves the index in the given IndexOutput.
+ * Structure of the saved Index :
+ * - IndexedFiles in sorted order.
+ * + example:
+ * "c:/com/Test.java 1"
+ * "c:/com/UI.java 2"
+ * - References with the words in sorted order
+ * + example:
+ * "classDecl/Test 1"
+ * "classDecl/UI 2"
+ * "ref/String 1 2"
+ */
+
+ protected void save(IndexOutput output) throws IOException {
+ boolean ok = false;
+ char[][] sortedWords = getSortedWords();
+ try {
+ output.open();
+ int numFiles = this.files.size;
+ for (int i = 0; i < numFiles; ++i) {
+ IndexedFile indexedFile = (IndexedFile) this.files.elementAt(i);
+ output.addFile(indexedFile);
+ }
+ int numWords = sortedWords.length;
+ for (int i = 0; i < numWords; ++i) {
+ char[] word = sortedWords[i];
+ WordEntry entry = (WordEntry) this.words.get(word);
+ output.addWord(entry);
+ }
+ output.flush();
+ output.close();
+ ok = true;
+ } finally {
+ if (!ok)
+ if (output != null)
+ output.close();
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Index.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Index.java
new file mode 100644
index 0000000000..45925eed4f
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Index.java
@@ -0,0 +1,374 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.*;
+import java.io.*;
+import org.eclipse.jdt.internal.core.index.*;
+
+/**
+ * An Index is used to create an index on the disk, and to make queries. It uses a set of
+ * indexers and a mergeFactory. The index fills an inMemoryIndex up
+ * to it reaches a certain size, and then merges it with a main index on the disk.
+ * <br> <br>
+ * The changes are only taken into account by the queries after a merge.
+ */
+
+public class Index implements IIndex {
+ /**
+ * Maximum size of the index
+ */
+ public static final int MAX_FOOTPRINT = 2500000;
+
+ /**
+ * Index in memory, who is merged with mainIndex each times it
+ * reaches a certain size.
+ */
+ protected InMemoryIndex addsIndex;
+ protected IndexInput addsIndexInput;
+
+ /**
+ * State of the indexGenerator: addsIndex empty <=> MERGED, or
+ * addsIndex not empty <=> CAN_MERGE
+ */
+ protected int state;
+
+ /**
+ * Files removed form the addsIndex.
+ */
+ protected Hashtable removedInAdds;
+
+ /**
+ * Files removed form the oldIndex.
+ */
+ protected Hashtable removedInOld;
+ protected static final int CAN_MERGE = 0;
+ protected static final int MERGED = 1;
+ private File indexFile;
+
+ /**
+ * String representation of this index.
+ */
+ private String toString;
+ public Index(File indexDirectory) throws IOException {
+ this(indexDirectory, ".index");
+ }
+
+ public Index(File indexDirectory, String indexName) throws IOException {
+ super();
+ state = MERGED;
+ indexFile = new File(indexDirectory, indexName);
+ initialize();
+ }
+
+ public Index(String indexName) throws IOException {
+ this(indexName, null);
+ }
+
+ public Index(String indexName, String toString) throws IOException {
+ super();
+ state = MERGED;
+ indexFile = new File(indexName);
+ this.toString = toString;
+ initialize();
+ }
+
+ /**
+ * Indexes the given document, using the appropriate indexer registered in the indexerRegistry.
+ * If the document already exists in the index, it overrides the previous one. The changes will be
+ * taken into account after a merge.
+ */
+ public void add(IDocument document, IIndexer indexer) throws IOException {
+ if (timeToMerge()) {
+ merge();
+ }
+ IndexedFile indexedFile = addsIndex.getIndexedFile(document.getName());
+ if (indexedFile != null /*&& removedInAdds.get(document.getName()) == null*/
+ )
+ remove(indexedFile, MergeFactory.ADDS_INDEX);
+ IndexerOutput output = new IndexerOutput(addsIndex);
+ indexer.index(document, output);
+ state = CAN_MERGE;
+ }
+
+ /**
+ * Returns true if the index in memory is not empty, so
+ * merge() can be called to fill the mainIndex with the files and words
+ * contained in the addsIndex.
+ */
+ protected boolean canMerge() {
+ return state == CAN_MERGE;
+ }
+
+ /**
+ * Initialises the indexGenerator.
+ */
+ public void empty() throws IOException {
+
+ if (indexFile.exists()) {
+ indexFile.delete();
+ //initialisation of mainIndex
+ InMemoryIndex mainIndex = new InMemoryIndex();
+ IndexOutput mainIndexOutput = new BlocksIndexOutput(indexFile);
+ if (!indexFile.exists())
+ mainIndex.save(mainIndexOutput);
+ }
+
+ //initialisation of addsIndex
+ addsIndex = new InMemoryIndex();
+ addsIndexInput = new SimpleIndexInput(addsIndex);
+
+ //vectors who keep track of the removed Files
+ removedInAdds = new Hashtable(11);
+ removedInOld = new Hashtable(11);
+ }
+
+ /**
+ * @see IIndex#getIndexFile
+ */
+ public File getIndexFile() {
+ return indexFile;
+ }
+
+ /**
+ * @see IIndex#getNumDocuments
+ */
+ public int getNumDocuments() throws IOException {
+ save();
+ IndexInput input = new BlocksIndexInput(indexFile);
+ try {
+ input.open();
+ return input.getNumFiles();
+ } finally {
+ input.close();
+ }
+ }
+
+ /**
+ * @see IIndex#getNumWords
+ */
+ public int getNumWords() throws IOException {
+ save();
+ IndexInput input = new BlocksIndexInput(indexFile);
+ try {
+ input.open();
+ return input.getNumWords();
+ } finally {
+ input.close();
+ }
+ }
+
+ /**
+ * Returns the path corresponding to a given document number
+ */
+ public String getPath(int documentNumber) throws IOException {
+ save();
+ IndexInput input = new BlocksIndexInput(indexFile);
+ try {
+ input.open();
+ IndexedFile file = input.getIndexedFile(documentNumber);
+ if (file == null)
+ return null;
+ return file.getPath();
+ } finally {
+ input.close();
+ }
+ }
+
+ /**
+ * see IIndex.hasChanged
+ */
+ public boolean hasChanged() {
+ return canMerge();
+ }
+
+ /**
+ * Initialises the indexGenerator.
+ */
+ public void initialize() throws IOException {
+
+ //initialisation of addsIndex
+ addsIndex = new InMemoryIndex();
+ addsIndexInput = new SimpleIndexInput(addsIndex);
+
+ //vectors who keep track of the removed Files
+ removedInAdds = new Hashtable(11);
+ removedInOld = new Hashtable(11);
+
+ // check whether existing index file can be read
+ if (indexFile.exists()) {
+ IndexInput mainIndexInput = new BlocksIndexInput(indexFile);
+ try {
+ mainIndexInput.open();
+ } catch (IOException e) {
+ BlocksIndexInput input = (BlocksIndexInput) mainIndexInput;
+ try {
+ input.opened = true;
+ input.close();
+ } finally {
+ input.opened = false;
+ }
+ indexFile.delete();
+ mainIndexInput = null;
+ throw e;
+ }
+ mainIndexInput.close();
+ } else {
+ InMemoryIndex mainIndex = new InMemoryIndex();
+ IndexOutput mainIndexOutput = new BlocksIndexOutput(indexFile);
+ mainIndex.save(mainIndexOutput);
+ }
+ }
+
+ /**
+ * Merges the in memory index and the index on the disk, and saves the results on the disk.
+ */
+ protected void merge() throws IOException {
+ //System.out.println("merge");
+
+ //initialisation of tempIndex
+ File tempFile = new File(indexFile.getAbsolutePath() + "TempVA");
+
+ boolean exists = indexFile.exists();
+ IndexInput mainIndexInput = new BlocksIndexInput(indexFile);
+ BlocksIndexOutput tempIndexOutput = new BlocksIndexOutput(tempFile);
+
+ //invoke a mergeFactory
+ new MergeFactory(
+ mainIndexInput,
+ addsIndexInput,
+ tempIndexOutput,
+ removedInOld,
+ removedInAdds)
+ .merge();
+
+ //rename the file created to become the main index
+ File mainIndexFile = (File) mainIndexInput.getSource();
+ File tempIndexFile = (File) tempIndexOutput.getDestination();
+ mainIndexFile.delete();
+ tempIndexFile.renameTo(mainIndexFile);
+
+ //initialise remove vectors and addsindex, and change the state
+ removedInAdds.clear();
+ removedInOld.clear();
+ addsIndex.init();
+ addsIndexInput = new SimpleIndexInput(addsIndex);
+ state = MERGED;
+ }
+
+ /**
+ * @see IIndex#query
+ */
+ public IQueryResult[] query(String word) throws IOException {
+ save();
+ IndexInput input = new BlocksIndexInput(indexFile);
+ try {
+ return input.query(word);
+ } finally {
+ input.close();
+ }
+ }
+
+ public IEntryResult[] queryEntries(char[] prefix) throws IOException {
+ save();
+ IndexInput input = new BlocksIndexInput(indexFile);
+ try {
+ return input.queryEntriesPrefixedBy(prefix);
+ } finally {
+ input.close();
+ }
+ }
+
+ /**
+ * @see IIndex#queryInDocumentNames
+ */
+ public IQueryResult[] queryInDocumentNames(String word) throws IOException {
+ save();
+ IndexInput input = new BlocksIndexInput(indexFile);
+ try {
+ return input.queryInDocumentNames(word);
+ } finally {
+ input.close();
+ }
+ }
+
+ /**
+ * @see IIndex#queryPrefix
+ */
+ public IQueryResult[] queryPrefix(char[] prefix) throws IOException {
+ save();
+ IndexInput input = new BlocksIndexInput(indexFile);
+ try {
+ return input.queryFilesReferringToPrefix(prefix);
+ } finally {
+ input.close();
+ }
+ }
+
+ /**
+ * @see IIndex#remove
+ */
+ public void remove(String documentName) throws IOException {
+ IndexedFile file = addsIndex.getIndexedFile(documentName);
+ if (file != null) {
+ //the file is in the adds Index, we remove it from this one
+ Int lastRemoved = (Int) removedInAdds.get(documentName);
+ if (lastRemoved != null) {
+ int fileNum = file.getFileNumber();
+ if (lastRemoved.value < fileNum)
+ lastRemoved.value = fileNum;
+ } else
+ removedInAdds.put(documentName, new Int(file.getFileNumber()));
+ } else {
+ //we remove the file from the old index
+ removedInOld.put(documentName, new Int(1));
+ }
+ state = CAN_MERGE;
+ }
+
+ /**
+ * Removes the given document from the given index (MergeFactory.ADDS_INDEX for the
+ * in memory index, MergeFactory.OLD_INDEX for the index on the disk).
+ */
+ protected void remove(IndexedFile file, int index) throws IOException {
+ String name = file.getPath();
+ if (index == MergeFactory.ADDS_INDEX) {
+ Int lastRemoved = (Int) removedInAdds.get(name);
+ if (lastRemoved != null) {
+ if (lastRemoved.value < file.getFileNumber())
+ lastRemoved.value = file.getFileNumber();
+ } else
+ removedInAdds.put(name, new Int(file.getFileNumber()));
+ } else
+ if (index == MergeFactory.OLD_INDEX)
+ removedInOld.put(name, new Int(1));
+ else
+ throw new Error();
+ state = CAN_MERGE;
+ }
+
+ /**
+ * @see IIndex#save
+ */
+ public void save() throws IOException {
+ if (canMerge())
+ merge();
+ }
+
+ /**
+ * Returns true if the in memory index reaches a critical size,
+ * to merge it with the index on the disk.
+ */
+ protected boolean timeToMerge() {
+ return (addsIndex.getFootprint() >= MAX_FOOTPRINT);
+ }
+
+ public String toString() {
+ if (this.toString == null)
+ return super.toString();
+ return this.toString;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexBlock.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexBlock.java
new file mode 100644
index 0000000000..9fd1a67a55
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexBlock.java
@@ -0,0 +1,91 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.util.*;
+
+import java.io.*;
+
+/**
+ * An indexBlock stores wordEntries.
+ */
+
+public abstract class IndexBlock extends Block {
+
+ public IndexBlock(int blockSize) {
+ super(blockSize);
+ }
+
+ /**
+ * Adds the given wordEntry to the indexBlock.
+ */
+
+ public abstract boolean addEntry(WordEntry entry);
+ /**
+ * @see Block#clear
+ */
+ public void clear() {
+ reset();
+ super.clear();
+ }
+
+ /**
+ * @see Block#findEntry
+ */
+ public WordEntry findEntryMatching(char[] pattern, boolean isCaseSensitive) {
+ reset();
+ WordEntry entry = new WordEntry();
+ while (nextEntry(entry)) {
+ if (CharOperation.match(pattern, entry.getWord(), isCaseSensitive)) {
+ return entry;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @see Block#findEntry
+ */
+ public WordEntry findEntryPrefixedBy(char[] word, boolean isCaseSensitive) {
+ reset();
+ WordEntry entry = new WordEntry();
+ while (nextEntry(entry)) {
+ if (CharOperation.prefixEquals(entry.getWord(), word, isCaseSensitive)) {
+ return entry;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @see Block#findEntry
+ */
+ public WordEntry findExactEntry(char[] word) {
+ reset();
+ WordEntry entry = new WordEntry();
+ while (nextEntry(entry)) {
+ if (CharOperation.equals(entry.getWord(), word)) {
+ return entry;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns whether the block is empty or not (if it doesn't contain any wordEntry).
+ */
+ public abstract boolean isEmpty();
+ /**
+ * Finds the next wordEntry and stores it in the given entry.
+ */
+
+ public abstract boolean nextEntry(WordEntry entry);
+ /**
+ * @see Block#findEntry
+ */
+ public void reset() {
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexInput.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexInput.java
new file mode 100644
index 0000000000..ae4380c38f
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexInput.java
@@ -0,0 +1,138 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+import org.eclipse.jdt.internal.core.index.*;
+
+/**
+ * This class provides an input on an index, after it has been generated.<br>
+ * You can access all the files of an index via getNextFile(), getCurrentFile()
+ * and moveToNextFile() (idem for the word entries). <br>
+ * The usage is the same for every subclass: creation (constructor), opening
+ * (the open() method), usage, and closing (the close() method), to release the
+ * data source used by this input.
+ */
+
+public abstract class IndexInput {
+ protected int filePosition;
+ protected WordEntry currentWordEntry;
+ protected int wordPosition;
+
+ public IndexInput() {
+ super();
+ wordPosition = 1;
+ filePosition = 1;
+ }
+
+ /**
+ * clears the cache of this indexInput, if it keeps track of the information already read.
+ */
+ public abstract void clearCache();
+ /**
+ * Closes the IndexInput. For example, if the input is on a RandomAccessFile,
+ * it calls the close() method of RandomAccessFile.
+ */
+ public abstract void close() throws IOException;
+ /**
+ * Returns the current file the indexInput is pointing to in the index.
+ */
+ public abstract IndexedFile getCurrentFile() throws IOException;
+ /**
+ * Returns the current file the indexInput is pointing to in the index.
+ */
+ public WordEntry getCurrentWordEntry() throws IOException {
+ if (!hasMoreWords())
+ return null;
+ return currentWordEntry;
+ }
+
+ /**
+ * Returns the position of the current file the input is pointing to in the index.
+ */
+ public int getFilePosition() {
+ return filePosition;
+ }
+
+ /**
+ * Returns the indexedFile corresponding to the given document number in the index the input
+ * reads in, or null if such indexedFile does not exist.
+ */
+ public abstract IndexedFile getIndexedFile(int fileNum) throws IOException;
+ /**
+ * Returns the indexedFile corresponding to the given document in the index the input
+ * reads in (e.g. the indexedFile with the same path in this index), or null if such
+ * indexedFile does not exist.
+ */
+ public abstract IndexedFile getIndexedFile(IDocument document)
+ throws IOException;
+ /**
+ * Returns the number of files in the index.
+ */
+ public abstract int getNumFiles();
+ /**
+ * Returns the number of unique words in the index.
+ */
+ public abstract int getNumWords();
+ /**
+ * Returns the Object the input is reading from. It can be an IIndex,
+ * a File, ...
+ */
+ public abstract Object getSource();
+ /**
+ * Returns true if the input has not reached the end of the index for the files.
+ */
+ public boolean hasMoreFiles() {
+ return getFilePosition() <= getNumFiles();
+ }
+
+ /**
+ * Returns true if the input has not reached the end of the index for the files.
+ */
+ public boolean hasMoreWords() {
+ return wordPosition <= getNumWords();
+ }
+
+ /**
+ * Moves the pointer on the current file to the next file in the index.
+ */
+ public abstract void moveToNextFile() throws IOException;
+ /**
+ * Moves the pointer on the current word to the next file in the index.
+ */
+ public abstract void moveToNextWordEntry() throws IOException;
+ /**
+ * Open the Source where the input gets the information from.
+ */
+ public abstract void open() throws IOException;
+ public void printStats(PrintStream out) {
+ out.println("Index stats :");
+ int numFiles = getNumFiles();
+ out.println(" files: " + numFiles);
+ out.println(" total words indexed (unique): " + this.getNumWords());
+ }
+
+ /**
+ * Returns the list of the files containing the given word in the index.
+ */
+ public abstract IQueryResult[] query(String word) throws IOException;
+ public abstract IEntryResult[] queryEntriesPrefixedBy(char[] prefix /*, boolean isCaseSensitive*/)
+ throws IOException;
+ public abstract IQueryResult[] queryFilesReferringToPrefix(char[] prefix)
+ throws IOException;
+ /**
+ * Returns the list of the files whose name contain the given word in the index.
+ */
+ public abstract IQueryResult[] queryInDocumentNames(String word)
+ throws IOException;
+ /**
+ * Set the pointer on the current file to the first file of the index.
+ */
+ protected abstract void setFirstFile() throws IOException;
+ /**
+ * Set the pointer on the current word to the first word of the index.
+ */
+ protected abstract void setFirstWord() throws IOException;
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexOutput.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexOutput.java
new file mode 100644
index 0000000000..bba3eac2f2
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexOutput.java
@@ -0,0 +1,37 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.IOException;
+
+/**
+ * An indexOutput is used to write an index into a different object (a File, ...).
+ */
+public abstract class IndexOutput {
+ /**
+ * Adds a File to the destination.
+ */
+ public abstract void addFile(IndexedFile file) throws IOException;
+ /**
+ * Adds a word to the destination.
+ */
+ public abstract void addWord(WordEntry word) throws IOException;
+ /**
+ * Closes the output, releasing the resources it was using.
+ */
+ public abstract void close() throws IOException;
+ /**
+ * Flushes the output.
+ */
+ public abstract void flush() throws IOException;
+ /**
+ * Returns the Object the output is writing to. It can be a file, another type of index, ...
+ */
+ public abstract Object getDestination();
+ /**
+ * Opens the output, before writing any information.
+ */
+ public abstract void open() throws IOException;
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexSummary.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexSummary.java
new file mode 100644
index 0000000000..4a94dfb90c
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexSummary.java
@@ -0,0 +1,334 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.util.*;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * An indexSummary is used when saving an index into a BlocksIndexOuput or
+ * reading it from a BlocksIndexInput. It contains basic informations about
+ * an index: first files/words in each block, number of files/words.
+ */
+
+public class IndexSummary {
+ /**
+ * First file for each block.
+ */
+ protected Vector firstFilesInBlocks = new Vector();
+
+ /**
+ * First word for each block.
+ */
+ protected Vector firstWordsInBlocks = new Vector();
+
+ /**
+ * Number of files in the index.
+ */
+ protected int numFiles;
+
+ /**
+ * Number of words in the index.
+ */
+ protected int numWords;
+
+ static class FirstFileInBlock {
+ IndexedFile indexedFile;
+ int blockNum;
+ }
+
+ static class FirstWordInBlock {
+ char[] word;
+ int blockNum;
+ public String toString() {
+ return "FirstWordInBlock: " + new String(word) + ", blockNum: " + blockNum;
+ }
+ }
+
+ protected int firstWordBlockNum;
+ protected boolean firstWordAdded = true;
+ /**
+ * Adds the given file as the first file for the given Block number.
+ */
+ public void addFirstFileInBlock(IndexedFile indexedFile, int blockNum) {
+ FirstFileInBlock entry = new FirstFileInBlock();
+ entry.indexedFile = indexedFile;
+ entry.blockNum = blockNum;
+ firstFilesInBlocks.addElement(entry);
+ }
+
+ /**
+ * Adds the given word as the first word for the given Block number.
+ */
+ public void addFirstWordInBlock(char[] word, int blockNum) {
+ if (firstWordAdded) {
+ firstWordBlockNum = blockNum;
+ firstWordAdded = false;
+ }
+ FirstWordInBlock entry = new FirstWordInBlock();
+ entry.word = word;
+ entry.blockNum = blockNum;
+ firstWordsInBlocks.addElement(entry);
+ }
+
+ /**
+ * Returns the numbers of all the blocks
+ */
+ public int[] getAllBlockNums() {
+
+ int max = firstWordsInBlocks.size();
+ int[] blockNums = new int[max];
+ for (int i = 0; i < max; i++) {
+ blockNums[i] = ((FirstWordInBlock) firstWordsInBlocks.elementAt(i)).blockNum;
+ }
+ return blockNums;
+ }
+
+ public int getBlockNum(int blockLocation) {
+ return (
+ (FirstWordInBlock) firstWordsInBlocks.elementAt(blockLocation)).blockNum;
+ }
+
+ /**
+ * Returns the number of the Block containing the file with the given number.
+ */
+ public int getBlockNumForFileNum(int fileNum) {
+ int min = 0;
+ int max = firstFilesInBlocks.size() - 1;
+ while (min <= max) {
+ int mid = (min + max) / 2;
+ FirstFileInBlock entry = (FirstFileInBlock) firstFilesInBlocks.elementAt(mid);
+ int compare = fileNum - entry.indexedFile.getFileNumber();
+ if (compare == 0)
+ return entry.blockNum;
+ if (compare < 0)
+ max = mid - 1;
+ else
+ min = mid + 1;
+ }
+ if (max < 0)
+ return -1;
+ FirstFileInBlock entry = (FirstFileInBlock) firstFilesInBlocks.elementAt(max);
+ return entry.blockNum;
+ }
+
+ /**
+ * Returns the number of the Block containing the given word.
+ */
+ public int getBlockNumForWord(char[] word) {
+ int min = 0;
+ int max = firstWordsInBlocks.size() - 1;
+ while (min <= max) {
+ int mid = (min + max) / 2;
+ FirstWordInBlock entry = (FirstWordInBlock) firstWordsInBlocks.elementAt(mid);
+ int compare = Util.compare(word, entry.word);
+ if (compare == 0)
+ return entry.blockNum;
+ if (compare < 0)
+ max = mid - 1;
+ else
+ min = mid + 1;
+ }
+ if (max < 0)
+ return -1;
+ FirstWordInBlock entry = (FirstWordInBlock) firstWordsInBlocks.elementAt(max);
+ return entry.blockNum;
+ }
+
+ public int[] getBlockNumsForPrefix(char[] prefix) {
+ int min = 0;
+ int size = firstWordsInBlocks.size();
+ int max = size - 1;
+ int match = -1;
+ while (min <= max && match < 0) {
+ int mid = (min + max) / 2;
+ FirstWordInBlock entry = (FirstWordInBlock) firstWordsInBlocks.elementAt(mid);
+ int compare = Util.startsWith(entry.word, prefix);
+ if (compare == 0) {
+ match = mid;
+ break;
+ }
+ if (compare >= 0)
+ max = mid - 1;
+ else
+ min = mid + 1;
+ }
+ if (max < 0)
+ return new int[0];
+
+ if (match < 0)
+ match = max;
+
+ int firstBlock = match - 1;
+ // Look if previous blocks are affected
+ for (; firstBlock >= 0; firstBlock--) {
+ FirstWordInBlock entry =
+ (FirstWordInBlock) firstWordsInBlocks.elementAt(firstBlock);
+ if (!CharOperation.startsWith(entry.word, prefix))
+ break;
+ }
+ if (firstBlock < 0)
+ firstBlock = 0;
+
+ // Look if next blocks are affected
+ int firstNotIncludedBlock = match + 1;
+ for (; firstNotIncludedBlock < size; firstNotIncludedBlock++) {
+ FirstWordInBlock entry =
+ (FirstWordInBlock) firstWordsInBlocks.elementAt(firstNotIncludedBlock);
+ if (!CharOperation.startsWith(entry.word, prefix))
+ break;
+ }
+
+ int numberOfBlocks = firstNotIncludedBlock - firstBlock;
+ int[] result = new int[numberOfBlocks];
+ int pos = firstBlock;
+ for (int i = 0; i < numberOfBlocks; i++, pos++) {
+ FirstWordInBlock entry = (FirstWordInBlock) firstWordsInBlocks.elementAt(pos);
+ result[i] = entry.blockNum;
+ }
+ return result;
+ }
+
+ public int getFirstBlockLocationForPrefix(char[] prefix) {
+ int min = 0;
+ int size = firstWordsInBlocks.size();
+ int max = size - 1;
+ int match = -1;
+ while (min <= max) {
+ int mid = (min + max) / 2;
+ FirstWordInBlock entry = (FirstWordInBlock) firstWordsInBlocks.elementAt(mid);
+ int compare = Util.startsWith(entry.word, prefix);
+ if (compare == 0) {
+ match = mid;
+ break;
+ }
+ if (compare >= 0) {
+ max = mid - 1;
+ } else {
+ match = mid; // not perfect match, but could be inside
+ min = mid + 1;
+ }
+ }
+ if (max < 0)
+ return -1;
+
+ // no match at all, might be some matching entries inside max block
+ if (match < 0) {
+ match = max;
+ } else {
+ // look for possible matches inside previous blocks
+ while (match > 0) {
+ FirstWordInBlock entry = (FirstWordInBlock) firstWordsInBlocks.elementAt(match);
+ if (!CharOperation.startsWith(entry.word, prefix)) {
+ break;
+ }
+ match--;
+ }
+ }
+ return match;
+ }
+
+ /**
+ * Returns the number of the first IndexBlock (containing words).
+ */
+ public int getFirstWordBlockNum() {
+ return firstWordBlockNum;
+ }
+
+ /**
+ * Blocks are contiguous, so the next one is a potential candidate if its first word starts with
+ * the given prefix
+ */
+ public int getNextBlockLocationForPrefix(char[] prefix, int blockLoc) {
+ if (++blockLoc < firstWordsInBlocks.size()) {
+ FirstWordInBlock entry =
+ (FirstWordInBlock) firstWordsInBlocks.elementAt(blockLoc);
+ if (CharOperation.startsWith(entry.word, prefix))
+ return blockLoc;
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the number of files contained in the index.
+ */
+ public int getNumFiles() {
+ return numFiles;
+ }
+
+ /**
+ * Returns the number of words contained in the index.
+ */
+ public int getNumWords() {
+ return numWords;
+ }
+
+ /**
+ * Loads the summary in memory.
+ */
+ public void read(RandomAccessFile raf) throws IOException {
+ numFiles = raf.readInt();
+ numWords = raf.readInt();
+ firstWordBlockNum = raf.readInt();
+ int numFirstFiles = raf.readInt();
+ for (int i = 0; i < numFirstFiles; ++i) {
+ FirstFileInBlock entry = new FirstFileInBlock();
+ String path = raf.readUTF();
+ int fileNum = raf.readInt();
+ entry.indexedFile = new IndexedFile(path, fileNum);
+ entry.blockNum = raf.readInt();
+ firstFilesInBlocks.addElement(entry);
+ }
+ int numFirstWords = raf.readInt();
+ for (int i = 0; i < numFirstWords; ++i) {
+ FirstWordInBlock entry = new FirstWordInBlock();
+ entry.word = raf.readUTF().toCharArray();
+ entry.blockNum = raf.readInt();
+ firstWordsInBlocks.addElement(entry);
+ }
+ }
+
+ /**
+ * Sets the number of files of the index.
+ */
+
+ public void setNumFiles(int numFiles) {
+ this.numFiles = numFiles;
+ }
+
+ /**
+ * Sets the number of words of the index.
+ */
+
+ public void setNumWords(int numWords) {
+ this.numWords = numWords;
+ }
+
+ /**
+ * Saves the summary on the disk.
+ */
+ public void write(RandomAccessFile raf) throws IOException {
+ long fp = raf.getFilePointer();
+ raf.writeInt(numFiles);
+ raf.writeInt(numWords);
+ raf.writeInt(firstWordBlockNum);
+ raf.writeInt(firstFilesInBlocks.size());
+ for (int i = 0, size = firstFilesInBlocks.size(); i < size; ++i) {
+ FirstFileInBlock entry = (FirstFileInBlock) firstFilesInBlocks.elementAt(i);
+ raf.writeUTF(entry.indexedFile.getPath());
+ raf.writeInt(entry.indexedFile.getFileNumber());
+ raf.writeInt(entry.blockNum);
+ }
+ raf.writeInt(firstWordsInBlocks.size());
+ for (int i = 0, size = firstWordsInBlocks.size(); i < size; ++i) {
+ FirstWordInBlock entry = (FirstWordInBlock) firstWordsInBlocks.elementAt(i);
+ raf.writeUTF(new String(entry.word));
+ raf.writeInt(entry.blockNum);
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexedFile.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexedFile.java
new file mode 100644
index 0000000000..27f6ab3f17
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexedFile.java
@@ -0,0 +1,185 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+import java.util.*;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.internal.core.index.*;
+
+/**
+ * An indexedFile associates a number to a document path, and document properties.
+ * It is what we add into an index, and the result of a query.
+ */
+
+public class IndexedFile implements IQueryResult {
+ protected String path;
+ protected int fileNumber;
+ protected static final String INFO_BEGIN = "(";
+ protected static final String INFO_END = ")";
+ protected static final String INFO_SEPARATOR = ",";
+ protected static final String INFO_VALUE_SEPARATOR = ":";
+ protected static final int MAX_PROPERTIES_SIZE = 2 * 1024;
+ protected Hashtable properties;
+ protected int propertiesSize = 2 * (INFO_BEGIN.length() + INFO_END.length());
+
+ public IndexedFile(String pathOrInfo, int fileNum) {
+ if (fileNum < 1)
+ throw new IllegalArgumentException();
+ this.fileNumber = fileNum;
+ properties = new Hashtable();
+ int dp = pathOrInfo.indexOf(INFO_BEGIN);
+ if (dp == -1)
+ path = pathOrInfo;
+ else {
+ String fileInfo = pathOrInfo;
+ path = fileInfo.substring(0, dp);
+ String props = fileInfo.substring(dp, fileInfo.length());
+ StringTokenizer t =
+ new StringTokenizer(props.substring(1, props.length() - 1), INFO_SEPARATOR);
+ while (t.hasMoreTokens()) {
+ String g = t.nextToken();
+ try {
+ int dpt = g.indexOf(INFO_VALUE_SEPARATOR);
+ setProperty(g.substring(0, dpt), g.substring(dpt + 1, g.length()));
+ } catch (Exception e) {
+ }
+ }
+ }
+ }
+
+ public IndexedFile(IDocument document, int fileNum) {
+ if (fileNum < 1)
+ throw new IllegalArgumentException();
+ this.path = document.getName();
+ this.fileNumber = fileNum;
+ properties = new Hashtable();
+ computeProperties(document);
+ }
+
+ protected void computeProperties(IDocument document) {
+ for (Enumeration e = document.getPropertyNames(); e.hasMoreElements();) {
+ String property = (String) e.nextElement();
+ setProperty(property, document.getProperty(property));
+ }
+ }
+
+ /**
+ * Returns the path represented by pathString converted back to a path relative to the local file system.
+ *
+ * @parame pathString the path to convert:
+ * <ul>
+ * <li>an absolute IPath (relative to the workspace root) if the path represents a resource in the
+ * workspace
+ * <li>a relative IPath (relative to the workspace root) followed by JAR_FILE_ENTRY_SEPARATOR
+ * followed by an absolute path (relative to the jar) if the path represents a .class file in
+ * an internal jar
+ * <li>an absolute path (relative to the file system) followed by JAR_FILE_ENTRY_SEPARATOR
+ * followed by an absolute path (relative to the jar) if the path represents a .class file in
+ * an external jar
+ * </ul>
+ * @return the converted path:
+ * <ul>
+ * <li>the original pathString if the path represents a resource in the workspace
+ * <li>an absolute path (relative to the file system) followed by JAR_FILE_ENTRY_SEPARATOR
+ * followed by an absolute path (relative to the jar) if the path represents a .class file in
+ * an external or internal jar
+ * </ul>
+ */
+ public static String convertPath(String pathString) {
+ int index = pathString.indexOf(JarFileEntryDocument.JAR_FILE_ENTRY_SEPARATOR);
+ if (index == -1)
+ return pathString;
+
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ Path jarPath = new Path(pathString.substring(0, index));
+ if (!jarPath.isAbsolute()) {
+ return jarPath.makeAbsolute().toString()
+ + pathString.substring(index, pathString.length());
+ } else {
+ return jarPath.toOSString() + pathString.substring(index, pathString.length());
+ }
+ }
+
+ /**
+ * Returns the size of the indexedFile.
+ */
+ public int footprint() {
+ //object+ 2 slots + size of the string
+ return 8 + (2 * 4) + (28 + path.length() * 2);
+ }
+
+ /**
+ * Returns the file number.
+ */
+ public int getFileNumber() {
+ return fileNumber;
+ }
+
+ /**
+ * Returns the path.
+ */
+ public String getPath() {
+ return path;
+ }
+
+ public String getProperty(String propertyName) {
+ return (String) properties.get(propertyName);
+ ;
+ }
+
+ /**
+ * getPropertyNames method comment.
+ */
+ public Enumeration getPropertyNames() {
+ return properties.keys();
+ }
+
+ public String propertiesToString() {
+ if (properties.isEmpty())
+ return "";
+ StringBuffer prop = new StringBuffer(INFO_BEGIN);
+ for (Enumeration e = getPropertyNames(); e.hasMoreElements();) {
+ String property = (String) e.nextElement();
+ String value = getProperty(property);
+ prop.append(property);
+ prop.append(INFO_VALUE_SEPARATOR);
+ prop.append(value);
+ if (e.hasMoreElements())
+ prop.append(INFO_SEPARATOR);
+ }
+ prop.append(INFO_END);
+ return prop.toString();
+ }
+
+ /**
+ * Sets the file number.
+ */
+ public void setFileNumber(int fileNumber) {
+ this.fileNumber = fileNumber;
+ }
+
+ /**
+ * getPropertyNames method comment.
+ */
+ public void setProperty(String propertyName, String value) {
+ propertiesSize
+ += (INFO_SEPARATOR.length()
+ + propertyName.length()
+ + INFO_VALUE_SEPARATOR.length()
+ + value.length())
+ * 2;
+ if (propertiesSize < MAX_PROPERTIES_SIZE)
+ properties.put(propertyName, value);
+ }
+
+ public String toString() {
+ return "IndexedFile(" + fileNumber + ": " + path + ")";
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexerOutput.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexerOutput.java
new file mode 100644
index 0000000000..c8d9644a4e
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexerOutput.java
@@ -0,0 +1,56 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.index.*;
+
+/**
+ * An indexerOutput is used by an indexer to add documents and word references to
+ * an inMemoryIndex. It keeps track of the document being indexed and add the
+ * word references to this document (so you do not need to precise the document
+ * each time you add a word).
+ */
+
+public class IndexerOutput implements IIndexerOutput {
+ protected InMemoryIndex index;
+ protected IndexedFile indexedFile;
+ protected IDocument document;
+ /**
+ * IndexerOutput constructor comment.
+ */
+ public IndexerOutput(InMemoryIndex index) {
+ this.index = index;
+ }
+
+ /**
+ * Adds the given document to the inMemoryIndex.
+ */
+
+ public void addDocument(IDocument document) {
+ if (indexedFile == null) {
+ indexedFile = index.addDocument(document);
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ /**
+ * Adds a reference to the given word to the inMemoryIndex.
+ */
+ public void addRef(char[] word) {
+ if (indexedFile == null) {
+ throw new IllegalStateException();
+ }
+ index.addRef(indexedFile, word);
+ }
+
+ /**
+ * Adds a reference to the given word to the inMemoryIndex.
+ */
+ public void addRef(String word) {
+ addRef(word.toCharArray());
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Int.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Int.java
new file mode 100644
index 0000000000..3b80e785b5
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Int.java
@@ -0,0 +1,12 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+public class Int {
+ public int value;
+ /**
+ * Int constructor comment.
+ */
+ public Int(int i) {
+ value = i;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/JarFileDocument.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/JarFileDocument.java
new file mode 100644
index 0000000000..638d427f5c
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/JarFileDocument.java
@@ -0,0 +1,69 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+
+import java.io.*;
+
+/**
+ * An <code>JarFileDocument</code> represents an jar file.
+ */
+
+public class JarFileDocument extends PropertyDocument {
+ protected IFile file;
+ /**
+ * JarFileDocument constructor comment.
+ */
+ public JarFileDocument(IFile file) {
+ this.file = file;
+ }
+
+ /**
+ * This API always return null for a JarFileDocument
+ * @see IDocument#getByteContent
+ */
+ public byte[] getByteContent() throws IOException {
+ return null;
+ }
+
+ /**
+ * This API always return null for a JarFileDocument
+ * @see IDocument#getByteContent
+ */
+ public char[] getCharContent() throws IOException {
+ return null;
+ }
+
+ public File getFile() {
+ return file.getLocation().toFile();
+ }
+
+ /**
+ * @see IDocument#getName
+ */
+ public String getName() {
+ return file.getFullPath().toString();
+ }
+
+ /**
+ * This API always return null for a JarFileDocument
+ * @see IDocument#getByteContent
+ */
+ public String getStringContent() throws java.io.IOException {
+ return null;
+ }
+
+ /**
+ * @see IDocument#getType
+ */
+ public String getType() {
+ String extension = file.getFileExtension();
+ if (extension == null)
+ return "";
+ return extension;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/JarFileEntryDocument.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/JarFileEntryDocument.java
new file mode 100644
index 0000000000..4edbe7fb6c
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/JarFileEntryDocument.java
@@ -0,0 +1,76 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.Path;
+
+import java.io.*;
+import java.util.zip.*;
+
+/**
+ * An <code>JarFileEntryDocument</code> represents an jar file.
+ */
+
+public class JarFileEntryDocument extends PropertyDocument {
+ protected ZipEntry zipEntry;
+ protected byte[] byteContents;
+ protected Path zipFilePath;
+ public static final String JAR_FILE_ENTRY_SEPARATOR = "|";
+ /**
+ * JarFileEntryDocument constructor comment.
+ */
+ public JarFileEntryDocument(
+ ZipEntry entry,
+ byte[] contents,
+ Path zipFilePath) {
+ this.zipEntry = entry;
+ this.byteContents = contents;
+ this.zipFilePath = zipFilePath;
+ }
+
+ /**
+ * This API always return null for a JarFileDocument
+ * @see IDocument#getByteContent
+ */
+ public byte[] getByteContent() throws IOException {
+ return this.byteContents;
+ }
+
+ /**
+ * This API always return null for a JarFileDocument
+ * @see IDocument#getByteContent
+ */
+ public char[] getCharContent() throws IOException {
+ return null;
+ }
+
+ /**
+ * @see IDocument#getName
+ */
+ public String getName() {
+ return zipFilePath + JAR_FILE_ENTRY_SEPARATOR + zipEntry.getName();
+ }
+
+ /**
+ * This API always return null for a JarFileDocument
+ * @see IDocument#getByteContent
+ */
+ public String getStringContent() throws java.io.IOException {
+ return null;
+ }
+
+ /**
+ * @see IDocument#getType
+ */
+ public String getType() {
+ return "class";
+ }
+
+ public void setBytes(byte[] byteContents) {
+ this.byteContents = byteContents;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/LRUCache.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/LRUCache.java
new file mode 100644
index 0000000000..c080db7018
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/LRUCache.java
@@ -0,0 +1,491 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+/**
+ * The <code>LRUCache</code> is a hashtable that stores a finite number of elements.
+ * When an attempt is made to add values to a full cache, the least recently used values
+ * in the cache are discarded to make room for the new values as necessary.
+ *
+ * <p>The data structure is based on the LRU virtual memory paging scheme.
+ *
+ * <p>Objects can take up a variable amount of cache space by implementing
+ * the <code>ILRUCacheable</code> interface.
+ *
+ * <p>This implementation is NOT thread-safe. Synchronization wrappers would
+ * have to be added to ensure atomic insertions and deletions from the cache.
+ *
+ * @see LRUCacheEntry
+ * @see ILRUCacheable
+ */
+public class LRUCache implements Cloneable {
+
+ /**
+ * This type is used internally by the LRUCache to represent entries
+ * stored in the cache.
+ * It is static because it does not require a pointer to the cache
+ * which contains it.
+ *
+ * @see LRUCache
+ */
+ protected static class LRUCacheEntry {
+
+ /**
+ * Hash table key
+ */
+ /* package */
+ Object _fKey;
+
+ /**
+ * Hash table value (an LRUCacheEntry object)
+ */
+ /* package */
+ Object _fValue;
+
+ /**
+ * Time value for queue sorting
+ */
+ /* package */
+ int _fTimestamp;
+
+ /**
+ * Cache footprint of this entry
+ */
+ int _fSpace;
+
+ /**
+ * Previous entry in queue
+ */
+ /* package */
+ LRUCacheEntry _fPrevious;
+
+ /**
+ * Next entry in queue
+ */
+ /* package */
+ LRUCacheEntry _fNext;
+
+ /**
+ * Creates a new instance of the receiver with the provided values
+ * for key, value, and space.
+ */
+ public LRUCacheEntry(Object key, Object value, int space) {
+ _fKey = key;
+ _fValue = value;
+ _fSpace = space;
+ }
+
+ /**
+ * Returns a String that represents the value of this object.
+ */
+ public String toString() {
+
+ return "LRUCacheEntry [" + _fKey + "-->" + _fValue + "]";
+ }
+ }
+
+ /**
+ * Amount of cache space used so far
+ */
+ protected int fCurrentSpace;
+
+ /**
+ * Maximum space allowed in cache
+ */
+ protected int fSpaceLimit;
+
+ /**
+ * Counter for handing out sequential timestamps
+ */
+ protected int fTimestampCounter;
+
+ /**
+ * Hash table for fast random access to cache entries
+ */
+ protected Hashtable fEntryTable;
+
+ /**
+ * Start of queue (most recently used entry)
+ */
+ protected LRUCacheEntry fEntryQueue;
+
+ /**
+ * End of queue (least recently used entry)
+ */
+ protected LRUCacheEntry fEntryQueueTail;
+
+ /**
+ * Default amount of space in the cache
+ */
+ protected static final int DEFAULT_SPACELIMIT = 100;
+ /**
+ * Creates a new cache. Size of cache is defined by
+ * <code>DEFAULT_SPACELIMIT</code>.
+ */
+ public LRUCache() {
+
+ this(DEFAULT_SPACELIMIT);
+ }
+
+ /**
+ * Creates a new cache.
+ * @param size Size of Cache
+ */
+ public LRUCache(int size) {
+
+ fTimestampCounter = fCurrentSpace = 0;
+ fEntryQueue = fEntryQueueTail = null;
+ fEntryTable = new Hashtable(size);
+ fSpaceLimit = size;
+ }
+
+ /**
+ * Returns a new cache containing the same contents.
+ *
+ * @return New copy of object.
+ */
+ public Object clone() {
+
+ LRUCache newCache = newInstance(fSpaceLimit);
+ LRUCacheEntry qEntry;
+
+ /* Preserve order of entries by copying from oldest to newest */
+ qEntry = this.fEntryQueueTail;
+ while (qEntry != null) {
+ newCache.privateAdd(qEntry._fKey, qEntry._fValue, qEntry._fSpace);
+ qEntry = qEntry._fPrevious;
+ }
+ return newCache;
+ }
+
+ /**
+ * Flushes all entries from the cache.
+ */
+ public void flush() {
+
+ fCurrentSpace = 0;
+ LRUCacheEntry entry = fEntryQueueTail; // Remember last entry
+ fEntryTable = new Hashtable(); // Clear it out
+ fEntryQueue = fEntryQueueTail = null;
+ while (entry != null) { // send deletion notifications in LRU order
+ privateNotifyDeletionFromCache(entry);
+ entry = entry._fPrevious;
+ }
+ }
+
+ /**
+ * Flushes the given entry from the cache. Does nothing if entry does not
+ * exist in cache.
+ *
+ * @param key Key of object to flush
+ */
+ public void flush(Object key) {
+
+ LRUCacheEntry entry;
+
+ entry = (LRUCacheEntry) fEntryTable.get(key);
+
+ /* If entry does not exist, return */
+ if (entry == null)
+ return;
+
+ this.privateRemoveEntry(entry, false);
+ }
+
+ /**
+ * Answers the value in the cache at the given key.
+ * If the value is not in the cache, returns null
+ *
+ * @param key Hash table key of object to retrieve
+ * @return Retreived object, or null if object does not exist
+ */
+ public Object get(Object key) {
+
+ LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get(key);
+ if (entry == null) {
+ return null;
+ }
+
+ this.updateTimestamp(entry);
+ return entry._fValue;
+ }
+
+ /**
+ * Returns the amount of space that is current used in the cache.
+ */
+ public int getCurrentSpace() {
+ return fCurrentSpace;
+ }
+
+ /**
+ * Returns the maximum amount of space available in the cache.
+ */
+ public int getSpaceLimit() {
+ return fSpaceLimit;
+ }
+
+ /**
+ * Returns an Enumeration of the keys currently in the cache.
+ */
+ public Enumeration keys() {
+
+ return fEntryTable.keys();
+ }
+
+ /**
+ * Returns an enumeration that iterates over all the keys and values
+ * currently in the cache.
+ */
+ public ICacheEnumeration keysAndValues() {
+ return new ICacheEnumeration() {
+
+ Enumeration fValues = fEntryTable.elements();
+ LRUCacheEntry fEntry;
+
+ public boolean hasMoreElements() {
+ return fValues.hasMoreElements();
+ }
+
+ public Object nextElement() {
+ fEntry = (LRUCacheEntry) fValues.nextElement();
+ return fEntry._fKey;
+ }
+
+ public Object getValue() {
+ if (fEntry == null) {
+ throw new java.util.NoSuchElementException();
+ }
+ return fEntry._fValue;
+ }
+ };
+ }
+
+ /**
+ * Ensures there is the specified amount of free space in the receiver,
+ * by removing old entries if necessary. Returns true if the requested space was
+ * made available, false otherwise.
+ *
+ * @param space Amount of space to free up
+ */
+ protected boolean makeSpace(int space) {
+
+ int limit;
+
+ limit = this.getSpaceLimit();
+
+ /* if space is already available */
+ if (fCurrentSpace + space <= limit) {
+ return true;
+ }
+
+ /* if entry is too big for cache */
+ if (space > limit) {
+ return false;
+ }
+
+ /* Free up space by removing oldest entries */
+ while (fCurrentSpace + space > limit && fEntryQueueTail != null) {
+ this.privateRemoveEntry(fEntryQueueTail, false);
+ }
+ return true;
+ }
+
+ /**
+ * Returns a new LRUCache instance
+ */
+ protected LRUCache newInstance(int size) {
+ return new LRUCache(size);
+ }
+
+ /**
+ * Adds an entry for the given key/value/space.
+ */
+ protected void privateAdd(Object key, Object value, int space) {
+
+ LRUCacheEntry entry;
+
+ entry = new LRUCacheEntry(key, value, space);
+ this.privateAddEntry(entry, false);
+ }
+
+ /**
+ * Adds the given entry from the receiver.
+ * @param shuffle Indicates whether we are just shuffling the queue
+ * (i.e., the entry table is left alone).
+ */
+ protected void privateAddEntry(LRUCacheEntry entry, boolean shuffle) {
+
+ if (!shuffle) {
+ fEntryTable.put(entry._fKey, entry);
+ fCurrentSpace += entry._fSpace;
+ }
+
+ entry._fTimestamp = fTimestampCounter++;
+ entry._fNext = this.fEntryQueue;
+ entry._fPrevious = null;
+
+ if (fEntryQueue == null) {
+ /* this is the first and last entry */
+ fEntryQueueTail = entry;
+ } else {
+ fEntryQueue._fPrevious = entry;
+ }
+
+ fEntryQueue = entry;
+ }
+
+ /**
+ * An entry has been removed from the cache, for example because it has
+ * fallen off the bottom of the LRU queue.
+ * Subclasses could over-ride this to implement a persistent cache below the LRU cache.
+ */
+ protected void privateNotifyDeletionFromCache(LRUCacheEntry entry) {
+ // Default is NOP.
+ }
+
+ /**
+ * Removes the entry from the entry queue.
+ * @param shuffle indicates whether we are just shuffling the queue
+ * (i.e., the entry table is left alone).
+ */
+ protected void privateRemoveEntry(LRUCacheEntry entry, boolean shuffle) {
+
+ LRUCacheEntry previous, next;
+
+ previous = entry._fPrevious;
+ next = entry._fNext;
+
+ if (!shuffle) {
+ fEntryTable.remove(entry._fKey);
+ fCurrentSpace -= entry._fSpace;
+ privateNotifyDeletionFromCache(entry);
+ }
+
+ /* if this was the first entry */
+ if (previous == null) {
+ fEntryQueue = next;
+ } else {
+ previous._fNext = next;
+ }
+
+ /* if this was the last entry */
+ if (next == null) {
+ fEntryQueueTail = previous;
+ } else {
+ next._fPrevious = previous;
+ }
+ }
+
+ /**
+ * Sets the value in the cache at the given key. Returns the value.
+ *
+ * @param key Key of object to add.
+ * @param value Value of object to add.
+ * @return added value.
+ */
+ public Object put(Object key, Object value) {
+
+ int newSpace, oldSpace, newTotal;
+ LRUCacheEntry entry;
+
+ /* Check whether there's an entry in the cache */
+ newSpace = spaceFor(key, value);
+ entry = (LRUCacheEntry) fEntryTable.get(key);
+
+ if (entry != null) {
+
+ /**
+ * Replace the entry in the cache if it would not overflow
+ * the cache. Otherwise flush the entry and re-add it so as
+ * to keep cache within budget
+ */
+ oldSpace = entry._fSpace;
+ newTotal = getCurrentSpace() - oldSpace + newSpace;
+ if (newTotal <= getSpaceLimit()) {
+ updateTimestamp(entry);
+ entry._fValue = value;
+ entry._fSpace = newSpace;
+ this.fCurrentSpace = newTotal;
+ return value;
+ } else {
+ privateRemoveEntry(entry, false);
+ }
+ }
+ if (makeSpace(newSpace)) {
+ privateAdd(key, value, newSpace);
+ }
+ return value;
+ }
+
+ /**
+ * Removes and returns the value in the cache for the given key.
+ * If the key is not in the cache, returns null.
+ *
+ * @param key Key of object to remove from cache.
+ * @return Value removed from cache.
+ */
+ public Object removeKey(Object key) {
+
+ LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get(key);
+ if (entry == null) {
+ return null;
+ }
+ Object value = entry._fValue;
+ this.privateRemoveEntry(entry, false);
+ return value;
+ }
+
+ /**
+ * Sets the maximum amount of space that the cache can store
+ *
+ * @param limit Number of units of cache space
+ */
+ public void setSpaceLimit(int limit) {
+ if (limit < fSpaceLimit) {
+ makeSpace(fSpaceLimit - limit);
+ }
+ fSpaceLimit = limit;
+ }
+
+ /**
+ * Returns the space taken by the given key and value.
+ */
+ protected int spaceFor(Object key, Object value) {
+
+ if (value instanceof ILRUCacheable) {
+ return ((ILRUCacheable) value).getCacheFootprint();
+ } else {
+ return 1;
+ }
+ }
+
+ /**
+ * Returns a String that represents the value of this object. This method
+ * is for debugging purposes only.
+ */
+ public String toString() {
+
+ return "LRUCache " + (getCurrentSpace() * 100.0 / getSpaceLimit()) + "% full";
+ }
+
+ /**
+ * Updates the timestamp for the given entry, ensuring that the queue is
+ * kept in correct order. The entry must exist
+ */
+ protected void updateTimestamp(LRUCacheEntry entry) {
+
+ entry._fTimestamp = fTimestampCounter++;
+ if (fEntryQueue != entry) {
+ this.privateRemoveEntry(entry, true);
+ this.privateAddEntry(entry, true);
+ }
+ return;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/MemoryCheckThread.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/MemoryCheckThread.java
new file mode 100644
index 0000000000..b3859153a5
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/MemoryCheckThread.java
@@ -0,0 +1,44 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+public class MemoryCheckThread extends Thread {
+ Runtime rt = Runtime.getRuntime();
+ int timeToSleep;
+ /**
+ * MemoryCheckThread constructor comment.
+ */
+ public MemoryCheckThread() {
+ super();
+ setDaemon(true);
+ setPriority(Thread.MAX_PRIORITY);
+ }
+
+ /**
+ * MemoryCheckThread constructor comment.
+ */
+ public MemoryCheckThread(int time) {
+ super();
+ timeToSleep = time;
+ setDaemon(true);
+ setPriority(Thread.MAX_PRIORITY);
+ }
+
+ public long evaluateMemory() {
+ return rt.totalMemory() - rt.freeMemory();
+ }
+
+ /**
+ * Insert the method's description here.
+ * Creation date: (6/27/00 9:14:35 AM)
+ */
+ public void run() {
+ while (true) {
+ try {
+ sleep(timeToSleep);
+ } catch (Exception e) {
+ }
+ System.gc();
+ System.out.println(evaluateMemory());
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/MergeFactory.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/MergeFactory.java
new file mode 100644
index 0000000000..952b0ef428
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/MergeFactory.java
@@ -0,0 +1,236 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.*;
+import java.io.*;
+
+/**
+ * A mergeFactory is used to merge 2 indexes into one. One of the indexes
+ * (oldIndex) is on the disk and the other(addsIndex) is in memory.
+ * The merge respects the following rules: <br>
+ * - The files are sorted in alphabetical order;<br>
+ * - if a file is in oldIndex and addsIndex, the one which is added
+ * is the one in the addsIndex.<br>
+ */
+public class MergeFactory {
+ /**
+ * Input on the addsIndex.
+ */
+ protected IndexInput addsInput;
+
+ /**
+ * Input on the oldIndex.
+ */
+ protected IndexInput oldInput;
+
+ /**
+ * Output to write the result of the merge in.
+ */
+ protected BlocksIndexOutput mergeOutput;
+
+ /**
+ * Files removed from oldIndex.
+ */
+ protected Hashtable removedInOld;
+
+ /**
+ * Files removed from addsIndex.
+ */
+ protected Hashtable removedInAdds;
+ protected int[] mappingOld;
+ protected int[] mappingAdds;
+ public static final int ADDS_INDEX = 0;
+ public static final int OLD_INDEX = 1;
+ /**
+ * MergeFactory constructor comment.
+ * @param directory java.io.File
+ */
+ public MergeFactory(
+ IndexInput oldIndexInput,
+ IndexInput addsIndexInput,
+ BlocksIndexOutput mergeIndexOutput,
+ Hashtable removedInOld,
+ Hashtable removedInAdds) {
+ oldInput = oldIndexInput;
+ addsInput = addsIndexInput;
+ mergeOutput = mergeIndexOutput;
+ this.removedInOld = removedInOld;
+ this.removedInAdds = removedInAdds;
+ }
+
+ /**
+ * Initialise the merge.
+ */
+ protected void init() {
+ mappingOld = new int[oldInput.getNumFiles() + 1];
+ mappingAdds = new int[addsInput.getNumFiles() + 1];
+
+ }
+
+ /**
+ * Merges the 2 indexes into a new one on the disk.
+ */
+ public void merge() throws IOException {
+ //init
+ addsInput.open();
+ oldInput.open();
+ mergeOutput.open();
+ init();
+ //merge
+ //findChanges();
+ mergeFiles();
+ mergeReferences();
+ mergeOutput.flush();
+ //closes everything
+ oldInput.close();
+ addsInput.close();
+ mergeOutput.close();
+ }
+
+ /**
+ * Merges the files of the 2 indexes in the new index, removes the files
+ * to be removed, and records the changes made to propagate them to the
+ * word references.
+ */
+
+ protected void mergeFiles() throws IOException {
+ int positionInMerge = 1;
+ int compare;
+ while (oldInput.hasMoreFiles() || addsInput.hasMoreFiles()) {
+ IndexedFile file1 = oldInput.getCurrentFile();
+ IndexedFile file2 = addsInput.getCurrentFile();
+
+ //if the file has been removed we don't take it into account
+ while (file1 != null && wasRemoved(file1, OLD_INDEX)) {
+ oldInput.moveToNextFile();
+ file1 = oldInput.getCurrentFile();
+ }
+ while (file2 != null && wasRemoved(file2, ADDS_INDEX)) {
+ addsInput.moveToNextFile();
+ file2 = addsInput.getCurrentFile();
+ }
+
+ //the addsIndex was empty, we just removed files from the oldIndex
+ if (file1 == null && file2 == null)
+ break;
+
+ //test if we reached the end of one the 2 index
+ if (file1 == null)
+ compare = 1;
+ else
+ if (file2 == null)
+ compare = -1;
+ else
+ compare = file1.getPath().compareTo(file2.getPath());
+
+ //records the changes to Make
+ if (compare == 0) {
+ //the file has been modified:
+ //we remove it from the oldIndex and add it to the addsIndex
+ removeFile(file1, OLD_INDEX);
+ mappingAdds[file2.getFileNumber()] = positionInMerge;
+ file1.setFileNumber(positionInMerge);
+ mergeOutput.addFile(file1);
+ oldInput.moveToNextFile();
+ addsInput.moveToNextFile();
+ } else
+ if (compare < 0) {
+ mappingOld[file1.getFileNumber()] = positionInMerge;
+ file1.setFileNumber(positionInMerge);
+ mergeOutput.addFile(file1);
+ oldInput.moveToNextFile();
+ } else {
+ mappingAdds[file2.getFileNumber()] = positionInMerge;
+ file2.setFileNumber(positionInMerge);
+ mergeOutput.addFile(file2);
+ addsInput.moveToNextFile();
+ }
+ positionInMerge++;
+ }
+ mergeOutput.flushFiles();
+ }
+
+ /**
+ * Merges the files of the 2 indexes in the new index, according to the changes
+ * recorded during mergeFiles().
+ */
+ protected void mergeReferences() throws IOException {
+ int compare;
+ while (oldInput.hasMoreWords() || addsInput.hasMoreWords()) {
+ WordEntry word1 = oldInput.getCurrentWordEntry();
+ WordEntry word2 = addsInput.getCurrentWordEntry();
+
+ if (word1 == null && word2 == null)
+ break;
+
+ if (word1 == null)
+ compare = 1;
+ else
+ if (word2 == null)
+ compare = -1;
+ else
+ compare = Util.compare(word1.getWord(), word2.getWord());
+ if (compare < 0) {
+ word1.mapRefs(mappingOld);
+ mergeOutput.addWord(word1);
+ oldInput.moveToNextWordEntry();
+ } else
+ if (compare > 0) {
+ word2.mapRefs(mappingAdds);
+ mergeOutput.addWord(word2);
+ addsInput.moveToNextWordEntry();
+ } else {
+ word1.mapRefs(mappingOld);
+ word2.mapRefs(mappingAdds);
+ word1.addRefs(word2.getRefs());
+ mergeOutput.addWord(word1);
+ addsInput.moveToNextWordEntry();
+ oldInput.moveToNextWordEntry();
+ }
+ }
+ mergeOutput.flushWords();
+ }
+
+ /**
+ * Records the deletion of one file.
+ */
+ protected void removeFile(IndexedFile file, int index) {
+ if (index == OLD_INDEX)
+ mappingOld[file.getFileNumber()] = -1;
+ else
+ mappingAdds[file.getFileNumber()] = -1;
+ }
+
+ /**
+ * Returns whether the given file has to be removed from the given index
+ * (ADDS_INDEX or OLD_INDEX). If it has to be removed, the mergeFactory
+ * deletes it and records the changes.
+ */
+
+ protected boolean wasRemoved(IndexedFile indexedFile, int index) {
+ String path = indexedFile.getPath();
+ if (index == OLD_INDEX) {
+ if (removedInOld.remove(path) != null) {
+ mappingOld[indexedFile.getFileNumber()] = -1;
+ return true;
+ }
+ } else
+ if (index == ADDS_INDEX) {
+ Int lastRemoved = (Int) removedInAdds.get(path);
+ if (lastRemoved != null) {
+ int fileNum = indexedFile.getFileNumber();
+ if (lastRemoved.value >= fileNum) {
+ mappingAdds[fileNum] = -1;
+ //if (lastRemoved.value == fileNum) // ONLY if files in sorted order for names AND fileNums
+ //removedInAdds.remove(path);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/ObjectVector.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/ObjectVector.java
new file mode 100644
index 0000000000..b0dae9422b
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/ObjectVector.java
@@ -0,0 +1,73 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+public final class ObjectVector {
+ static int INITIAL_SIZE = 10;
+
+ public int size;
+ int maxSize;
+ Object[] elements;
+ public ObjectVector() {
+ maxSize = INITIAL_SIZE;
+ size = 0;
+ elements = new Object[maxSize];
+ }
+
+ public void add(Object newElement) {
+ if (size == maxSize) // knows that size starts <= maxSize
+ System.arraycopy(elements, 0, (elements = new Object[maxSize *= 2]), 0, size);
+ elements[size++] = newElement;
+ }
+
+ public void addAll(Object[] newElements) {
+ if (size + newElements.length >= maxSize) {
+ maxSize = size + newElements.length; // assume no more elements will be added
+ System.arraycopy(elements, 0, (elements = new Object[maxSize]), 0, size);
+ }
+ System.arraycopy(newElements, 0, elements, size, newElements.length);
+ size += newElements.length;
+ }
+
+ public boolean contains(Object element) {
+ for (int i = size; --i >= 0;)
+ if (element == elements[i])
+ return true;
+ return false;
+ }
+
+ public Object elementAt(int index) {
+ return elements[index];
+ }
+
+ public Object find(Object element) {
+ for (int i = size; --i >= 0;)
+ if (element == elements[i])
+ return elements[i];
+ return null;
+ }
+
+ public Object remove(Object element) {
+ // assumes only one occurrence of the element exists
+ for (int i = size; --i >= 0;)
+ if (element == elements[i]) {
+ // shift the remaining elements down one spot
+ System.arraycopy(elements, i + 1, elements, i, --size - i);
+ elements[size] = null;
+ return element;
+ }
+ return null;
+ }
+
+ public void removeAll() {
+ for (int i = size; --i >= 0;)
+ elements[i] = null;
+ size = 0;
+ }
+
+ public String toString() {
+ String s = "";
+ for (int i = 0; i < size; i++)
+ s += elements[i].toString() + "\n";
+ return s;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/PropertyDocument.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/PropertyDocument.java
new file mode 100644
index 0000000000..e30612b513
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/PropertyDocument.java
@@ -0,0 +1,44 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.index.*;
+import java.util.*;
+
+/**
+ * The properties of a document are stored into a hashtable.
+ * @see IDocument
+ */
+
+public abstract class PropertyDocument implements IDocument {
+ protected Hashtable properties;
+ public PropertyDocument() {
+ properties = new Hashtable(5);
+ }
+
+ /**
+ * @see IDocument#getProperty
+ */
+ public String getProperty(String property) {
+ return (String) properties.get(property);
+ }
+
+ /**
+ * @see IDocument#getPropertyNames
+ */
+
+ public Enumeration getPropertyNames() {
+ return properties.keys();
+ }
+
+ /**
+ * @see IDocument#setProperty
+ */
+
+ public void setProperty(String property, String value) {
+ properties.put(property, value);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/SafeRandomAccessFile.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/SafeRandomAccessFile.java
new file mode 100644
index 0000000000..637f5f9ac0
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/SafeRandomAccessFile.java
@@ -0,0 +1,28 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+
+/**
+ * A safe subclass of RandomAccessFile, which ensure that it's closed
+ * on finalize.
+ */
+public class SafeRandomAccessFile extends RandomAccessFile {
+ public SafeRandomAccessFile(java.io.File file, String mode)
+ throws java.io.IOException {
+ super(file, mode);
+ }
+
+ public SafeRandomAccessFile(String name, String mode)
+ throws java.io.IOException {
+ super(name, mode);
+ }
+
+ protected void finalize() throws IOException {
+ close();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/SimpleIndexBlock.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/SimpleIndexBlock.java
new file mode 100644
index 0000000000..cf36680e89
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/SimpleIndexBlock.java
@@ -0,0 +1,121 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.util.*;
+
+import java.io.*;
+
+/**
+ * Does no compression of words, and uses 4-byte ints for file numbers and number of files.
+ */
+public class SimpleIndexBlock extends IndexBlock {
+ protected int offset = 0;
+
+ public SimpleIndexBlock(int blockSize) {
+ super(blockSize);
+ }
+
+ /**
+ * @see IndexBlock#addEntry
+ */
+ public boolean addEntry(WordEntry entry) {
+ char[] word = entry.getWord();
+ int n = entry.getNumRefs();
+ int sizeEstimate = 2 + word.length * 3 + 4 + n * 4;
+ int offset = this.offset;
+ if (offset + sizeEstimate > this.blockSize - 2)
+ return false;
+ offset += field.putUTF(offset, word);
+ field.putInt4(offset, n);
+ offset += 4;
+ for (int i = 0; i < n; ++i) {
+ field.putInt4(offset, entry.getRef(i));
+ offset += 4;
+ }
+ this.offset = offset;
+ return true;
+ }
+
+ public WordEntry findEntry(char[] word) {
+ try {
+ int offset = 0;
+ int byteLen;
+ while ((byteLen = field.getUInt2(offset)) != 0) {
+ char[] tempWord = field.getUTF(offset);
+ offset += byteLen + 2;
+ if (CharOperation.equals(tempWord, word)) {
+ WordEntry entry = new WordEntry(word);
+ int n = field.getInt4(offset);
+ offset += 4;
+ for (int i = 0; i < n; ++i) {
+ int ref = field.getInt4(offset);
+ offset += 4;
+ entry.addRef(ref);
+ }
+ return entry;
+ } else {
+ int n = field.getInt4(offset);
+ offset += 4 + 4 * n;
+ }
+ }
+ return null;
+ } catch (UTFDataFormatException e) {
+ return null;
+ }
+ }
+
+ /**
+ * @see IndexBlock#flush
+ */
+ public void flush() {
+ if (offset > 0) {
+ field.putInt2(offset, 0);
+ offset = 0;
+ }
+ }
+
+ /**
+ * @see IndexBlock#isEmpty
+ */
+ public boolean isEmpty() {
+ return offset == 0;
+ }
+
+ /**
+ * @see IndexBlock#nextEntry
+ */
+ public boolean nextEntry(WordEntry entry) {
+ try {
+ int offset = this.offset;
+ int byteLen = field.getUInt2(offset);
+ if (byteLen == 0)
+ return false;
+ char[] word = field.getUTF(offset);
+ offset += byteLen + 2;
+ entry.reset(word);
+ int n = field.getInt4(offset);
+ offset += 4;
+ for (int i = 0; i < n; ++i) {
+ int ref = field.getInt4(offset);
+ offset += 4;
+ entry.addRef(ref);
+ }
+ this.offset = offset;
+ return true;
+ } catch (UTFDataFormatException e) {
+ return false;
+ }
+ }
+
+ /**
+ * @see IndexBlock#reset
+ */
+ public void reset() {
+ super.reset();
+ this.offset = 0;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/SimpleIndexInput.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/SimpleIndexInput.java
new file mode 100644
index 0000000000..ceab155488
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/SimpleIndexInput.java
@@ -0,0 +1,197 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.IOException;
+import org.eclipse.jdt.internal.core.index.*;
+import java.util.Vector;
+
+/**
+ * A simpleIndexInput is an input on an in memory Index.
+ */
+
+public class SimpleIndexInput extends IndexInput {
+ protected char[][] sortedWords;
+ protected IndexedFile currentFile;
+ protected IndexedFile[] sortedFiles;
+ protected InMemoryIndex index;
+
+ public SimpleIndexInput(InMemoryIndex index) {
+ super();
+ this.index = index;
+ }
+
+ /**
+ * @see IndexInput#clearCache
+ */
+ public void clearCache() {
+ }
+
+ /**
+ * @see IndexInput#close
+ */
+ public void close() throws IOException {
+ sortedFiles = null;
+ }
+
+ /**
+ * @see IndexInput#getCurrentFile
+ */
+ public IndexedFile getCurrentFile() throws IOException {
+ if (!hasMoreFiles())
+ return null;
+ return currentFile;
+ }
+
+ /**
+ * @see IndexInput#getIndexedFile
+ */
+ public IndexedFile getIndexedFile(int fileNum) throws IOException {
+ for (int i = 0; i < sortedFiles.length; i++)
+ if (sortedFiles[i].getFileNumber() == fileNum)
+ return sortedFiles[i];
+ return null;
+ }
+
+ /**
+ * @see IndexInput#getIndexedFile
+ */
+ public IndexedFile getIndexedFile(IDocument document) throws IOException {
+ for (int i = index.getNumFiles(); i >= 1; i--) {
+ IndexedFile file = getIndexedFile(i);
+ String path = file.getPath();
+ String name = document.getName();
+ if (name.equals(path))
+ return file;
+ }
+ return null;
+ }
+
+ /**
+ * @see IndexInput#getNumFiles
+ */
+ public int getNumFiles() {
+ return index.getNumFiles();
+ }
+
+ /**
+ * @see IndexInput#getNumWords
+ */
+ public int getNumWords() {
+ return sortedWords.length;
+ }
+
+ /**
+ * @see IndexInput#getSource
+ */
+ public Object getSource() {
+ return index;
+ }
+
+ /**
+ * @see IndexInput#init
+ */
+ public void init() {
+ index.init();
+
+ }
+
+ /**
+ * @see IndexInput#moveToNextFile
+ */
+ public void moveToNextFile() throws IOException {
+ filePosition++;
+ if (!hasMoreFiles()) {
+ return;
+ }
+ currentFile = sortedFiles[filePosition - 1];
+ }
+
+ /**
+ * @see IndexInput#moveToNextWordEntry
+ */
+ public void moveToNextWordEntry() throws IOException {
+ wordPosition++;
+ if (!hasMoreWords()) {
+ return;
+ }
+ char[] word = sortedWords[wordPosition - 1];
+ currentWordEntry = (WordEntry) index.words.get(word);
+ }
+
+ /**
+ * @see IndexInput#open
+ */
+ public void open() throws IOException {
+ sortedWords = index.getSortedWords();
+ sortedFiles = index.getSortedFiles();
+ filePosition = 1;
+ wordPosition = 1;
+ setFirstFile();
+ setFirstWord();
+ }
+
+ /**
+ * @see IndexInput#query
+ */
+ public IQueryResult[] query(String word) throws IOException {
+ char[] wordChar = word.toCharArray();
+ WordEntry wordEntry = index.getWordEntry(wordChar);
+ int[] fileNums = wordEntry.getRefs();
+ IQueryResult[] files = new IQueryResult[fileNums.length];
+ for (int i = 0; i < files.length; i++)
+ files[i] = getIndexedFile(fileNums[i]);
+ return files;
+ }
+
+ public IEntryResult[] queryEntriesPrefixedBy(char[] prefix)
+ throws IOException {
+ return null;
+ }
+
+ public IQueryResult[] queryFilesReferringToPrefix(char[] prefix)
+ throws IOException {
+ return null;
+ }
+
+ /**
+ * @see IndexInput#query
+ */
+ public IQueryResult[] queryInDocumentNames(String word) throws IOException {
+ setFirstFile();
+ Vector matches = new Vector();
+ while (hasMoreFiles()) {
+ IndexedFile file = getCurrentFile();
+ if (file.getPath().indexOf(word) != -1)
+ matches.addElement(file.getPath());
+ moveToNextFile();
+ }
+ IQueryResult[] match = new IQueryResult[matches.size()];
+ matches.copyInto(match);
+ return match;
+ }
+
+ /**
+ * @see IndexInput#setFirstFile
+ */
+ protected void setFirstFile() throws IOException {
+ filePosition = 1;
+ if (sortedFiles.length > 0) {
+ currentFile = sortedFiles[0];
+ }
+ }
+
+ /**
+ * @see IndexInput#setFirstWord
+ */
+ protected void setFirstWord() throws IOException {
+ wordPosition = 1;
+ if (sortedWords.length > 0) {
+ char[] word = sortedWords[0];
+ currentWordEntry = (WordEntry) index.words.get(word);
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Util.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Util.java
new file mode 100644
index 0000000000..808972981d
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Util.java
@@ -0,0 +1,433 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.*;
+import java.util.Vector;
+
+public class Util {
+
+ private Util() {
+ }
+
+ /**
+ * Compares two strings lexicographically.
+ * The comparison is based on the Unicode value of each character in
+ * the strings.
+ *
+ * @return the value <code>0</code> if the str1 is equal to str2;
+ * a value less than <code>0</code> if str1
+ * is lexicographically less than str2;
+ * and a value greater than <code>0</code> if str1 is
+ * lexicographically greater than str2.
+ */
+ public static int compare(char[] str1, char[] str2) {
+ int len1 = str1.length;
+ int len2 = str2.length;
+ int n = Math.min(len1, len2);
+ int i = 0;
+ while (n-- != 0) {
+ char c1 = str1[i];
+ char c2 = str2[i++];
+ if (c1 != c2) {
+ return c1 - c2;
+ }
+ }
+ return len1 - len2;
+ }
+
+ public static byte[] getFileByteContent(File file) throws java.io.IOException {
+ int fileLength;
+ byte classFileBytes[] = new byte[fileLength = (int) file.length()];
+ BufferedInputStream stream = null;
+ try {
+ stream = new BufferedInputStream(new FileInputStream(file));
+ int bytesRead = 0;
+ int lastReadSize = 0;
+ while ((lastReadSize != -1) && (bytesRead != fileLength)) {
+ lastReadSize = stream.read(classFileBytes, bytesRead, fileLength - bytesRead);
+ bytesRead += lastReadSize;
+ }
+ } finally {
+ if (stream != null)
+ stream.close();
+ }
+ return classFileBytes;
+ }
+
+ public static char[] getFileCharContent(File file) throws java.io.IOException {
+ byte[] bytes = null;
+ BufferedReader reader = null;
+ char[] contents = null;
+ try {
+ reader = new BufferedReader(new FileReader(file));
+ int length = (int) file.length();
+ contents = new char[length];
+ int len = 0;
+ int readSize = 0;
+ while ((readSize != -1) && (len != length)) {
+ len += readSize;
+ readSize = reader.read(contents, len, length - len);
+ }
+ if (len != length)
+ System.arraycopy(contents, 0, (contents = new char[len]), 0, len);
+ } finally {
+ if (reader != null)
+ reader.close();
+ }
+ return contents;
+ }
+
+ /**
+ * Adds all files with the given suffix in the given directory
+ * and all its subdirectories to the given Vector.
+ */
+ public static void getFiles(File fileOrDir, String[] suffix, Vector v) {
+ if (fileOrDir.isDirectory()) {
+ String[] list = fileOrDir.list();
+ if (list != null) {
+ sort(list);
+ for (int i = 0; i < list.length; ++i) {
+ File file = new File(fileOrDir, list[i]);
+ getFiles(file, suffix, v);
+ }
+ }
+ } else {
+ for (int i = 0; i < suffix.length; i++) {
+ if (fileOrDir.getName().toLowerCase().endsWith(suffix[i])) {
+ v.addElement(fileOrDir);
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds all files with the given suffix in the given directory
+ * and all its subdirectories to the given Vector.
+ */
+ public static void getFiles(File fileOrDir, String suffix, Vector v) {
+ if (fileOrDir.isDirectory()) {
+ String[] list = fileOrDir.list();
+ if (list != null) {
+ sort(list);
+ for (int i = 0; i < list.length; ++i) {
+ File file = new File(fileOrDir, list[i]);
+ getFiles(file, suffix, v);
+ }
+ }
+ } else {
+ if (fileOrDir.getName().toLowerCase().endsWith(suffix)) {
+ v.addElement(fileOrDir);
+ }
+ }
+ }
+
+ /**
+ * Returns the length of the common prefix between s1 and s2.
+ */
+ public static int prefixLength(char[] s1, char[] s2) {
+ int len = 0;
+ int max = Math.min(s1.length, s2.length);
+ for (int i = 0; i < max && s1[i] == s2[i]; ++i)
+ ++len;
+ return len;
+ }
+
+ /**
+ * Returns the length of the common prefix between s1 and s2.
+ */
+ public static int prefixLength(String s1, String s2) {
+ int len = 0;
+ int max = Math.min(s1.length(), s2.length());
+ for (int i = 0; i < max && s1.charAt(i) == s2.charAt(i); ++i)
+ ++len;
+ return len;
+ }
+
+ private static void quickSort(char[][] list, int left, int right) {
+ int original_left = left;
+ int original_right = right;
+ char[] mid = list[(left + right) / 2];
+ do {
+ while (compare(list[left], mid) < 0) {
+ left++;
+ }
+ while (compare(mid, list[right]) < 0) {
+ right--;
+ }
+ if (left <= right) {
+ char[] tmp = list[left];
+ list[left] = list[right];
+ list[right] = tmp;
+ left++;
+ right--;
+ }
+ }
+ while (left <= right);
+ if (original_left < right) {
+ quickSort(list, original_left, right);
+ }
+ if (left < original_right) {
+ quickSort(list, left, original_right);
+ }
+ }
+
+ private static void quickSort(int[] list, int left, int right) {
+ int original_left = left;
+ int original_right = right;
+ int mid = list[(left + right) / 2];
+ do {
+ while (list[left] < mid) {
+ left++;
+ }
+ while (mid < list[right]) {
+ right--;
+ }
+ if (left <= right) {
+ int tmp = list[left];
+ list[left] = list[right];
+ list[right] = tmp;
+ left++;
+ right--;
+ }
+ }
+ while (left <= right);
+ if (original_left < right) {
+ quickSort(list, original_left, right);
+ }
+ if (left < original_right) {
+ quickSort(list, left, original_right);
+ }
+ }
+
+ private static void quickSort(String[] list, int left, int right) {
+
+ int original_left = left;
+ int original_right = right;
+
+ String mid = list[(left + right) / 2];
+ do {
+ while (list[left].compareTo(mid) < 0) {
+ left++;
+ }
+ while (mid.compareTo(list[right]) < 0) {
+ right--;
+ }
+ if (left <= right) {
+ String tmp = list[left];
+ list[left] = list[right];
+ list[right] = tmp;
+ left++;
+ right--;
+ }
+ }
+ while (left <= right);
+
+ if (original_left < right) {
+ quickSort(list, original_left, right);
+ }
+ if (left < original_right) {
+ quickSort(list, left, original_right);
+ }
+ }
+
+ private static void quickSort(IndexedFile[] list, int left, int right) {
+
+ int original_left = left;
+ int original_right = right;
+
+ IndexedFile mid = list[(left + right) / 2];
+ do {
+ while (list[left].getPath().compareTo(mid.getPath()) < 0) {
+ left++;
+ }
+ while (mid.getPath().compareTo(list[right].getPath()) < 0) {
+ right--;
+ }
+ if (left <= right) {
+ IndexedFile tmp = list[left];
+ list[left] = list[right];
+ list[right] = tmp;
+ left++;
+ right--;
+ }
+ }
+ while (left <= right);
+
+ if (original_left < right) {
+ quickSort(list, original_left, right);
+ }
+ if (left < original_right) {
+ quickSort(list, left, original_right);
+ }
+ }
+
+ /**
+ * Reads in a string from the specified data input stream. The
+ * string has been encoded using a modified UTF-8 format.
+ * <p>
+ * The first two bytes are read as if by
+ * <code>readUnsignedShort</code>. This value gives the number of
+ * following bytes that are in the encoded string, not
+ * the length of the resulting string. The following bytes are then
+ * interpreted as bytes encoding characters in the UTF-8 format
+ * and are converted into characters.
+ * <p>
+ * This method blocks until all the bytes are read, the end of the
+ * stream is detected, or an exception is thrown.
+ *
+ * @param in a data input stream.
+ * @return a Unicode string.
+ * @exception EOFException if the input stream reaches the end
+ * before all the bytes.
+ * @exception IOException if an I/O error occurs.
+ * @exception UTFDataFormatException if the bytes do not represent a
+ * valid UTF-8 encoding of a Unicode string.
+ * @see java.io.DataInputStream#readUnsignedShort()
+ */
+ public final static char[] readUTF(DataInput in) throws IOException {
+ int utflen = in.readUnsignedShort();
+ char str[] = new char[utflen];
+ int count = 0;
+ int strlen = 0;
+ while (count < utflen) {
+ int c = in.readUnsignedByte();
+ int char2, char3;
+ switch (c >> 4) {
+ case 0 :
+ case 1 :
+ case 2 :
+ case 3 :
+ case 4 :
+ case 5 :
+ case 6 :
+ case 7 :
+ // 0xxxxxxx
+ count++;
+ str[strlen++] = (char) c;
+ break;
+ case 12 :
+ case 13 :
+ // 110x xxxx 10xx xxxx
+ count += 2;
+ if (count > utflen)
+ throw new UTFDataFormatException();
+ char2 = in.readUnsignedByte();
+ if ((char2 & 0xC0) != 0x80)
+ throw new UTFDataFormatException();
+ str[strlen++] = (char) (((c & 0x1F) << 6) | (char2 & 0x3F));
+ break;
+ case 14 :
+ // 1110 xxxx 10xx xxxx 10xx xxxx
+ count += 3;
+ if (count > utflen)
+ throw new UTFDataFormatException();
+ char2 = in.readUnsignedByte();
+ char3 = in.readUnsignedByte();
+ if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
+ throw new UTFDataFormatException();
+ str[strlen++] =
+ (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
+ break;
+ default :
+ // 10xx xxxx, 1111 xxxx
+ throw new UTFDataFormatException();
+ }
+ }
+ if (strlen < utflen) {
+ System.arraycopy(str, 0, str = new char[strlen], 0, strlen);
+ }
+ return str;
+ }
+
+ public static void sort(char[][] list) {
+ if (list.length > 1)
+ quickSort(list, 0, list.length - 1);
+ }
+
+ public static void sort(int[] list) {
+ if (list.length > 1)
+ quickSort(list, 0, list.length - 1);
+ }
+
+ public static void sort(String[] list) {
+ if (list.length > 1)
+ quickSort(list, 0, list.length - 1);
+ }
+
+ public static void sort(IndexedFile[] list) {
+ if (list.length > 1)
+ quickSort(list, 0, list.length - 1);
+ }
+
+ public static int startsWith(char[] str, char[] prefix) {
+ int len1 = str.length;
+ int len2 = prefix.length;
+ int n = Math.min(len1, len2);
+ int i = 0;
+ while (n-- != 0) {
+ char c1 = str[i];
+ char c2 = prefix[i++];
+ if (c1 != c2) {
+ return c1 - c2;
+ }
+ }
+ if (len2 == i)
+ return 0;
+
+ return 1;
+ }
+
+ /**
+ * Writes a string to the given output stream using UTF-8
+ * encoding in a machine-independent manner.
+ * <p>
+ * First, two bytes are written to the output stream as if by the
+ * <code>writeShort</code> method giving the number of bytes to
+ * follow. This value is the number of bytes actually written out,
+ * not the length of the string. Following the length, each character
+ * of the string is output, in sequence, using the UTF-8 encoding
+ * for the character.
+ *
+ * @param str a string to be written.
+ * @exception IOException if an I/O error occurs.
+ * @since JDK1.0
+ */
+ public static void writeUTF(OutputStream out, char[] str) throws IOException {
+ int strlen = str.length;
+ int utflen = 0;
+ for (int i = 0; i < strlen; i++) {
+ int c = str[i];
+ if ((c >= 0x0001) && (c <= 0x007F)) {
+ utflen++;
+ } else
+ if (c > 0x07FF) {
+ utflen += 3;
+ } else {
+ utflen += 2;
+ }
+ }
+ if (utflen > 65535)
+ throw new UTFDataFormatException();
+ out.write((utflen >>> 8) & 0xFF);
+ out.write((utflen >>> 0) & 0xFF);
+ for (int i = 0; i < strlen; i++) {
+ int c = str[i];
+ if ((c >= 0x0001) && (c <= 0x007F)) {
+ out.write(c);
+ } else
+ if (c > 0x07FF) {
+ out.write(0xE0 | ((c >> 12) & 0x0F));
+ out.write(0x80 | ((c >> 6) & 0x3F));
+ out.write(0x80 | ((c >> 0) & 0x3F));
+ } else {
+ out.write(0xC0 | ((c >> 6) & 0x1F));
+ out.write(0x80 | ((c >> 0) & 0x3F));
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/WordEntry.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/WordEntry.java
new file mode 100644
index 0000000000..53f6cbf62b
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/WordEntry.java
@@ -0,0 +1,164 @@
+package org.eclipse.jdt.internal.core.index.impl;
+
+public class WordEntry {
+ protected char[] fWord;
+ protected int fNumRefs;
+ protected int[] fRefs;
+ public WordEntry() {
+ this(new char[0]);
+ }
+
+ public WordEntry(char[] word) {
+ fWord = word;
+ fNumRefs = 0;
+ fRefs = new int[10];
+ }
+
+ /**
+ * Adds a reference and records the change in footprint.
+ */
+ public int addRef(int fileNum) {
+ if (fNumRefs > 0 && fRefs[fNumRefs - 1] == fileNum) {
+ return 0;
+ }
+ int footprintDelta = 0;
+ if (fRefs.length == 0)
+ fRefs = new int[20];
+ if (fNumRefs == fRefs.length) {
+ footprintDelta = fRefs.length * 4;
+ int[] newRefs = new int[fRefs.length * 2];
+ System.arraycopy(fRefs, 0, newRefs, 0, fRefs.length);
+ fRefs = newRefs;
+ }
+ fRefs[fNumRefs++] = fileNum;
+ return footprintDelta;
+ }
+
+ /**
+ * Adds a set of references and records the change in footprint.
+ */
+ public void addRefs(int[] refs) {
+ int[] newRefs = new int[fNumRefs + refs.length];
+ int pos1 = 0;
+ int pos2 = 0;
+ int posNew = 0;
+ int compare;
+ int r1 = 0;
+ int r2 = 0;
+ while (pos1 < fNumRefs || pos2 < refs.length) {
+ if (pos1 >= fNumRefs) {
+ r2 = refs[pos2];
+ compare = -1;
+ } else
+ if (pos2 >= refs.length) {
+ compare = 1;
+ r1 = fRefs[pos1];
+ } else {
+ r1 = fRefs[pos1];
+ r2 = refs[pos2];
+ compare = r2 - r1;
+ }
+ if (compare > 0) {
+ newRefs[posNew] = r1;
+ posNew++;
+ pos1++;
+ } else {
+ if (r2 != 0) {
+ newRefs[posNew] = r2;
+ posNew++;
+ }
+ pos2++;
+ }
+ }
+ fRefs = newRefs;
+ fNumRefs = posNew;
+ /*for (int i = 0; i < refs.length; i++)
+ addRef(refs[i]);
+ int[] newRefs = new int[fNumRefs];
+ System.arraycopy(fRefs, 0, newRefs, 0, fNumRefs);
+ fRefs = newRefs;
+ Util.sort(fRefs);*/
+ }
+
+ /**
+ * Returns the size of the wordEntry
+ */
+
+ public int footprint() {
+ return 8 + (3 * 4) + (8 + fWord.length * 2) + (8 + fRefs.length * 4);
+ }
+
+ /**
+ * Returns the number of references, e.g. the number of files this word appears in.
+ */
+ public int getNumRefs() {
+ return fNumRefs;
+ }
+
+ /**
+ * returns the file number in the i position in the list of references.
+ */
+ public int getRef(int i) {
+ if (i >= fNumRefs)
+ throw new IndexOutOfBoundsException();
+ return fRefs[i];
+ }
+
+ /**
+ * Returns the references of the wordEntry (the number of the files it appears in).
+ */
+
+ public int[] getRefs() {
+ int[] result = new int[fNumRefs];
+ System.arraycopy(fRefs, 0, result, 0, fNumRefs);
+ return result;
+ }
+
+ /**
+ * returns the word of the wordEntry.
+ */
+
+ public char[] getWord() {
+ return fWord;
+ }
+
+ /**
+ * Changes the references of the wordEntry to match the mapping. For example,<br>
+ * if the current references are [1 3 4]<br>
+ * and mapping is [1 2 3 4 5]<br>
+ * in references 1 becomes mapping[1] = 2, 3->4, and 4->5<br>
+ * => references = [2 4 5].<br>
+ */
+ public void mapRefs(int[] mappings) {
+ int position = 0;
+ for (int i = 0; i < fNumRefs; i++) {
+ int map = mappings[fRefs[i]];
+ if (map != -1 && map != 0) {
+ fRefs[position] = map;
+ position++;
+ }
+ }
+ fNumRefs = position;
+
+ //to be changed!
+ System.arraycopy(fRefs, 0, (fRefs = new int[fNumRefs]), 0, fNumRefs);
+ Util.sort(fRefs);
+ }
+
+ /**
+ * Clears the wordEntry.
+ */
+
+ public void reset(char[] word) {
+ for (int i = fNumRefs; i-- > 0;) {
+ fRefs[i] = 0;
+ }
+ fNumRefs = 0;
+ fWord = word;
+ }
+
+ public String toString() {
+ return new String(fWord);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/AbstractSearchScope.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/AbstractSearchScope.java
new file mode 100644
index 0000000000..5973530a2d
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/AbstractSearchScope.java
@@ -0,0 +1,45 @@
+package org.eclipse.jdt.internal.core.search;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.resources.IResource;
+
+public abstract class AbstractSearchScope {
+
+ protected IResource[] elements = new IResource[5];
+ protected int elementCount = 0;
+ /**
+ * Adds the given resource to this search scope.
+ */
+ public void add(IResource element) {
+ if (this.elementCount == this.elements.length) {
+ System.arraycopy(
+ this.elements,
+ 0,
+ this.elements = new IResource[this.elementCount * 2],
+ 0,
+ this.elementCount);
+ }
+ elements[elementCount++] = element;
+ }
+
+ /**
+ * Returns whether this search scope encloses the given resource.
+ */
+ protected boolean encloses(IResource element) {
+ IPath elementPath = element.getFullPath();
+ for (int i = 0; i < elementCount; i++) {
+ if (this.elements[i].getFullPath().isPrefixOf(elementPath)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/HierarchyScope.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/HierarchyScope.java
new file mode 100644
index 0000000000..e6fd0a670e
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/HierarchyScope.java
@@ -0,0 +1,152 @@
+package org.eclipse.jdt.internal.core.search;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.JarPackageFragmentRoot;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.zip.ZipFile;
+
+/**
+ * Scope limited to the subtype and supertype hierarchy of a given type.
+ */
+public class HierarchyScope
+ extends AbstractSearchScope
+ implements IJavaSearchScope {
+
+ private ITypeHierarchy fHierarchy;
+ private IType[] fTypes;
+ private Hashtable resourcePaths = new Hashtable();
+ private IPath[] enclosingProjectsAndJars;
+
+ /**
+ * Creates a new hiearchy scope for the given type.
+ */
+ public HierarchyScope(IType type) throws JavaModelException {
+ fHierarchy = type.newTypeHierarchy(null);
+ buildResourceVector();
+ }
+
+ private void buildResourceVector() throws JavaModelException {
+ Hashtable resources = new Hashtable();
+ Hashtable paths = new Hashtable();
+ fTypes = fHierarchy.getAllTypes();
+ for (int i = 0; i < fTypes.length; i++) {
+ IType type = fTypes[i];
+ IResource resource = type.getUnderlyingResource();
+ if (resource != null && resources.get(resource) == null) {
+ resources.put(resource, resource);
+ add(resource);
+ }
+ IPackageFragmentRoot root =
+ (IPackageFragmentRoot) type.getPackageFragment().getParent();
+ if (root instanceof JarPackageFragmentRoot) {
+ // type in a jar
+ JarPackageFragmentRoot jar = (JarPackageFragmentRoot) root;
+ String zipFileName;
+ ZipFile zipFile = null;
+ try {
+ zipFile = jar.getJar();
+ zipFileName = zipFile.getName();
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ } finally {
+ if (zipFile != null) {
+ try {
+ zipFile.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+ String resourcePath =
+ zipFileName
+ + JAR_FILE_ENTRY_SEPARATOR
+ + type.getFullyQualifiedName().replace('.', '/')
+ + ".class";
+ this.resourcePaths.put(resourcePath, resourcePath);
+ paths.put(jar.getPath(), type);
+ } else {
+ // type is a project
+ paths.put(type.getJavaProject().getProject().getFullPath(), type);
+ }
+ }
+ this.enclosingProjectsAndJars = new IPath[paths.size()];
+ int i = 0;
+ for (Enumeration e = paths.keys(); e.hasMoreElements();) {
+ this.enclosingProjectsAndJars[i++] = (IPath) e.nextElement();
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see IJavaSearchScope#encloses(String)
+ */
+ public boolean encloses(String resourcePath) {
+ int separatorIndex = resourcePath.indexOf(JAR_FILE_ENTRY_SEPARATOR);
+ if (separatorIndex != -1) {
+ return this.resourcePaths.get(resourcePath) != null;
+ } else {
+ for (int i = 0; i < this.elementCount; i++) {
+ if (resourcePath.startsWith(this.elements[i].getFullPath().toString())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see IJavaSearchScope#encloses(IJavaElement)
+ */
+ public boolean encloses(IJavaElement element) {
+ if (element instanceof IType) {
+ return fHierarchy.contains((IType) element);
+ } else
+ if (element instanceof IMember) {
+ return fHierarchy.contains(((IMember) element).getDeclaringType());
+ }
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see IJavaSearchScope#enclosingProjectsAndJars()
+ */
+ public IPath[] enclosingProjectsAndJars() {
+ return this.enclosingProjectsAndJars;
+ }
+
+ /* (non-Javadoc)
+ * @see IJavaSearchScope#includesBinaries()
+ */
+ public boolean includesBinaries() {
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see IJavaSearchScope#includesClasspaths()
+ */
+ public boolean includesClasspaths() {
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see IJavaSearchScope#setIncludesBinaries(boolean)
+ */
+ public void setIncludesBinaries(boolean includesBinaries) {
+ }
+
+ /* (non-Javadoc)
+ * @see IJavaSearchScope#setIncludesClasspaths(boolean)
+ */
+ public void setIncludesClasspaths(boolean includesClasspaths) {
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IIndexSearchRequestor.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IIndexSearchRequestor.java
new file mode 100644
index 0000000000..6ace6e4520
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IIndexSearchRequestor.java
@@ -0,0 +1,102 @@
+package org.eclipse.jdt.internal.core.search;
+
+public interface IIndexSearchRequestor {
+ /**
+ * Accepts the declaration of a class in the compilation unit with the given resource path.
+ * The class is declared in the given package and with the given type name.
+ * <p>
+ * Note that the resource path can be null if the search query doesn't require it (eg. get all class names).
+ */
+ void acceptClassDeclaration(
+ String resourcePath,
+ char[] simpleTypeName,
+ char[][] enclosingTypeNames,
+ char[] packageName);
+ /**
+ * Accepts the declaration of a constructor in the compilation unit with the given resource path.
+ * The constructor is declared with a given name and number of arguments.
+ */
+ void acceptConstructorDeclaration(
+ String resourcePath,
+ char[] typeName,
+ int parameterCount);
+ /**
+ * Accepts the reference to a constructor in the compilation unit with the given resource path.
+ * The constructor is referenced using the given name and a number of arguments.
+ *
+ * Note that the resource path can be null if the search query doesn't require it.
+ */
+ void acceptConstructorReference(
+ String resourcePath,
+ char[] typeName,
+ int parameterCount);
+ /**
+ * Accepts the declaration of a field in the compilation unit with the given resource path.
+ * <p>
+ * Note that the resource path can be null if the search query doesn't require it (eg. get all class names).
+ * Likewise, the declaring package name and the declaring type names if the query doesn't require them.
+ */
+ void acceptFieldDeclaration(String resourcePath, char[] fieldName);
+ /**
+ * Accepts the reference to a field in the compilation unit with the given resource path.
+ * The field is referenced using the given name
+ */
+ void acceptFieldReference(String resourcePath, char[] fieldName);
+ /**
+ * Accepts the declaration of an interface in the compilation unit with the given resource path.
+ * The interface is declared in the given package and with the given type name.
+ * <p>
+ * Note that the resource path can be null if the search query doesn't require it (eg. get all interface names).
+ */
+ void acceptInterfaceDeclaration(
+ String resourcePath,
+ char[] simpleTypeName,
+ char[][] enclosingTypeNames,
+ char[] packageName);
+ /**
+ * Accepts the declaration of a method in the compilation unit with the given resource path.
+ * The method is declared with a given method name and number of arguments.
+ */
+ void acceptMethodDeclaration(
+ String resourcePath,
+ char[] methodName,
+ int parameterCount);
+ /**
+ * Accepts the reference to a method in the compilation unit with the given resource path.
+ * The method is referenced using the given selector and a number of arguments.
+ *
+ * Note that the resource path can be null if the search query doesn't require it.
+ */
+ void acceptMethodReference(
+ String resourcePath,
+ char[] methodName,
+ int parameterCount);
+ /**
+ * Accepts the reference to a package in the compilation unit with the given resource path.
+ * The package is referenced using the given package name.
+ *
+ * Note that the resource path can be null if the search query doesn't require it.
+ */
+ void acceptPackageReference(String resourcePath, char[] packageName);
+ /**
+ * Accepts the reference to a supertype in the compilation unit with the given resource path.
+ * Note that the resource path and/or the package name can be null.
+ */
+ void acceptSuperTypeReference(
+ String resourcePath,
+ char[] qualification,
+ char[] typeName,
+ char[] enclosingTypeName,
+ char classOrInterface,
+ char[] superQualification,
+ char[] superTypeName,
+ char superClassOrInterface,
+ int modifiers);
+ /**
+ * Accepts the reference to a class in the compilation unit with the given resource path.
+ * The class is referenced using the given type name.
+ * <p>
+ * Note that the resource path can be null if the search query doesn't require it.
+ */
+ void acceptTypeReference(String resourcePath, char[] typeName);
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IInfoConstants.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IInfoConstants.java
new file mode 100644
index 0000000000..ca53e87c1d
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IInfoConstants.java
@@ -0,0 +1,9 @@
+package org.eclipse.jdt.internal.core.search;
+
+public interface IInfoConstants {
+ /* granularity of search results */
+ int NameInfo = 1;
+ int PathInfo = 2;
+ int PositionInfo = 4;
+ int DeclarationInfo = 8;
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSearchAdapter.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSearchAdapter.java
new file mode 100644
index 0000000000..555cc99276
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSearchAdapter.java
@@ -0,0 +1,99 @@
+package org.eclipse.jdt.internal.core.search;
+
+public class IndexSearchAdapter implements IIndexSearchRequestor {
+ /**
+ * @see IIndexSearchRequestor
+ */
+ public void acceptClassDeclaration(
+ String resourcePath,
+ char[] simpleTypeName,
+ char[][] enclosingTypeNames,
+ char[] packageName) {
+ }
+
+ /**
+ * @see IIndexSearchRequestor
+ */
+ public void acceptConstructorDeclaration(
+ String resourcePath,
+ char[] typeName,
+ int parameterCount) {
+ }
+
+ /**
+ * @see IIndexSearchRequestor
+ */
+ public void acceptConstructorReference(
+ String resourcePath,
+ char[] typeName,
+ int parameterCount) {
+ }
+
+ /**
+ * @see IIndexSearchRequestor
+ */
+ public void acceptFieldDeclaration(String resourcePath, char[] fieldName) {
+ }
+
+ /**
+ * @see IIndexSearchRequestor
+ */
+ public void acceptFieldReference(String resourcePath, char[] fieldName) {
+ }
+
+ /**
+ * @see IIndexSearchRequestor
+ */
+ public void acceptInterfaceDeclaration(
+ String resourcePath,
+ char[] simpleTypeName,
+ char[][] enclosingTypeNames,
+ char[] packageName) {
+ }
+
+ /**
+ * @see IIndexSearchRequestor
+ */
+ public void acceptMethodDeclaration(
+ String resourcePath,
+ char[] methodName,
+ int parameterCount) {
+ }
+
+ /**
+ * @see IIndexSearchRequestor
+ */
+ public void acceptMethodReference(
+ String resourcePath,
+ char[] methodName,
+ int parameterCount) {
+ }
+
+ /**
+ * @see IIndexSearchRequestor
+ */
+ public void acceptPackageReference(String resourcePath, char[] packageName) {
+ }
+
+ /**
+ * @see IIndexSearchRequestor
+ */
+ public void acceptSuperTypeReference(
+ String resourcePath,
+ char[] qualification,
+ char[] typeName,
+ char[] enclosingTypeName,
+ char classOrInterface,
+ char[] superQualification,
+ char[] superTypeName,
+ char superClassOrInterface,
+ int modifiers) {
+ }
+
+ /**
+ * @see IIndexSearchRequestor
+ */
+ public void acceptTypeReference(String resourcePath, char[] typeName) {
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSelector.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSelector.java
new file mode 100644
index 0000000000..4546d6ef50
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSelector.java
@@ -0,0 +1,240 @@
+package org.eclipse.jdt.internal.core.search;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.search.indexing.*;
+import org.eclipse.jdt.internal.core.*;
+
+import java.util.*;
+
+/**
+ * Selects the indexes that correspond to projects in a given search scope
+ * and that are dependent on a given focus element.
+ */
+public class IndexSelector {
+ IJavaSearchScope searchScope;
+ IJavaElement focus;
+ IndexManager indexManager;
+
+ IIndex[] indexes;
+ public IndexSelector(
+ IJavaSearchScope searchScope,
+ IJavaElement focus,
+ IndexManager indexManager) {
+
+ this.searchScope = searchScope;
+ this.focus = focus;
+ this.indexManager = indexManager;
+ }
+
+ /**
+ * Returns whether elements of the given project or jar can see the focus element
+ * either because the focus is part of the project or the jar, or because it is
+ * accessible throught the project's classpath
+ */
+ private boolean canSeeFocus(IPath projectOrJarPath) {
+ try {
+ while (!(this.focus instanceof IJavaProject)
+ && !(this.focus instanceof JarPackageFragmentRoot)) {
+ this.focus = this.focus.getParent();
+ }
+ IJavaModel model = this.focus.getJavaModel();
+ IJavaProject project = this.getJavaProject(projectOrJarPath, model);
+ if (this.focus instanceof JarPackageFragmentRoot) {
+ // focus is part of a jar
+ JarPackageFragmentRoot jar = (JarPackageFragmentRoot) this.focus;
+ IPath jarPath = jar.getPath();
+ if (project == null) {
+ // consider that a jar can see another jar only they are both referenced by the same project
+ return this.haveSameParent(projectOrJarPath, jarPath, model);
+ } else {
+ IClasspathEntry[] entries = project.getResolvedClasspath(true);
+ for (int i = 0, length = entries.length; i < length; i++) {
+ IClasspathEntry entry = entries[i];
+ if ((entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY)
+ && entry.getPath().equals(jarPath)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ } else {
+ // focus is part of a project
+ IJavaProject focusProject = (IJavaProject) this.focus;
+ if (project == null) {
+ // consider that a jar can see a project only if it is referenced by this project
+ IClasspathEntry[] entries = focusProject.getResolvedClasspath(true);
+ for (int i = 0, length = entries.length; i < length; i++) {
+ IClasspathEntry entry = entries[i];
+ if ((entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY)
+ && entry.getPath().equals(projectOrJarPath)) {
+ return true;
+ }
+ }
+ return false;
+ } else {
+ if (focusProject.equals(project)) {
+ return true;
+ } else {
+ IPath focusPath = focusProject.getProject().getFullPath();
+ IClasspathEntry[] entries = project.getResolvedClasspath(true);
+ for (int i = 0, length = entries.length; i < length; i++) {
+ IClasspathEntry entry = entries[i];
+ if ((entry.getEntryKind() == IClasspathEntry.CPE_PROJECT)
+ && entry.getPath().equals(focusPath)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+ }
+ } catch (JavaModelException e) {
+ return false;
+ }
+ }
+
+ private void computeIndexes() {
+ Vector indexesInScope = new Vector();
+ IPath[] projectsAndJars = this.searchScope.enclosingProjectsAndJars();
+ IWorkspaceRoot root = this.indexManager.workspace.getRoot();
+ for (int i = 0; i < projectsAndJars.length; i++) {
+ IPath location;
+ IPath path = projectsAndJars[i];
+ if ((!root.getProject(path.lastSegment()).exists())
+ // if project does not exist
+ && path.segmentCount() > 1
+ && ((location = root.getFile(path).getLocation()) == null
+ || !new java.io.File(location.toOSString()).exists())
+ // and internal jar file does not exist
+ && !new java.io.File(path.toOSString()).exists()) {
+ // and external jar file does not exist
+ continue;
+ }
+ if (this.focus == null || this.canSeeFocus(path)) {
+ IIndex index = this.indexManager.getIndex(path);
+ if (indexesInScope.indexOf(index) == -1) {
+ indexesInScope.add(index);
+ }
+ }
+ }
+ this.indexes = new IIndex[indexesInScope.size()];
+ indexesInScope.copyInto(this.indexes);
+ }
+
+ public IIndex[] getIndexes() {
+ if (this.indexes == null) {
+ this.computeIndexes();
+ }
+ return this.indexes;
+ }
+
+ /**
+ * Returns the java project that corresponds to the given path.
+ * Returns null if the path doesn't correspond to a project.
+ */
+ private IJavaProject getJavaProject(IPath path, IJavaModel model) {
+ IJavaProject project = model.getJavaProject(path.lastSegment());
+ if (project.exists()) {
+ return project;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns whether the given jars are referenced in the classpath of the same project.
+ */
+ private boolean haveSameParent(
+ IPath jarPath1,
+ IPath jarPath2,
+ IJavaModel model) {
+ if (jarPath1.equals(jarPath2)) {
+ return true;
+ }
+ try {
+ IJavaProject[] projects = model.getJavaProjects();
+ for (int i = 0, length = projects.length; i < length; i++) {
+ IJavaProject project = projects[i];
+ IClasspathEntry[] entries = project.getResolvedClasspath(true);
+ boolean referencesJar1 = false;
+ boolean referencesJar2 = false;
+ for (int j = 0, length2 = entries.length; j < length2; j++) {
+ IClasspathEntry entry = entries[j];
+ if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
+ IPath entryPath = entry.getPath();
+ if (entryPath.equals(jarPath1)) {
+ referencesJar1 = true;
+ } else
+ if (entryPath.equals(jarPath2)) {
+ referencesJar2 = true;
+ }
+ }
+ }
+ if (referencesJar1 && referencesJar2) {
+ return true;
+ }
+
+ }
+ } catch (JavaModelException e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether elements of the given project can see the focus element
+ * either because the focus is part of the project, or because it is
+ * accesible throught the project's classpath
+ */
+ private boolean projectCanSeeFocusElement(IJavaProject project) {
+ try {
+ while (!(this.focus instanceof IJavaProject)
+ && !(this.focus instanceof JarPackageFragmentRoot)) {
+ this.focus = this.focus.getParent();
+ }
+ if (this.focus instanceof JarPackageFragmentRoot) {
+ // this.focus is part of a jar
+ JarPackageFragmentRoot root = (JarPackageFragmentRoot) this.focus;
+ IPath rootPath = root.getPath();
+ IClasspathEntry[] entries = project.getResolvedClasspath(true);
+ for (int i = 0, length = entries.length; i < length; i++) {
+ IClasspathEntry entry = entries[i];
+ if ((entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY)
+ && entry.getPath().equals(rootPath)) {
+ return true;
+ }
+ }
+ return false;
+ } else {
+ // this.focus is part of a project
+ IJavaProject focusProject = (IJavaProject) this.focus;
+ if (project.equals(focusProject)) {
+ return true;
+ } else {
+ IPath focusPath = focusProject.getProject().getFullPath();
+ IClasspathEntry[] entries = project.getResolvedClasspath(true);
+ for (int i = 0, length = entries.length; i < length; i++) {
+ IClasspathEntry entry = entries[i];
+ if ((entry.getEntryKind() == IClasspathEntry.CPE_PROJECT)
+ && entry.getPath().equals(focusPath)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+ } catch (JavaModelException e) {
+ return false;
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java
new file mode 100644
index 0000000000..477b4dd3cd
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java
@@ -0,0 +1,208 @@
+package org.eclipse.jdt.internal.core.search;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.*;
+import org.eclipse.jdt.internal.core.search.AbstractSearchScope;
+
+import java.util.*;
+
+/**
+ * A Java-specific scope for searching relative to one or more projects.
+ * The scope can be configured to follow the respective classpath of
+ * in-scope projects, and to not search binaries. By default, both classpaths
+ * and binaries are included.
+ */
+public class JavaSearchScope
+ extends AbstractSearchScope
+ implements IJavaSearchScope {
+
+ private boolean includesBinaries = true;
+ private boolean includesClasspaths = true;
+
+ private IResource fLastCheckedResource;
+ private boolean fLastResult;
+
+ /* The paths of the resources in this search scope
+ (or the classpath entries' paths
+ if the resources are projects) */
+ private IPath[] paths = new IPath[1];
+ private int pathsCount = 0;
+ /**
+ * Adds the given resource to this search scope.
+ */
+ public void add(IResource element) {
+ super.add(element);
+
+ // clear indexer cache
+ fLastCheckedResource = null;
+
+ if (element instanceof IProject) {
+ // remember the paths of its classpath entries
+ IJavaModel javaModel = JavaModelManager.getJavaModelManager().getJavaModel();
+ IJavaProject javaProject = javaModel.getJavaProject(element.getName());
+ try {
+ IClasspathEntry[] entries = javaProject.getResolvedClasspath(true);
+ for (int i = 0, length = entries.length; i < length; i++) {
+ IClasspathEntry entry = entries[i];
+ this.add(entry.getPath());
+ }
+ } catch (JavaModelException e) {
+ }
+ } else {
+ this.add(element.getFullPath());
+ }
+ }
+
+ /**
+ * Adds the given path to this search scope.
+ */
+ private void add(IPath path) {
+ if (this.paths.length == this.pathsCount) {
+ System.arraycopy(
+ this.paths,
+ 0,
+ this.paths = new IPath[this.pathsCount * 2],
+ 0,
+ this.pathsCount);
+ }
+ this.paths[this.pathsCount++] = path;
+ }
+
+ /* (non-Javadoc)
+ * @see IJavaSearchScope#encloses(String)
+ */
+ public boolean encloses(String resourcePathString) {
+ int separatorIndex = resourcePathString.indexOf(JAR_FILE_ENTRY_SEPARATOR);
+ if (separatorIndex != -1) {
+ resourcePathString = resourcePathString.substring(0, separatorIndex);
+ }
+ IPath resourcePath = new Path(resourcePathString);
+ for (int i = 0; i < this.pathsCount; i++) {
+ if (this.paths[i].isPrefixOf(resourcePath)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether this search scope encloses the given resource.
+ */
+ protected boolean encloses(IResource element) {
+ boolean encloses = false;
+ IPath elementPath = element.getFullPath();
+ for (int i = 0; i < this.pathsCount; i++) {
+ if (this.paths[i].isPrefixOf(elementPath)) {
+ encloses = true;
+ break;
+ }
+ }
+ fLastCheckedResource = element;
+ fLastResult = encloses;
+ return encloses;
+ }
+
+ /* (non-Javadoc)
+ * @see IJavaSearchScope#encloses(IJavaElement)
+ */
+ public boolean encloses(IJavaElement element) {
+ try {
+ IResource resource = element.getUnderlyingResource();
+ if (resource == null) {
+ // case of a binary in an external jar
+ return true;
+ } else
+ if (resource.equals(fLastCheckedResource)) {
+ return fLastResult;
+ }
+ return encloses(resource);
+ } catch (JavaModelException e) {
+ return false;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see IJavaSearchScope#enclosingProjectsAndJars()
+ */
+ public IPath[] enclosingProjectsAndJars() {
+ try {
+ Vector paths = new Vector();
+ IJavaModel javaModel = JavaModelManager.getJavaModelManager().getJavaModel();
+ IWorkspaceRoot root = javaModel.getWorkspace().getRoot();
+ for (int i = 0; i < this.elementCount; i++) {
+ IResource element = this.elements[i];
+ IPath path = element.getProject().getFullPath();
+ IProject project = element.getProject();
+ if (project.exists() && project.isOpen()) {
+ if (!paths.contains(path))
+ paths.add(path);
+ if (this.includesClasspaths) {
+ IJavaProject javaProject = javaModel.getJavaProject(project.getName());
+ IClasspathEntry[] entries = javaProject.getResolvedClasspath(true);
+ for (int j = 0; j < entries.length; j++) {
+ IClasspathEntry entry = entries[j];
+ switch (entry.getEntryKind()) {
+ case IClasspathEntry.CPE_PROJECT :
+ path = entry.getPath();
+ if (!paths.contains(path)
+ && root.getProject(path.lastSegment()).isAccessible()) {
+ paths.add(path);
+ }
+ break;
+ case IClasspathEntry.CPE_LIBRARY :
+ if (this.includesBinaries) {
+ path = entry.getPath();
+ if (!paths.contains(path))
+ paths.add(path);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ IPath[] result = new IPath[paths.size()];
+ paths.copyInto(result);
+ return result;
+ } catch (JavaModelException e) {
+ return new IPath[0];
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see IJavaSearchScope#includesBinaries()
+ */
+ public boolean includesBinaries() {
+ return this.includesBinaries;
+ }
+
+ /* (non-Javadoc)
+ * @see IJavaSearchScope#includesClasspaths()
+ */
+ public boolean includesClasspaths() {
+ return this.includesClasspaths;
+ }
+
+ /* (non-Javadoc)
+ * @see IJavaSearchScope#setIncludesBinaries
+ */
+ public void setIncludesBinaries(boolean includesBinaries) {
+ this.includesBinaries = includesBinaries;
+ }
+
+ /* (non-Javadoc)
+ * @see IJavaSearchScope#setIncludeClasspaths
+ */
+ public void setIncludesClasspaths(boolean includesClasspaths) {
+ this.includesClasspaths = includesClasspaths;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaWorkspaceScope.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaWorkspaceScope.java
new file mode 100644
index 0000000000..f7cf4eaa20
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaWorkspaceScope.java
@@ -0,0 +1,30 @@
+package org.eclipse.jdt.internal.core.search;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.*;
+
+import java.util.*;
+
+/**
+ * A Java-specific scope for searching the entire workspace.
+ * The scope can be configured to not search binaries. By default, binaries
+ * are included.
+ */
+public class JavaWorkspaceScope extends JavaSearchScope {
+ public JavaWorkspaceScope() {
+ this.setIncludesBinaries(true);
+ IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
+ for (int i = 0, length = projects.length; i < length; i++) {
+ this.add(projects[i]);
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PathCollector.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PathCollector.java
new file mode 100644
index 0000000000..5992a9b207
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PathCollector.java
@@ -0,0 +1,173 @@
+package org.eclipse.jdt.internal.core.search;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+import java.util.*;
+
+/**
+ * Collects the resource paths reported by a client to this search requestor.
+ */
+public class PathCollector implements IIndexSearchRequestor {
+
+ /* a set of resource paths */
+ public Hashtable paths = new Hashtable(5);
+ /**
+ * @see IIndexSearchRequestor
+ */
+ public void acceptClassDeclaration(
+ String resourcePath,
+ char[] simpleTypeName,
+ char[][] enclosingTypeNames,
+ char[] packageName) {
+ this.paths.put(resourcePath, resourcePath);
+ }
+
+ /**
+ * @see IIndexSearchRequestor
+ */
+ public void acceptConstructorDeclaration(
+ String resourcePath,
+ char[] typeName,
+ int parameterCount) {
+
+ this.paths.put(resourcePath, resourcePath);
+ }
+
+ /**
+ * @see IIndexSearchRequestor
+ */
+ public void acceptConstructorReference(
+ String resourcePath,
+ char[] typeName,
+ int parameterCount) {
+
+ this.paths.put(resourcePath, resourcePath);
+ }
+
+ /**
+ * @see IIndexSearchRequestor
+ */
+ public void acceptFieldDeclaration(String resourcePath, char[] fieldName) {
+ this.paths.put(resourcePath, resourcePath);
+ }
+
+ /**
+ * @see IIndexSearchRequestor
+ */
+ public void acceptFieldReference(String resourcePath, char[] fieldName) {
+
+ this.paths.put(resourcePath, resourcePath);
+ }
+
+ /**
+ * @see IIndexSearchRequestor
+ */
+ public void acceptInterfaceDeclaration(
+ String resourcePath,
+ char[] simpleTypeName,
+ char[][] enclosingTypeNames,
+ char[] packageName) {
+
+ this.paths.put(resourcePath, resourcePath);
+ }
+
+ /**
+ * @see IIndexSearchRequestor
+ */
+ public void acceptMethodDeclaration(
+ String resourcePath,
+ char[] methodName,
+ int parameterCount) {
+
+ this.paths.put(resourcePath, resourcePath);
+ }
+
+ /**
+ * @see IIndexSearchRequestor
+ */
+ public void acceptMethodReference(
+ String resourcePath,
+ char[] methodName,
+ int parameterCount) {
+
+ this.paths.put(resourcePath, resourcePath);
+ }
+
+ /**
+ * @see IIndexSearchRequestor
+ */
+ public void acceptPackageReference(String resourcePath, char[] packageName) {
+
+ this.paths.put(resourcePath, resourcePath);
+ }
+
+ /**
+ * @see IIndexSearchRequestor
+ */
+ public void acceptSuperTypeReference(
+ String resourcePath,
+ char[] qualification,
+ char[] typeName,
+ char[] enclosingTypeName,
+ char classOrInterface,
+ char[] superQualification,
+ char[] superTypeName,
+ char superClassOrInterface,
+ int modifiers) {
+ this.paths.put(resourcePath, resourcePath);
+ }
+
+ /**
+ * @see IIndexSearchRequestor
+ */
+ public void acceptSuperTypeReference(
+ String resourcePath,
+ char[] qualification,
+ char[] typeName,
+ char classOrInterface,
+ char[] superQualification,
+ char[] superTypeName,
+ char superClassOrInterface,
+ int modifiers) {
+ this.paths.put(resourcePath, resourcePath);
+ }
+
+ /**
+ * @see IIndexSearchRequestor
+ */
+ public void acceptTypeReference(String resourcePath, char[] typeName) {
+ this.paths.put(resourcePath, resourcePath);
+ }
+
+ /**
+ * Returns the files that correspond to the paths that have been collected.
+ */
+ public IFile[] getFiles(IWorkspace workspace) {
+ IFile[] result = new IFile[this.paths.size()];
+ int i = 0;
+ for (Enumeration enum = this.paths.elements(); enum.hasMoreElements();) {
+ String resourcePath = (String) enum.nextElement();
+ IPath path = new Path(resourcePath);
+ result[i++] = workspace.getRoot().getFile(path);
+ }
+ return result;
+ }
+
+ /**
+ * Returns the paths that have been collected.
+ */
+ public String[] getPaths() {
+ String[] result = new String[this.paths.size()];
+ int i = 0;
+ for (Enumeration enum = this.paths.elements(); enum.hasMoreElements();) {
+ result[i++] = (String) enum.nextElement();
+ }
+ return result;
+ }
+
+}
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
new file mode 100644
index 0000000000..e8f77c488c
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java
@@ -0,0 +1,146 @@
+package org.eclipse.jdt.internal.core.search;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.search.indexing.*;
+import org.eclipse.jdt.internal.core.search.matching.*;
+import org.eclipse.jdt.internal.core.search.processing.*;
+
+import java.io.*;
+
+public class PatternSearchJob implements IJob, IJobConstants {
+
+ protected SearchPattern pattern;
+ protected IJavaSearchScope scope;
+ protected IJavaElement focus;
+ protected IIndexSearchRequestor requestor;
+ protected IProgressMonitor progressMonitor;
+ protected IndexManager indexManager;
+ protected int detailLevel;
+ protected IndexSelector indexSelector;
+
+ protected long executionTime = 0;
+ public PatternSearchJob(
+ SearchPattern pattern,
+ IJavaSearchScope scope,
+ int detailLevel,
+ IIndexSearchRequestor requestor,
+ IndexManager indexManager,
+ IProgressMonitor progressMonitor) {
+
+ this(
+ pattern,
+ scope,
+ null,
+ detailLevel,
+ requestor,
+ indexManager,
+ progressMonitor);
+ }
+
+ public PatternSearchJob(
+ SearchPattern pattern,
+ IJavaSearchScope scope,
+ IJavaElement focus,
+ int detailLevel,
+ IIndexSearchRequestor requestor,
+ IndexManager indexManager,
+ IProgressMonitor progressMonitor) {
+
+ this.pattern = pattern;
+ this.scope = scope;
+ this.focus = focus;
+ this.detailLevel = detailLevel;
+ this.requestor = requestor;
+ this.indexManager = indexManager;
+ this.progressMonitor = progressMonitor;
+ }
+
+ public boolean belongsTo(String jobFamily) {
+ return true;
+ }
+
+ /**
+ * execute method comment.
+ */
+ public boolean execute() {
+
+ if (progressMonitor != null && progressMonitor.isCanceled())
+ throw new OperationCanceledException();
+ boolean isComplete = COMPLETE;
+ executionTime = 0;
+ if (this.indexSelector == null) {
+ this.indexSelector =
+ new IndexSelector(this.scope, this.focus, this.indexManager);
+ }
+ IIndex[] searchIndexes = this.indexSelector.getIndexes();
+ for (int i = 0, max = searchIndexes.length; i < max; i++) {
+ isComplete &= search(searchIndexes[i]);
+ }
+ if (JobManager.VERBOSE) {
+ System.out.println(
+ "-> execution time: " + executionTime + " ms. for : " + this);
+ }
+ return isComplete;
+ }
+
+ /**
+ * execute method comment.
+ */
+ public boolean search(IIndex index) {
+
+ if (progressMonitor != null && progressMonitor.isCanceled())
+ throw new OperationCanceledException();
+
+ if (index == null)
+ return COMPLETE;
+ ReadWriteMonitor monitor = indexManager.getMonitorFor(index);
+ if (monitor == null)
+ return COMPLETE; // index got deleted since acquired
+ try {
+ monitor.enterRead(); // ask permission to read
+
+ /* if index has changed, commit these before querying */
+ if (index.hasChanged()) {
+ try {
+ monitor.exitRead(); // free read lock
+ monitor.enterWrite(); // ask permission to write
+ if (IndexManager.VERBOSE)
+ System.out.println("-> merging index : " + index.getIndexFile());
+ index.save();
+ } catch (IOException e) {
+ return FAILED;
+ } finally {
+ monitor.exitWrite(); // finished writing
+ monitor.enterRead(); // reaquire read permission
+ }
+ }
+ long start = System.currentTimeMillis();
+ pattern.findIndexMatches(
+ index,
+ requestor,
+ detailLevel,
+ progressMonitor,
+ this.scope);
+ executionTime += System.currentTimeMillis() - start;
+ return COMPLETE;
+ } catch (IOException e) {
+ return FAILED;
+ } finally {
+ monitor.exitRead(); // finished reading
+ }
+ }
+
+ public String toString() {
+ return "searching " + pattern.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/SubTypeSearchJob.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/SubTypeSearchJob.java
new file mode 100644
index 0000000000..0add16cda9
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/SubTypeSearchJob.java
@@ -0,0 +1,119 @@
+package org.eclipse.jdt.internal.core.search;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.search.indexing.*;
+import org.eclipse.jdt.internal.core.search.matching.*;
+import org.eclipse.jdt.internal.core.search.processing.*;
+import org.eclipse.jdt.internal.core.index.impl.*;
+
+import java.io.*;
+import java.util.*;
+
+public class SubTypeSearchJob extends PatternSearchJob {
+
+ Hashtable inputs = new Hashtable(5);
+ public SubTypeSearchJob(
+ SearchPattern pattern,
+ IJavaSearchScope scope,
+ int detailLevel,
+ IIndexSearchRequestor requestor,
+ IndexManager indexManager,
+ IProgressMonitor progressMonitor) {
+ super(pattern, scope, detailLevel, requestor, indexManager, progressMonitor);
+ }
+
+ public SubTypeSearchJob(
+ SearchPattern pattern,
+ IJavaSearchScope scope,
+ IJavaElement focus,
+ int detailLevel,
+ IIndexSearchRequestor requestor,
+ org.eclipse.jdt.internal.core.search.indexing.IndexManager indexManager,
+ IProgressMonitor progressMonitor) {
+ super(
+ pattern,
+ scope,
+ focus,
+ detailLevel,
+ requestor,
+ indexManager,
+ progressMonitor);
+ }
+
+ public void closeAll() {
+
+ Enumeration openedInputs = inputs.elements();
+ while (openedInputs.hasMoreElements()) {
+ IndexInput input = (IndexInput) openedInputs.nextElement();
+ try {
+ input.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ /**
+ * execute method comment.
+ */
+ public boolean search(IIndex index) {
+
+ if (progressMonitor != null && progressMonitor.isCanceled())
+ throw new OperationCanceledException();
+
+ if (index == null)
+ return COMPLETE;
+ ReadWriteMonitor monitor = indexManager.getMonitorFor(index);
+ if (monitor == null)
+ return COMPLETE; // index got deleted since acquired
+ try {
+ monitor.enterRead(); // ask permission to read
+
+ /* if index has changed, commit these before querying */
+ if (index.hasChanged()) {
+ try {
+ monitor.exitRead(); // free read lock
+ monitor.enterWrite(); // ask permission to write
+ if (IndexManager.VERBOSE)
+ System.out.println("-> merging index : " + index.getIndexFile());
+ index.save();
+ } catch (IOException e) {
+ return FAILED;
+ } finally {
+ monitor.exitWrite(); // finished writing
+ monitor.enterRead(); // reaquire read permission
+ }
+ }
+ long start = System.currentTimeMillis();
+
+ IndexInput input;
+ if ((input = (IndexInput) inputs.get(index)) == null) {
+ input = new BlocksIndexInput(index.getIndexFile());
+ input.open();
+ inputs.put(index, input);
+ //System.out.println("Acquiring INPUT for "+index);
+ }
+ pattern.findIndexMatches(
+ input,
+ requestor,
+ detailLevel,
+ progressMonitor,
+ this.scope);
+ executionTime += System.currentTimeMillis() - start;
+ return COMPLETE;
+ } catch (IOException e) {
+ return FAILED;
+ } finally {
+ monitor.exitRead(); // finished reading
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AbstractIndexer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AbstractIndexer.java
new file mode 100644
index 0000000000..1bd8cb7f7c
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AbstractIndexer.java
@@ -0,0 +1,766 @@
+package org.eclipse.jdt.internal.core.search.indexing;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.core.search.*;
+
+import org.eclipse.jdt.internal.compiler.util.*;
+
+import java.io.*;
+
+public abstract class AbstractIndexer
+ implements IIndexer, IIndexConstants, IJavaSearchConstants {
+ IIndexerOutput output;
+ /**
+ * AbstractIndexer constructor comment.
+ */
+ public AbstractIndexer() {
+ super();
+ }
+
+ public void addClassDeclaration(
+ int modifiers,
+ char[] packageName,
+ char[] name,
+ char[][] enclosingTypeNames,
+ char[] superclass,
+ char[][] superinterfaces) {
+
+ this.output.addRef(
+ encodeTypeEntry(packageName, enclosingTypeNames, name, true));
+
+ addSuperTypeReference(
+ modifiers,
+ packageName,
+ name,
+ enclosingTypeNames,
+ CLASS_SUFFIX,
+ superclass,
+ CLASS_SUFFIX);
+ if (superinterfaces != null) {
+ for (int i = 0, max = superinterfaces.length; i < max; i++) {
+ addSuperTypeReference(
+ modifiers,
+ packageName,
+ name,
+ enclosingTypeNames,
+ CLASS_SUFFIX,
+ superinterfaces[i],
+ INTERFACE_SUFFIX);
+ }
+ }
+
+ }
+
+ public void addConstructorDeclaration(
+ char[] typeName,
+ char[][] parameterTypes,
+ char[][] exceptionTypes) {
+ // Calculate the number of arguments of the constructor
+ int numberOfArguments = 0;
+ if (parameterTypes != null) {
+ numberOfArguments = parameterTypes.length;
+ for (int i = 0; i < numberOfArguments; i++) {
+ this.addTypeReference(parameterTypes[i]);
+ }
+ }
+ //convert the number of arguments into a char array
+ char[] countChars;
+ if (numberOfArguments < 10) {
+ countChars = COUNTS[numberOfArguments];
+ } else {
+ countChars = String.valueOf(numberOfArguments).toCharArray();
+ }
+ //add the reference
+ this.output.addRef(
+ concat(
+ CONSTRUCTOR_DECL,
+ CharOperation.lastSegment(typeName, '.'),
+ countChars,
+ SEPARATOR));
+
+ if (exceptionTypes != null) {
+ for (int i = 0, max = exceptionTypes.length; i < max; i++) {
+ this.addTypeReference(exceptionTypes[i]);
+ }
+ }
+ }
+
+ public void addConstructorReference(char[] typeName, int argCount) {
+
+ char[] countChars;
+ if (argCount < 10) {
+ countChars = COUNTS[argCount];
+ } else {
+ countChars = String.valueOf(argCount).toCharArray();
+ }
+ this.output.addRef(
+ concat(
+ CONSTRUCTOR_REF,
+ CharOperation.lastSegment(typeName, '.'),
+ countChars,
+ SEPARATOR));
+
+ }
+
+ public void addFieldDeclaration(char[] typeName, char[] fieldName) {
+ this.output.addRef(CharOperation.concat(FIELD_DECL, fieldName));
+ this.addTypeReference(typeName);
+ }
+
+ public void addFieldReference(char[] fieldName) {
+ this.output.addRef(CharOperation.concat(FIELD_REF, fieldName));
+ }
+
+ public void addInterfaceDeclaration(
+ int modifiers,
+ char[] packageName,
+ char[] name,
+ char[][] enclosingTypeNames,
+ char[][] superinterfaces) {
+
+ this.output.addRef(
+ encodeTypeEntry(packageName, enclosingTypeNames, name, false));
+
+ if (superinterfaces != null) {
+ for (int i = 0, max = superinterfaces.length; i < max; i++) {
+ addSuperTypeReference(
+ modifiers,
+ packageName,
+ name,
+ enclosingTypeNames,
+ INTERFACE_SUFFIX,
+ superinterfaces[i],
+ INTERFACE_SUFFIX);
+ }
+ }
+ /* if willing to connect interfaces to Object as a supertype, then uncomment the following
+ else {
+ addSuperTypeReference(modifiers, packageName, name, INTERFACE_SUFFIX, null, CLASS_SUFFIX); // extends Object by default
+ }
+ */
+ }
+
+ public void addMethodDeclaration(
+ char[] methodName,
+ char[][] parameterTypes,
+ char[] returnType,
+ char[][] exceptionTypes) {
+ // Calculate the number of arguments of the method
+ int numberOfArguments = 0;
+ if (parameterTypes != null) {
+ numberOfArguments = parameterTypes.length;
+ for (int i = 0; i < numberOfArguments; i++) {
+ this.addTypeReference(parameterTypes[i]);
+ }
+ }
+ //convert the number of arguments into a char array
+ char[] countChars;
+ if (numberOfArguments < 10) {
+ countChars = COUNTS[numberOfArguments];
+ } else {
+ countChars = String.valueOf(numberOfArguments).toCharArray();
+ }
+ //add the reference
+ this.output.addRef(concat(METHOD_DECL, methodName, countChars, SEPARATOR));
+
+ if (exceptionTypes != null) {
+ for (int i = 0, max = exceptionTypes.length; i < max; i++) {
+ this.addTypeReference(exceptionTypes[i]);
+ }
+ }
+ if (returnType != null)
+ this.addTypeReference(returnType);
+ }
+
+ public void addMethodReference(char[] methodName, int argCount) {
+ char[] countChars;
+ if (argCount < 10) {
+ countChars = COUNTS[argCount];
+ } else {
+ countChars = String.valueOf(argCount).toCharArray();
+ }
+ this.output.addRef(concat(METHOD_REF, methodName, countChars, SEPARATOR));
+
+ }
+
+ public void addNameReference(char[] name) {
+ this.output.addRef(CharOperation.concat(REF, name));
+ }
+
+ private void addSuperTypeReference(
+ int modifiers,
+ char[] packageName,
+ char[] typeName,
+ char[][] enclosingTypeNames,
+ char classOrInterface,
+ char[] superTypeName,
+ char superClassOrInterface) {
+
+ if (superTypeName == null)
+ superTypeName = OBJECT;
+
+ char[] enclosingTypeName = CharOperation.concatWith(enclosingTypeNames, '$');
+ char[] typeSimpleName = CharOperation.lastSegment(typeName, '.');
+ char[] superTypeSimpleName = CharOperation.lastSegment(superTypeName, '.');
+ char[] superQualification;
+ if (superTypeSimpleName == superTypeName) {
+ superQualification = null;
+ } else {
+ int length = superTypeName.length - superTypeSimpleName.length - 1;
+ System.arraycopy(
+ superTypeName,
+ 0,
+ superQualification = new char[length],
+ 0,
+ length);
+ }
+ // if the supertype name contains a $, then split it into: source name and append the $ prefix to the qualification
+ // e.g. p.A$B ---> p.A$ + B
+ char[] superTypeSourceName =
+ CharOperation.lastSegment(superTypeSimpleName, '$');
+ if (superTypeSourceName != superTypeSimpleName) {
+ int start = superQualification == null ? 0 : superQualification.length + 1;
+ int prefixLength = superTypeSimpleName.length - superTypeSourceName.length;
+ char[] mangledQualification = new char[start + prefixLength];
+ if (superQualification != null) {
+ System.arraycopy(superQualification, 0, mangledQualification, 0, start - 1);
+ mangledQualification[start - 1] = '.';
+ }
+ System.arraycopy(
+ superTypeSimpleName,
+ 0,
+ mangledQualification,
+ start,
+ prefixLength);
+ superQualification = mangledQualification;
+ superTypeSimpleName = superTypeSourceName;
+ }
+ this.output.addRef(
+ concat(
+ SUPER_REF,
+ superTypeSimpleName,
+ superQualification,
+ superClassOrInterface,
+ typeSimpleName,
+ enclosingTypeName,
+ packageName,
+ classOrInterface,
+ (char) modifiers,
+ SEPARATOR));
+ }
+
+ public void addTypeReference(char[] typeName) {
+
+ this.output.addRef(
+ CharOperation.concat(TYPE_REF, CharOperation.lastSegment(typeName, '.')));
+ }
+
+ /**
+ * Constructor declaration entries are encoded as follow: 'constructorDecl/' TypeName '/' Arity
+ * e.g. constructorDecl/X/0
+ * constructorDecl/Y/1
+ *
+ */
+ public static final char[] bestConstructorDeclarationPrefix(
+ char[] typeName,
+ int arity,
+ int matchMode,
+ boolean isCaseSensitive) {
+
+ if (!isCaseSensitive || typeName == null)
+ return CONSTRUCTOR_DECL;
+ switch (matchMode) {
+ case EXACT_MATCH :
+ if (arity >= 0) {
+ char[] countChars;
+ if (arity < 10) {
+ countChars = COUNTS[arity];
+ } else {
+ countChars = String.valueOf(arity).toCharArray();
+ }
+ return concat(CONSTRUCTOR_DECL, typeName, countChars, SEPARATOR);
+ }
+ case PREFIX_MATCH :
+ return CharOperation.concat(CONSTRUCTOR_DECL, typeName);
+ case PATTERN_MATCH :
+ int starPos = CharOperation.indexOf('*', typeName);
+ switch (starPos) {
+ case -1 :
+ return CharOperation.concat(CONSTRUCTOR_DECL, typeName);
+ default :
+ int refLength = CONSTRUCTOR_DECL.length;
+ char[] result = new char[refLength + starPos];
+ System.arraycopy(CONSTRUCTOR_DECL, 0, result, 0, refLength);
+ System.arraycopy(typeName, 0, result, refLength, starPos);
+ return result;
+ case 0 : // fall through
+ }
+ default :
+ return CONSTRUCTOR_DECL;
+ }
+ }
+
+ /**
+ * Constructor reference entries are encoded as follow: 'constructorRef/' TypeName '/' Arity
+ * e.g. constructorRef/X/0
+ * constructorRef/Y/1
+ *
+ */
+ public static final char[] bestConstructorReferencePrefix(
+ char[] typeName,
+ int arity,
+ int matchMode,
+ boolean isCaseSensitive) {
+
+ if (!isCaseSensitive || typeName == null)
+ return CONSTRUCTOR_REF;
+ switch (matchMode) {
+ case EXACT_MATCH :
+ if (arity >= 0) {
+ char[] countChars;
+ if (arity < 10) {
+ countChars = COUNTS[arity];
+ } else {
+ countChars = String.valueOf(arity).toCharArray();
+ }
+ return concat(CONSTRUCTOR_REF, typeName, countChars, SEPARATOR);
+ }
+ case PREFIX_MATCH :
+ return CharOperation.concat(CONSTRUCTOR_REF, typeName);
+ case PATTERN_MATCH :
+ int starPos = CharOperation.indexOf('*', typeName);
+ switch (starPos) {
+ case -1 :
+ return CharOperation.concat(CONSTRUCTOR_REF, typeName);
+ default :
+ int refLength = CONSTRUCTOR_REF.length;
+ char[] result = new char[refLength + starPos];
+ System.arraycopy(CONSTRUCTOR_REF, 0, result, 0, refLength);
+ System.arraycopy(typeName, 0, result, refLength, starPos);
+ return result;
+ case 0 : // fall through
+ }
+ default :
+ return CONSTRUCTOR_REF;
+ }
+ }
+
+ /**
+ * Method declaration entries are encoded as follow: 'fieldDecl/' Name
+ * e.g. fieldDecl/x
+ *
+ */
+ public static final char[] bestFieldDeclarationPrefix(
+ char[] name,
+ int matchMode,
+ boolean isCaseSensitive) {
+
+ if (!isCaseSensitive || name == null)
+ return FIELD_DECL;
+ switch (matchMode) {
+ case EXACT_MATCH :
+ case PREFIX_MATCH :
+ return CharOperation.concat(FIELD_DECL, name);
+ case PATTERN_MATCH :
+ int starPos = CharOperation.indexOf('*', name);
+ switch (starPos) {
+ case -1 :
+ return CharOperation.concat(FIELD_DECL, name);
+ default :
+ int refLength = FIELD_DECL.length;
+ char[] result = new char[refLength + starPos];
+ System.arraycopy(FIELD_DECL, 0, result, 0, refLength);
+ System.arraycopy(name, 0, result, refLength, starPos);
+ return result;
+ case 0 : // fall through
+ }
+ default :
+ return FIELD_DECL;
+ }
+ }
+
+ /**
+ * Method declaration entries are encoded as follow: 'methodDecl/' Selector '/' Arity
+ * e.g. methodDecl/clone/0
+ * methodDecl/append/1
+ *
+ */
+ public static final char[] bestMethodDeclarationPrefix(
+ char[] selector,
+ int arity,
+ int matchMode,
+ boolean isCaseSensitive) {
+
+ if (!isCaseSensitive || selector == null)
+ return METHOD_DECL;
+ switch (matchMode) {
+ case EXACT_MATCH :
+ if (arity >= 0) {
+ char[] countChars;
+ if (arity < 10) {
+ countChars = COUNTS[arity];
+ } else {
+ countChars = String.valueOf(arity).toCharArray();
+ }
+ return concat(METHOD_DECL, selector, countChars, SEPARATOR);
+ }
+ case PREFIX_MATCH :
+ return CharOperation.concat(METHOD_DECL, selector);
+ case PATTERN_MATCH :
+ int starPos = CharOperation.indexOf('*', selector);
+ switch (starPos) {
+ case -1 :
+ return CharOperation.concat(METHOD_DECL, selector);
+ default :
+ int refLength = METHOD_DECL.length;
+ char[] result = new char[refLength + starPos];
+ System.arraycopy(METHOD_DECL, 0, result, 0, refLength);
+ System.arraycopy(selector, 0, result, refLength, starPos);
+ return result;
+ case 0 : // fall through
+ }
+ default :
+ return METHOD_DECL;
+ }
+ }
+
+ /**
+ * Method reference entries are encoded as follow: 'methodRef/' Selector '/' Arity
+ * e.g. methodRef/clone/0
+ * methodRef/append/1
+ *
+ */
+ public static final char[] bestMethodReferencePrefix(
+ char[] selector,
+ int arity,
+ int matchMode,
+ boolean isCaseSensitive) {
+
+ if (!isCaseSensitive || selector == null)
+ return METHOD_REF;
+ switch (matchMode) {
+ case EXACT_MATCH :
+ if (arity >= 0) {
+ char[] countChars;
+ if (arity < 10) {
+ countChars = COUNTS[arity];
+ } else {
+ countChars = String.valueOf(arity).toCharArray();
+ }
+ return concat(METHOD_REF, selector, countChars, SEPARATOR);
+ }
+ case PREFIX_MATCH :
+ return CharOperation.concat(METHOD_REF, selector);
+ case PATTERN_MATCH :
+ int starPos = CharOperation.indexOf('*', selector);
+ switch (starPos) {
+ case -1 :
+ return CharOperation.concat(METHOD_REF, selector);
+ default :
+ int refLength = METHOD_REF.length;
+ char[] result = new char[refLength + starPos];
+ System.arraycopy(METHOD_REF, 0, result, 0, refLength);
+ System.arraycopy(selector, 0, result, refLength, starPos);
+ return result;
+ case 0 : // fall through
+ }
+ default :
+ return METHOD_REF;
+ }
+ }
+
+ /**
+ * Type entries are encoded as follow: '<tag>/' Name
+ * e.g. ref/Object
+ * ref/x
+ */
+ public static final char[] bestReferencePrefix(
+ char[] tag,
+ char[] name,
+ int matchMode,
+ boolean isCaseSensitive) {
+
+ if (!isCaseSensitive || name == null)
+ return tag;
+ switch (matchMode) {
+ case EXACT_MATCH :
+ case PREFIX_MATCH :
+ return CharOperation.concat(tag, name);
+ case PATTERN_MATCH :
+ int starPos = CharOperation.indexOf('*', name);
+ switch (starPos) {
+ case -1 :
+ return CharOperation.concat(tag, name);
+ default :
+ int refLength = tag.length;
+ char[] result = new char[refLength + starPos];
+ System.arraycopy(tag, 0, result, 0, refLength);
+ System.arraycopy(name, 0, result, refLength, starPos);
+ return result;
+ case 0 : // fall through
+ }
+ default :
+ return tag;
+ }
+ }
+
+ /**
+ * Type entries are encoded as follow: 'typeDecl/' ('C' | 'I') '/' PackageName '/' TypeName
+ * e.g. typeDecl/C/java.lang/Object
+ * typeDecl/I/java.lang/Cloneable
+ *
+ * Current encoding is optimized for queries: all classes/interfaces
+ */
+ public static final char[] bestTypeDeclarationPrefix(
+ char[] packageName,
+ char[] typeName,
+ char classOrInterface,
+ int matchMode,
+ boolean isCaseSensitive) {
+ // index is case sensitive, thus in case attempting case insensitive search, cannot consider
+ // type name.
+ if (!isCaseSensitive) {
+ packageName = null;
+ typeName = null;
+ }
+ switch (classOrInterface) {
+ default :
+ return TYPE_DECL; // cannot do better given encoding
+ case CLASS_SUFFIX :
+ if (packageName == null)
+ return CLASS_DECL;
+ break;
+ case INTERFACE_SUFFIX :
+ if (packageName == null)
+ return INTERFACE_DECL;
+ break;
+ }
+ switch (matchMode) {
+ case EXACT_MATCH :
+ case PREFIX_MATCH :
+ break;
+ case PATTERN_MATCH :
+ if (typeName != null) {
+ int starPos = CharOperation.indexOf('*', typeName);
+ switch (starPos) {
+ case -1 :
+ break;
+ case 0 :
+ typeName = null;
+ break;
+ default :
+ typeName = CharOperation.subarray(typeName, 0, starPos);
+ }
+ }
+ }
+ int packageLength = packageName.length;
+ int typeLength = typeName == null ? 0 : typeName.length;
+ int pos;
+ char[] result = new char[TYPE_DECL_LENGTH + packageLength + typeLength + 3];
+ System.arraycopy(TYPE_DECL, 0, result, 0, pos = TYPE_DECL_LENGTH);
+ result[pos++] = classOrInterface;
+ result[pos++] = SEPARATOR;
+ System.arraycopy(packageName, 0, result, pos, packageLength);
+ pos += packageLength;
+ result[pos++] = SEPARATOR;
+ if (typeLength > 0) {
+ System.arraycopy(typeName, 0, result, pos, typeName.length);
+ }
+ return result;
+ }
+
+ /**
+ * Concat(first, second, third, fourth, fifth, sep) --> [first][second][sep][third][sep][fourth][sep][fifth]
+ * i.e. no separator is inserted in between first and second
+ */
+ protected static final char[] concat(
+ char[] firstWithSeparator,
+ char[] second,
+ char[] third,
+ char[] fourth,
+ char[] fifth,
+ char separator) {
+ int length1 = firstWithSeparator.length;
+ int length2 = second == null ? 0 : second.length;
+ int length3 = third == null ? 0 : third.length;
+ int length4 = fourth == null ? 0 : fourth.length;
+ int length5 = fifth == null ? 0 : fifth.length;
+ char[] result = new char[length1 + length2 + length3 + length4 + length5 + 3];
+ System.arraycopy(firstWithSeparator, 0, result, 0, length1);
+ if (second != null)
+ System.arraycopy(second, 0, result, length1, length2);
+ int pos = length1 + length2;
+ result[pos] = separator;
+ if (third != null)
+ System.arraycopy(third, 0, result, pos + 1, length3);
+ pos += length3 + 1;
+ result[pos] = separator;
+ if (fourth != null)
+ System.arraycopy(fourth, 0, result, pos + 1, length4);
+ pos += length4 + 1;
+ result[pos] = separator;
+ if (fifth != null)
+ System.arraycopy(fifth, 0, result, pos + 1, length5);
+ return result;
+ }
+
+ /**
+ * Concat(first, second, third, sep) --> [first][second][sep][third]
+ * i.e. no separator is inserted in between first and second
+ */
+ protected static final char[] concat(
+ char[] firstWithSeparator,
+ char[] second,
+ char[] third,
+ char separator) {
+ int length1 = firstWithSeparator.length;
+ int length2 = second == null ? 0 : second.length;
+ int length3 = third == null ? 0 : third.length;
+ char[] result = new char[length1 + length2 + length3 + 1];
+ System.arraycopy(firstWithSeparator, 0, result, 0, length1);
+ if (second != null)
+ System.arraycopy(second, 0, result, length1, length2);
+ result[length1 + length2] = separator;
+ if (third != null)
+ System.arraycopy(third, 0, result, length1 + length2 + 1, length3);
+ return result;
+ }
+
+ /**
+ * Concat(first, second, third, charAfterThird, fourth, fifth, sixth, charAfterSixth, last, sep) --> [first][second][sep][third][sep][charAfterThird][sep][fourth][sep][fifth][sep][sixth][sep][charAfterSixth][last]
+ * i.e. no separator is inserted in between first and second
+ */
+ protected static final char[] concat(
+ char[] firstWithSeparator,
+ char[] second,
+ char[] third,
+ char charAfterThird,
+ char[] fourth,
+ char[] fifth,
+ char[] sixth,
+ char charAfterSixth,
+ char last,
+ char separator) {
+ int length1 = firstWithSeparator.length;
+ int length2 = second == null ? 0 : second.length;
+ int length3 = third == null ? 0 : third.length;
+ int length4 = fourth == null ? 0 : fourth.length;
+ int length5 = fifth == null ? 0 : fifth.length;
+ int length6 = sixth == null ? 0 : sixth.length;
+ char[] result =
+ new char[length1 + length2 + length3 + length4 + length5 + length6 + 9];
+ System.arraycopy(firstWithSeparator, 0, result, 0, length1);
+ if (second != null)
+ System.arraycopy(second, 0, result, length1, length2);
+ int pos = length1 + length2;
+ result[pos] = separator;
+ if (third != null)
+ System.arraycopy(third, 0, result, pos + 1, length3);
+ pos += length3 + 1;
+ result[pos] = separator;
+ result[++pos] = charAfterThird;
+ result[++pos] = separator;
+ if (fourth != null)
+ System.arraycopy(fourth, 0, result, pos + 1, length4);
+ pos += length4 + 1;
+ result[pos] = separator;
+ if (fifth != null)
+ System.arraycopy(fifth, 0, result, pos + 1, length5);
+ pos += length5 + 1;
+ result[pos] = separator;
+ if (sixth != null)
+ System.arraycopy(sixth, 0, result, pos + 1, length6);
+ pos += length6 + 1;
+ result[pos] = separator;
+ result[++pos] = charAfterSixth;
+ result[++pos] = last;
+ return result;
+ }
+
+ /**
+ * Type entries are encoded as follow: 'typeDecl/' ('C' | 'I') '/' PackageName '/' TypeName '/' EnclosingTypeName
+ * e.g. typeDecl/C/java.lang/Object/
+ * typeDecl/I/java.lang/Cloneable/
+ * typeDecl/C/javax.swing/LazyValue/UIDefaults
+ * Current encoding is optimized for queries: all classes/interfaces
+ */
+ protected static final char[] encodeTypeEntry(
+ char[] packageName,
+ char[][] enclosingTypeNames,
+ char[] typeName,
+ boolean isClass) {
+ int packageLength = packageName == null ? 0 : packageName.length;
+ int enclosingTypeNamesLength = 0;
+ if (enclosingTypeNames != null) {
+ for (int i = 0, length = enclosingTypeNames.length; i < length; i++) {
+ enclosingTypeNamesLength += enclosingTypeNames[i].length + 1;
+ }
+ }
+ int pos;
+ char[] result =
+ new char[TYPE_DECL_LENGTH
+ + packageLength
+ + typeName.length
+ + enclosingTypeNamesLength
+ + 4];
+ System.arraycopy(TYPE_DECL, 0, result, 0, pos = TYPE_DECL_LENGTH);
+ result[pos++] = isClass ? CLASS_SUFFIX : INTERFACE_SUFFIX;
+ result[pos++] = SEPARATOR;
+ if (packageName != null) {
+ System.arraycopy(packageName, 0, result, pos, packageLength);
+ pos += packageLength;
+ }
+ result[pos++] = SEPARATOR;
+ System.arraycopy(typeName, 0, result, pos, typeName.length);
+ pos += typeName.length;
+ result[pos++] = SEPARATOR;
+ if (enclosingTypeNames != null) {
+ for (int i = 0, length = enclosingTypeNames.length; i < length; i++) {
+ int enclosingTypeNameLength = enclosingTypeNames[i].length;
+ System.arraycopy(
+ enclosingTypeNames[i],
+ 0,
+ result,
+ pos,
+ enclosingTypeNameLength);
+ pos += enclosingTypeNameLength;
+ result[pos++] = SEPARATOR;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the file types the <code>IIndexer</code> handles.
+ */
+
+ public abstract String[] getFileTypes();
+ /**
+ * @see IIndexer#index
+ */
+ public void index(IDocument document, IIndexerOutput output)
+ throws IOException {
+ this.output = output;
+ if (shouldIndex(document))
+ indexFile(document);
+ }
+
+ protected abstract void indexFile(IDocument document) throws IOException;
+ /**
+ * @see IIndexer#shouldIndex
+ */
+ public boolean shouldIndex(IDocument document) {
+ String type = document.getType();
+ String[] supportedTypes = this.getFileTypes();
+ for (int i = 0; i < supportedTypes.length; ++i) {
+ if (supportedTypes[i].equals(type))
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddClassFileToIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddClassFileToIndex.java
new file mode 100644
index 0000000000..ad21c9cf11
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddClassFileToIndex.java
@@ -0,0 +1,78 @@
+package org.eclipse.jdt.internal.core.search.indexing;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.resources.*;
+
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.internal.core.search.processing.*;
+import org.eclipse.jdt.internal.core.index.impl.*;
+
+import java.io.*;
+
+class AddClassFileToIndex implements IJob, IJobConstants {
+ IFile resource;
+ IndexManager manager;
+ byte[] contents;
+ public AddClassFileToIndex(IFile resource, IndexManager manager) {
+ this.resource = resource;
+ this.manager = manager;
+ }
+
+ public boolean belongsTo(String jobFamily) {
+ return jobFamily.equals(resource.getProject().getName());
+ }
+
+ public boolean execute() {
+ try {
+ IProject project = resource.getProject();
+ IIndex index = manager.getIndex(project.getFullPath());
+ if (!resource.isLocal(IResource.DEPTH_ZERO)) {
+ return FAILED;
+ }
+ /* ensure no concurrent write access to index */
+ if (index == null)
+ return COMPLETE;
+ ReadWriteMonitor monitor = manager.getMonitorFor(index);
+ if (monitor == null)
+ return COMPLETE; // index got deleted since acquired
+ try {
+ monitor.enterWrite(); // ask permission to write
+ byte[] contents = this.getContents();
+ if (contents == null)
+ return FAILED;
+ index.add(new IFileDocument(resource, contents), new BinaryIndexer());
+ } finally {
+ monitor.exitWrite(); // free write lock
+ }
+ } catch (IOException e) {
+ return FAILED;
+ }
+ return COMPLETE;
+ }
+
+ private byte[] getContents() {
+ if (this.contents == null)
+ this.initializeContents();
+ return this.contents;
+ }
+
+ public void initializeContents() {
+ if (!resource.isLocal(IResource.DEPTH_ZERO)) {
+ return;
+ } else {
+ try {
+ this.contents = Util.getFileByteContent(resource.getLocation().toFile());
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ public String toString() {
+ return "indexing " + resource.getName();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddCompilationUnitToIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddCompilationUnitToIndex.java
new file mode 100644
index 0000000000..9814c3261e
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddCompilationUnitToIndex.java
@@ -0,0 +1,79 @@
+package org.eclipse.jdt.internal.core.search.indexing;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.internal.core.search.processing.*;
+import org.eclipse.jdt.internal.core.index.impl.*;
+
+import java.io.*;
+
+class AddCompilationUnitToIndex implements IJob, IJobConstants {
+ IFile resource;
+ IndexManager manager;
+ char[] contents;
+ public AddCompilationUnitToIndex(IFile resource, IndexManager manager) {
+ this.resource = resource;
+ this.manager = manager;
+ }
+
+ public boolean belongsTo(String jobFamily) {
+ return jobFamily.equals(resource.getProject().getName());
+ }
+
+ public boolean execute() {
+ try {
+ IProject project = resource.getProject();
+ IIndex index = manager.getIndex(project.getFullPath());
+ if (!resource.isLocal(IResource.DEPTH_ZERO)) {
+ return FAILED;
+ }
+ /* ensure no concurrent write access to index */
+ if (index == null)
+ return COMPLETE;
+ ReadWriteMonitor monitor = manager.getMonitorFor(index);
+ if (monitor == null)
+ return COMPLETE; // index got deleted since acquired
+ try {
+ monitor.enterWrite(); // ask permission to write
+ char[] contents = this.getContents();
+ if (contents == null)
+ return FAILED;
+ index.add(new IFileDocument(resource, contents), new SourceIndexer());
+ } finally {
+ monitor.exitWrite(); // free write lock
+ }
+ } catch (IOException e) {
+ return FAILED;
+ }
+ return COMPLETE;
+ }
+
+ private char[] getContents() {
+ if (this.contents == null)
+ this.initializeContents();
+ return contents;
+ }
+
+ public void initializeContents() {
+ if (!resource.isLocal(IResource.DEPTH_ZERO)) {
+ return;
+ } else {
+ try {
+ this.contents = Util.getFileCharContent(resource.getLocation().toFile());
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ public String toString() {
+ return "indexing " + resource.getName();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java
new file mode 100644
index 0000000000..caa669cc4b
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java
@@ -0,0 +1,184 @@
+package org.eclipse.jdt.internal.core.search.indexing;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.internal.core.search.processing.*;
+import org.eclipse.jdt.internal.core.*;
+import org.eclipse.jdt.internal.core.index.impl.*;
+
+import java.io.*;
+import java.util.zip.*;
+import java.util.*;
+
+class AddJarFileToIndex implements IJob, IJobConstants {
+ JarPackageFragmentRoot jarRoot;
+ IndexManager manager;
+ String projectName;
+ IFile resource;
+ private String toString;
+ public AddJarFileToIndex(
+ IFile resource,
+ IndexManager manager,
+ String projectName) {
+ this.resource = resource;
+ this.manager = manager;
+ this.projectName = projectName;
+ }
+
+ public AddJarFileToIndex(
+ IPackageFragmentRoot jarRoot,
+ IndexManager manager,
+ String projectName) {
+ this.jarRoot = (JarPackageFragmentRoot) jarRoot;
+ this.manager = manager;
+ this.projectName = projectName;
+ }
+
+ public boolean belongsTo(String jobFamily) {
+ return jobFamily.equals(projectName);
+ }
+
+ public boolean execute() {
+ try {
+ if (this.resource != null) {
+ if (!this.resource.isLocal(IResource.DEPTH_ZERO)) {
+ return FAILED;
+ }
+ }
+ IPath indexedPath =
+ this.jarRoot == null ? this.resource.getFullPath() : this.jarRoot.getPath();
+ // if index already cached, then do not perform any check
+ IIndex index = (IIndex) manager.getIndex(indexedPath, false);
+ if (index != null)
+ return COMPLETE;
+
+ index = manager.getIndex(indexedPath);
+ if (index == null)
+ return COMPLETE;
+ ReadWriteMonitor monitor = manager.getMonitorFor(index);
+ if (monitor == null)
+ return COMPLETE; // index got deleted since acquired
+ ZipFile zip = null;
+ try {
+ // this path will be a relative path to the workspace in case the zipfile in the workspace otherwise it will be a path in the
+ // local file system
+ Path zipFilePath = null;
+
+ monitor.enterWrite(); // ask permission to write
+ if (resource != null) {
+ zip = new ZipFile(this.resource.getLocation().toFile());
+ zipFilePath = (Path) this.resource.getFullPath().makeRelative();
+ // absolute path relative to the workspace
+ } else {
+ zip = new ZipFile(this.jarRoot.getPath().toFile());
+ zipFilePath = (Path) this.jarRoot.getPath();
+ // absolute path relative to the local file system
+ // make it a canonical path to avoid duplicate entries
+ zipFilePath = (Path) JavaProject.canonicalizedPath(zipFilePath);
+ }
+
+ if (JobManager.VERBOSE)
+ System.out.println("INDEX : " + zip.getName());
+ long initialTime = System.currentTimeMillis();
+
+ final Hashtable indexedFileNames = new Hashtable(100);
+ IQueryResult[] results = index.queryInDocumentNames(""); // all file names
+ int resultLength = results == null ? 0 : results.length;
+ if (resultLength != 0) {
+ /* check integrity of the existing index file
+ * if the length is equal to 0, we want to index the whole jar again
+ * If not, then we want to check that there is no missing entry, if
+ * one entry is missing then we
+ */
+ for (int i = 0; i < resultLength; i++) {
+ String fileName = results[i].getPath();
+ indexedFileNames.put(fileName, fileName);
+ }
+ boolean needToReindex = false;
+ for (Enumeration e = zip.entries(); e.hasMoreElements();) {
+ // iterate each entry to index it
+ ZipEntry ze = (ZipEntry) e.nextElement();
+ if (ze.getName().toUpperCase().endsWith(".CLASS")) {
+ JarFileEntryDocument entryDocument =
+ new JarFileEntryDocument(ze, null, zipFilePath);
+ if (indexedFileNames.remove(entryDocument.getName()) == null) {
+ needToReindex = true;
+ break;
+ }
+ }
+ }
+ if (!needToReindex && indexedFileNames.size() == 0) {
+ return COMPLETE;
+ }
+ }
+
+ /*
+ * Index the jar for the first time or reindex the jar in case the previous index file has been corrupted
+ */
+ if (index != null) {
+ // index already existed: recreate it so that we forget about previous entries
+ index = manager.recreateIndex(indexedPath);
+ }
+ for (Enumeration e = zip.entries(); e.hasMoreElements();) {
+ // iterate each entry to index it
+ ZipEntry ze = (ZipEntry) e.nextElement();
+ if (ze.getName().toUpperCase().endsWith(".CLASS")) {
+ InputStream zipInputStream = zip.getInputStream(ze);
+ byte classFileBytes[] = new byte[(int) ze.getSize()];
+ int length = classFileBytes.length;
+ int len = 0;
+ int readSize = 0;
+ while ((readSize != -1) && (len != length)) {
+ readSize = zipInputStream.read(classFileBytes, len, length - len);
+ len += readSize;
+ }
+ zipInputStream.close();
+ // Add the name of the file to the index
+ index.add(
+ new JarFileEntryDocument(ze, classFileBytes, zipFilePath),
+ new BinaryIndexer());
+ }
+ }
+ if (JobManager.VERBOSE)
+ System.out.println(
+ "INDEX : "
+ + zip.getName()
+ + " COMPLETE in "
+ + (System.currentTimeMillis() - initialTime)
+ + " ms");
+ } finally {
+ if (zip != null)
+ zip.close();
+ monitor.exitWrite(); // free write lock
+ }
+ } catch (IOException e) {
+ return FAILED;
+ }
+ return COMPLETE;
+ }
+
+ /**
+ * Insert the method's description here.
+ * Creation date: (10/10/00 1:27:18 PM)
+ * @return java.lang.String
+ */
+ public String toString() {
+ if (toString == null) {
+ if (resource != null) {
+ toString = "indexing " + resource.getLocation().toFile().toString();
+ } else {
+ toString = "indexing " + jarRoot.getPath().toFile().toString();
+ }
+ }
+ return toString;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/BinaryIndexer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/BinaryIndexer.java
new file mode 100644
index 0000000000..a484969f7e
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/BinaryIndexer.java
@@ -0,0 +1,662 @@
+package org.eclipse.jdt.internal.core.search.indexing;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.classfmt.*;
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+import org.eclipse.jdt.internal.core.index.*;
+
+import java.io.*;
+import java.util.*;
+import java.util.zip.*;
+
+public class BinaryIndexer extends AbstractIndexer {
+ public static final String[] FILE_TYPES = new String[] { "class" };
+ private static final char[] BYTE = "byte".toCharArray();
+ private static final char[] CHAR = "char".toCharArray();
+ private static final char[] DOUBLE = "double".toCharArray();
+ private static final char[] FLOAT = "float".toCharArray();
+ private static final char[] INT = "int".toCharArray();
+ private static final char[] LONG = "long".toCharArray();
+ private static final char[] SHORT = "short".toCharArray();
+ private static final char[] BOOLEAN = "boolean".toCharArray();
+ private static final char[] VOID = "void".toCharArray();
+
+ private boolean needReferences;
+
+ private static final boolean DEBUG = false;
+ /**
+ * BinaryIndexer constructor comment.
+ */
+ public BinaryIndexer() {
+ needReferences = false;
+ }
+
+ /**
+ * BinaryIndexer constructor comment.
+ */
+ public BinaryIndexer(boolean retrieveReferences) {
+ needReferences = retrieveReferences;
+ }
+
+ /**
+ * For example:
+ * - int foo(String[]) is ([Ljava/lang/String;)I => java.lang.String[] in a char[][]
+ * - void foo(int) is (I)V ==> int
+ */
+ private void convertToArrayType(
+ char[][] parameterTypes,
+ int counter,
+ int arrayDim) {
+ int length = parameterTypes[counter].length;
+ char[] arrayType = new char[length + arrayDim * 2];
+ System.arraycopy(parameterTypes[counter], 0, arrayType, 0, length);
+ for (int i = 0; i < arrayDim; i++) {
+ arrayType[length + (i * 2)] = '[';
+ arrayType[length + (i * 2) + 1] = ']';
+ }
+ parameterTypes[counter] = arrayType;
+ }
+
+ /**
+ * For example:
+ * - int foo(String[]) is ([Ljava/lang/String;)I => java.lang.String[] in a char[][]
+ * - void foo(int) is (I)V ==> int
+ */
+ private char[] convertToArrayType(char[] typeName, int arrayDim) {
+ int length = typeName.length;
+ char[] arrayType = new char[length + arrayDim * 2];
+ System.arraycopy(typeName, 0, arrayType, 0, length);
+ for (int i = 0; i < arrayDim; i++) {
+ arrayType[length + (i * 2)] = '[';
+ arrayType[length + (i * 2) + 1] = ']';
+ }
+ return arrayType;
+ }
+
+ private char[] decodeFieldType(char[] signature) throws ClassFormatException {
+ if (signature == null)
+ return null;
+ int arrayDim = 0;
+ for (int i = 0, max = signature.length; i < max; i++) {
+ switch (signature[i]) {
+ case 'B' :
+ if (arrayDim > 0) {
+ return convertToArrayType(BYTE, arrayDim);
+ } else {
+ return BYTE;
+ }
+ case 'C' :
+ if (arrayDim > 0) {
+ return convertToArrayType(CHAR, arrayDim);
+ } else {
+ return CHAR;
+ }
+ case 'D' :
+ if (arrayDim > 0) {
+ return convertToArrayType(DOUBLE, arrayDim);
+ } else {
+ return DOUBLE;
+ }
+ case 'F' :
+ if (arrayDim > 0) {
+ return convertToArrayType(FLOAT, arrayDim);
+ } else {
+ return FLOAT;
+ }
+ case 'I' :
+ if (arrayDim > 0) {
+ return convertToArrayType(INT, arrayDim);
+ } else {
+ return INT;
+ }
+ case 'J' :
+ if (arrayDim > 0) {
+ return convertToArrayType(LONG, arrayDim);
+ } else {
+ return LONG;
+ }
+ case 'L' :
+ int indexOfSemiColon = CharOperation.indexOf(';', signature, i + 1);
+ if (indexOfSemiColon == -1)
+ throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
+ if (arrayDim > 0) {
+ return convertToArrayType(
+ replace('/', '.', CharOperation.subarray(signature, i + 1, indexOfSemiColon)),
+ arrayDim);
+ } else {
+ return replace(
+ '/',
+ '.',
+ CharOperation.subarray(signature, i + 1, indexOfSemiColon));
+ }
+ case 'S' :
+ if (arrayDim > 0) {
+ return convertToArrayType(SHORT, arrayDim);
+ } else {
+ return SHORT;
+ }
+ case 'Z' :
+ if (arrayDim > 0) {
+ return convertToArrayType(BOOLEAN, arrayDim);
+ } else {
+ return BOOLEAN;
+ }
+ case 'V' :
+ return VOID;
+ case '[' :
+ arrayDim++;
+ break;
+ default :
+ throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * For example:
+ * - int foo(String[]) is ([Ljava/lang/String;)I => java.lang.String[] in a char[][]
+ * - void foo(int) is (I)V ==> int
+ */
+ private char[][] decodeParameterTypes(char[] signature)
+ throws ClassFormatException {
+ if (signature == null)
+ return null;
+ int indexOfClosingParen = CharOperation.lastIndexOf(')', signature);
+ if (indexOfClosingParen == 1) {
+ // there is no parameter
+ return null;
+ }
+ if (indexOfClosingParen == -1) {
+ throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
+ }
+ char[][] parameterTypes = new char[3][];
+ int parameterTypesCounter = 0;
+ int arrayDim = 0;
+ for (int i = 1; i < indexOfClosingParen; i++) {
+ if (parameterTypesCounter == parameterTypes.length) {
+ // resize
+ System.arraycopy(
+ parameterTypes,
+ 0,
+ (parameterTypes = new char[parameterTypesCounter * 2][]),
+ 0,
+ parameterTypesCounter);
+ }
+ switch (signature[i]) {
+ case 'B' :
+ parameterTypes[parameterTypesCounter++] = BYTE;
+ if (arrayDim > 0) {
+ convertToArrayType(parameterTypes, parameterTypesCounter - 1, arrayDim);
+ }
+ arrayDim = 0;
+ break;
+ case 'C' :
+ parameterTypes[parameterTypesCounter++] = CHAR;
+ if (arrayDim > 0) {
+ convertToArrayType(parameterTypes, parameterTypesCounter - 1, arrayDim);
+ }
+ arrayDim = 0;
+ break;
+ case 'D' :
+ parameterTypes[parameterTypesCounter++] = DOUBLE;
+ if (arrayDim > 0) {
+ convertToArrayType(parameterTypes, parameterTypesCounter - 1, arrayDim);
+ }
+ arrayDim = 0;
+ break;
+ case 'F' :
+ parameterTypes[parameterTypesCounter++] = FLOAT;
+ if (arrayDim > 0) {
+ convertToArrayType(parameterTypes, parameterTypesCounter - 1, arrayDim);
+ }
+ arrayDim = 0;
+ break;
+ case 'I' :
+ parameterTypes[parameterTypesCounter++] = INT;
+ if (arrayDim > 0) {
+ convertToArrayType(parameterTypes, parameterTypesCounter - 1, arrayDim);
+ }
+ arrayDim = 0;
+ break;
+ case 'J' :
+ parameterTypes[parameterTypesCounter++] = LONG;
+ if (arrayDim > 0) {
+ convertToArrayType(parameterTypes, parameterTypesCounter - 1, arrayDim);
+ }
+ arrayDim = 0;
+ break;
+ case 'L' :
+ int indexOfSemiColon = CharOperation.indexOf(';', signature, i + 1);
+ if (indexOfSemiColon == -1)
+ throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
+ parameterTypes[parameterTypesCounter++] =
+ replace('/', '.', CharOperation.subarray(signature, i + 1, indexOfSemiColon));
+ if (arrayDim > 0) {
+ convertToArrayType(parameterTypes, parameterTypesCounter - 1, arrayDim);
+ }
+ i = indexOfSemiColon;
+ arrayDim = 0;
+ break;
+ case 'S' :
+ parameterTypes[parameterTypesCounter++] = SHORT;
+ if (arrayDim > 0) {
+ convertToArrayType(parameterTypes, parameterTypesCounter - 1, arrayDim);
+ }
+ arrayDim = 0;
+ break;
+ case 'Z' :
+ parameterTypes[parameterTypesCounter++] = BOOLEAN;
+ if (arrayDim > 0) {
+ convertToArrayType(parameterTypes, parameterTypesCounter - 1, arrayDim);
+ }
+ arrayDim = 0;
+ break;
+ case '[' :
+ arrayDim++;
+ break;
+ default :
+ throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
+ }
+ }
+ if (parameterTypes.length != parameterTypesCounter) {
+ System.arraycopy(
+ parameterTypes,
+ 0,
+ parameterTypes = new char[parameterTypesCounter][],
+ 0,
+ parameterTypesCounter);
+ }
+ return parameterTypes;
+ }
+
+ private char[] decodeReturnType(char[] signature) throws ClassFormatException {
+ if (signature == null)
+ return null;
+ int indexOfClosingParen = CharOperation.lastIndexOf(')', signature);
+ if (indexOfClosingParen == -1)
+ throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
+ int arrayDim = 0;
+ for (int i = indexOfClosingParen + 1, max = signature.length; i < max; i++) {
+ switch (signature[i]) {
+ case 'B' :
+ if (arrayDim > 0) {
+ return convertToArrayType(BYTE, arrayDim);
+ } else {
+ return BYTE;
+ }
+ case 'C' :
+ if (arrayDim > 0) {
+ return convertToArrayType(CHAR, arrayDim);
+ } else {
+ return CHAR;
+ }
+ case 'D' :
+ if (arrayDim > 0) {
+ return convertToArrayType(DOUBLE, arrayDim);
+ } else {
+ return DOUBLE;
+ }
+ case 'F' :
+ if (arrayDim > 0) {
+ return convertToArrayType(FLOAT, arrayDim);
+ } else {
+ return FLOAT;
+ }
+ case 'I' :
+ if (arrayDim > 0) {
+ return convertToArrayType(INT, arrayDim);
+ } else {
+ return INT;
+ }
+ case 'J' :
+ if (arrayDim > 0) {
+ return convertToArrayType(LONG, arrayDim);
+ } else {
+ return LONG;
+ }
+ case 'L' :
+ int indexOfSemiColon = CharOperation.indexOf(';', signature, i + 1);
+ if (indexOfSemiColon == -1)
+ throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
+ if (arrayDim > 0) {
+ return convertToArrayType(
+ replace('/', '.', CharOperation.subarray(signature, i + 1, indexOfSemiColon)),
+ arrayDim);
+ } else {
+ return replace(
+ '/',
+ '.',
+ CharOperation.subarray(signature, i + 1, indexOfSemiColon));
+ }
+ case 'S' :
+ if (arrayDim > 0) {
+ return convertToArrayType(SHORT, arrayDim);
+ } else {
+ return SHORT;
+ }
+ case 'Z' :
+ if (arrayDim > 0) {
+ return convertToArrayType(BOOLEAN, arrayDim);
+ } else {
+ return BOOLEAN;
+ }
+ case 'V' :
+ return VOID;
+ case '[' :
+ arrayDim++;
+ break;
+ default :
+ throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
+ }
+ }
+ return null;
+ }
+
+ private int extractArgCount(char[] signature) throws ClassFormatException {
+ int indexOfClosingParen = CharOperation.lastIndexOf(')', signature);
+ if (indexOfClosingParen == 1) {
+ // there is no parameter
+ return 0;
+ }
+ if (indexOfClosingParen == -1) {
+ throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
+ }
+ int parameterTypesCounter = 0;
+ for (int i = 1; i < indexOfClosingParen; i++) {
+ switch (signature[i]) {
+ case 'B' :
+ case 'C' :
+ case 'D' :
+ case 'F' :
+ case 'I' :
+ case 'J' :
+ case 'S' :
+ case 'Z' :
+ parameterTypesCounter++;
+ break;
+ case 'L' :
+ int indexOfSemiColon = CharOperation.indexOf(';', signature, i + 1);
+ if (indexOfSemiColon == -1)
+ throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
+ parameterTypesCounter++;
+ i = indexOfSemiColon;
+ break;
+ case '[' :
+ break;
+ default :
+ throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
+ }
+ }
+ return parameterTypesCounter;
+ }
+
+ private final char[] extractClassName(
+ int[] constantPoolOffsets,
+ ClassFileReader reader,
+ int index) {
+ int constantPoolIndex = reader.u2At(constantPoolOffsets[index] + 1);
+ int utf8Offset =
+ constantPoolOffsets[reader.u2At(constantPoolOffsets[constantPoolIndex] + 1)];
+ return reader.utf8At(utf8Offset + 3, reader.u2At(utf8Offset + 1));
+ }
+
+ private final char[] extractName(
+ int[] constantPoolOffsets,
+ ClassFileReader reader,
+ int index) {
+ int constantPoolIndex = reader.u2At(constantPoolOffsets[index] + 3);
+ int utf8Offset =
+ constantPoolOffsets[reader.u2At(constantPoolOffsets[constantPoolIndex] + 1)];
+ return reader.utf8At(utf8Offset + 3, reader.u2At(utf8Offset + 1));
+ }
+
+ /**
+ * Extract all type, method, field and interface method references from the constant pool
+ */
+ private void extractReferenceFromConstantPool(
+ byte[] contents,
+ ClassFileReader reader)
+ throws ClassFormatException {
+ int[] constantPoolOffsets = reader.getConstantPoolOffsets();
+ int constantPoolCount = constantPoolOffsets.length;
+ for (int i = 1; i < constantPoolCount; i++) {
+ int tag = reader.u1At(constantPoolOffsets[i]);
+ /**
+ * u1 tag
+ * u2 class_index
+ * u2 name_and_type_index
+ */
+ char[] className = null;
+ char[] name = null;
+ char[] type = null;
+ switch (tag) {
+ case ClassFileStruct.FieldRefTag :
+ // add reference to the class/interface and field name and type
+ // className = extractClassName(constantPoolOffsets, reader, i);
+ name = extractName(constantPoolOffsets, reader, i);
+ // type = extractType(constantPoolOffsets, reader, i);
+ addFieldReference(name);
+ break;
+ case ClassFileStruct.MethodRefTag :
+ // add reference to the class and method name and type
+ case ClassFileStruct.InterfaceMethodRefTag :
+ // add reference to the interface and method name and type
+ name = extractName(constantPoolOffsets, reader, i);
+ type = extractType(constantPoolOffsets, reader, i);
+ addMethodReference(name, extractArgCount(type));
+ }
+ }
+ }
+
+ private final char[] extractType(
+ int[] constantPoolOffsets,
+ ClassFileReader reader,
+ int index) {
+ int constantPoolIndex = reader.u2At(constantPoolOffsets[index] + 3);
+ int utf8Offset =
+ constantPoolOffsets[reader.u2At(constantPoolOffsets[constantPoolIndex] + 3)];
+ return reader.utf8At(utf8Offset + 3, reader.u2At(utf8Offset + 1));
+ }
+
+ /**
+ * getFileTypes method comment.
+ */
+ public String[] getFileTypes() {
+ return FILE_TYPES;
+ }
+
+ private void indexClassFile(byte[] contents, char[] documentName)
+ throws IOException {
+ try {
+ ClassFileReader reader = new ClassFileReader(contents, documentName);
+ // we don't want to index local and anonymous classes
+ if (reader.isLocal() || reader.isAnonymous())
+ return;
+
+ int[] constantPoolOffsets = reader.getConstantPoolOffsets();
+
+ // first add type references
+ char[] className = replace('/', '.', reader.getName());
+ // looks like java/lang/String
+ // need to extract the package name and the simple name
+ int packageNameIndex = CharOperation.lastIndexOf('.', className);
+ char[] packageName = null;
+ char[] name = null;
+ if (packageNameIndex >= 0) {
+ packageName = CharOperation.subarray(className, 0, packageNameIndex);
+ name =
+ CharOperation.subarray(className, packageNameIndex + 1, className.length);
+ } else {
+ name = className;
+ }
+ char[] enclosingTypeName = null;
+ if (reader.isNestedType()) {
+ name = reader.getInnerSourceName();
+ char[] fullEnclosingName = reader.getEnclosingTypeName();
+ int nameLength = fullEnclosingName.length - packageNameIndex - 1;
+ enclosingTypeName = new char[nameLength];
+ System.arraycopy(
+ fullEnclosingName,
+ packageNameIndex + 1,
+ enclosingTypeName,
+ 0,
+ nameLength);
+ }
+ // eliminate invalid innerclasses (1G4KCF7)
+ if (name == null)
+ return;
+
+ char[][] superinterfaces = replace('/', '.', reader.getInterfaceNames());
+ if (DEBUG) {
+ if (packageName != null) {
+ System.out.println("package name = " + new String(packageName));
+ }
+ if (name != null) {
+ System.out.println("class name = " + new String(name));
+ }
+ if (superinterfaces != null) {
+ for (int i = 0, max = superinterfaces.length; i < max; i++) {
+ System.out.println(
+ "superinterfaces[" + i + "]= " + new String(superinterfaces[i]));
+ }
+ }
+ }
+ char[][] enclosingTypeNames =
+ enclosingTypeName == null ? null : new char[][] { enclosingTypeName };
+ if (reader.isInterface()) {
+ addInterfaceDeclaration(
+ reader.getModifiers(),
+ packageName,
+ name,
+ enclosingTypeNames,
+ superinterfaces);
+ } else {
+ char[] superclass = replace('/', '.', reader.getSuperclassName());
+ if (DEBUG) {
+ if (superclass != null) {
+ System.out.println("superclass name = " + new String(superclass));
+ }
+ }
+ addClassDeclaration(
+ reader.getModifiers(),
+ packageName,
+ name,
+ enclosingTypeNames,
+ superclass,
+ superinterfaces);
+ }
+
+ // first reference all methods declarations and field declarations
+ MethodInfo[] methods = (MethodInfo[]) reader.getMethods();
+ if (methods != null) {
+ for (int i = 0, max = methods.length; i < max; i++) {
+ MethodInfo method = methods[i];
+ char[] descriptor = method.getMethodDescriptor();
+ char[][] parameterTypes = decodeParameterTypes(descriptor);
+ char[] returnType = decodeReturnType(descriptor);
+ char[][] exceptionTypes = replace('/', '.', method.getExceptionTypeNames());
+ if (DEBUG) {
+ if (method.getSelector() != null) {
+ System.out.println("method selector = " + new String(method.getSelector()));
+ }
+ if (parameterTypes != null) {
+ for (int j = 0, max2 = parameterTypes.length; j < max2; j++) {
+ System.out.println(
+ "parameterTypes[" + j + "]= " + new String(parameterTypes[j]));
+ }
+ }
+ if (returnType != null) {
+ System.out.println("return type = " + new String(returnType));
+ }
+ if (exceptionTypes != null) {
+ for (int j = 0, max2 = exceptionTypes.length; j < max2; j++) {
+ System.out.println(
+ "exceptionTypes[" + j + "]= " + new String(exceptionTypes[j]));
+ }
+ }
+ }
+ if (method.isConstructor()) {
+ addConstructorDeclaration(className, parameterTypes, exceptionTypes);
+ } else {
+ if (!method.isClinit()) {
+ addMethodDeclaration(
+ method.getSelector(),
+ parameterTypes,
+ returnType,
+ exceptionTypes);
+ }
+ }
+ }
+ }
+ FieldInfo[] fields = (FieldInfo[]) reader.getFields();
+ if (fields != null) {
+ for (int i = 0, max = fields.length; i < max; i++) {
+ FieldInfo field = fields[i];
+ char[] fieldName = field.getName();
+ char[] fieldType = decodeFieldType(replace('/', '.', field.getTypeName()));
+ if (DEBUG) {
+ if (fieldName != null) {
+ System.out.println("field name = " + new String(fieldName));
+ }
+ if (fieldType != null) {
+ System.out.println("field type = " + new String(fieldType));
+ }
+ }
+ addFieldDeclaration(fieldType, fieldName);
+ }
+ }
+
+ // record all references found inside the .class file
+ if (needReferences) {
+ extractReferenceFromConstantPool(contents, reader);
+ }
+ } catch (ClassFormatException e) {
+ }
+ }
+
+ /**
+ * indexFile method comment.
+ */
+ protected void indexFile(IDocument document) throws IOException {
+ // Add the name of the file to the index
+ output.addDocument(document);
+ indexClassFile(document.getByteContent(), document.getName().toCharArray());
+ }
+
+ /**
+ * Modify the array by replacing all occurences of toBeReplaced with newChar
+ */
+ private char[][] replace(char toBeReplaced, char newChar, char[][] array) {
+ if (array == null)
+ return null;
+ for (int i = 0, max = array.length; i < max; i++) {
+ replace(toBeReplaced, newChar, array[i]);
+ }
+ return array;
+ }
+
+ /**
+ * Modify the array by replacing all occurences of toBeReplaced with newChar
+ */
+ private char[] replace(char toBeReplaced, char newChar, char[] array) {
+ if (array == null)
+ return null;
+ for (int i = 0, max = array.length; i < max; i++) {
+ if (array[i] == toBeReplaced) {
+ array[i] = newChar;
+ }
+ }
+ return array;
+ }
+
+ /**
+ * setFileTypes method comment.
+ */
+ public void setFileTypes(String[] fileTypes) {
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IIndexConstants.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IIndexConstants.java
new file mode 100644
index 0000000000..b7aca5a1d8
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IIndexConstants.java
@@ -0,0 +1,48 @@
+package org.eclipse.jdt.internal.core.search.indexing;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.core.search.processing.*;
+
+public interface IIndexConstants extends IJobConstants {
+
+ /* index encoding */
+ char[] REF = "ref/".toCharArray();
+ char[] FIELD_REF = "fieldRef/".toCharArray();
+ char[] METHOD_REF = "methodRef/".toCharArray();
+ char[] CONSTRUCTOR_REF = "constructorRef/".toCharArray();
+ char[] TYPE_REF = "typeRef/".toCharArray();
+ char[] SUPER_REF = "superRef/".toCharArray();
+ char[] TYPE_DECL = "typeDecl/".toCharArray();
+ int TYPE_DECL_LENGTH = 9;
+ char[] CLASS_DECL = "typeDecl/C/".toCharArray();
+ char[] INTERFACE_DECL = "typeDecl/I/".toCharArray();
+ char[] METHOD_DECL = "methodDecl/".toCharArray();
+ char[] CONSTRUCTOR_DECL = "constructorDecl/".toCharArray();
+ char[] FIELD_DECL = "fieldDecl/".toCharArray();
+ char[] OBJECT = "Object".toCharArray();
+ char[][] COUNTS =
+ new char[][] {
+ new char[] { '0' },
+ new char[] { '1' },
+ new char[] { '2' },
+ new char[] { '3' },
+ new char[] { '4' },
+ new char[] { '5' },
+ new char[] { '6' },
+ new char[] { '7' },
+ new char[] { '8' },
+ new char[] { '9' }
+ };
+
+ char CLASS_SUFFIX = 'C';
+ char INTERFACE_SUFFIX = 'I';
+ char TYPE_SUFFIX = 0;
+ char SEPARATOR = '/';
+
+ char[] ONE_STAR = new char[] { '*' };
+ char[] NO_CHAR = new char[0];
+ char[][] NO_CHAR_CHAR = new char[0][];
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java
new file mode 100644
index 0000000000..5f80fad717
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java
@@ -0,0 +1,123 @@
+package org.eclipse.jdt.internal.core.search.indexing;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.internal.core.search.processing.*;
+import org.eclipse.jdt.internal.core.index.impl.*;
+
+import java.io.*;
+import java.util.*;
+
+public class IndexAllProject implements IJob, IJobConstants {
+ IProject project;
+ IndexManager manager;
+ public IndexAllProject(IProject project, IndexManager manager) {
+ this.project = project;
+ this.manager = manager;
+ }
+
+ public boolean belongsTo(String jobFamily) {
+ return jobFamily.equals(project.getName());
+ }
+
+ /**
+ * Ensure consistency of a project index. Need to walk all nested resources,
+ * and discover resources which have either been changed, added or deleted
+ * since the index was produced.
+ */
+ public boolean execute() {
+
+ if (!project.isOpen())
+ return COMPLETE; // nothing to do
+
+ IIndex index = manager.getIndex(project.getFullPath());
+ if (index == null)
+ return COMPLETE;
+ ReadWriteMonitor monitor = manager.getMonitorFor(index);
+ if (monitor == null)
+ return COMPLETE; // index got deleted since acquired
+ try {
+ monitor.enterRead(); // ask permission to read
+
+ /* if index has changed, commit these before querying */
+ if (index.hasChanged()) {
+ try {
+ monitor.exitRead(); // free read lock
+ monitor.enterWrite(); // ask permission to write
+ if (IndexManager.VERBOSE)
+ System.out.println("-> merging index : " + index.getIndexFile());
+ index.save();
+ } catch (IOException e) {
+ return FAILED;
+ } finally {
+ monitor.exitWrite(); // finished writing
+ monitor.enterRead(); // reacquire read permission
+ }
+ }
+ final String OK = "OK";
+ final String DELETED = "DELETED";
+ final long indexLastModified = index.getIndexFile().lastModified();
+
+ final Hashtable indexedFileNames = new Hashtable(100);
+ IQueryResult[] results = index.queryInDocumentNames(""); // all file names
+ for (int i = 0, max = results == null ? 0 : results.length; i < max; i++) {
+ String fileName = results[i].getPath();
+ indexedFileNames.put(fileName, DELETED);
+ }
+ project.accept(new IResourceVisitor() {
+ public boolean visit(IResource resource) {
+ if (resource.getType() == IResource.FILE) {
+ String extension = resource.getFileExtension();
+ if ((extension != null) && extension.equalsIgnoreCase("java")) {
+ IPath path = resource.getLocation();
+ if (path != null) {
+ File resourceFile = path.toFile();
+ String name = new IFileDocument((IFile) resource).getName();
+ if (indexedFileNames.get(name) == null) {
+ indexedFileNames.put(name, resource);
+ } else {
+ indexedFileNames.put(
+ name,
+ resourceFile.lastModified() > indexLastModified
+ ? (Object) resource
+ : (Object) OK);
+ }
+ }
+ }
+ return false;
+ }
+ return true;
+ }
+ });
+ Enumeration names = indexedFileNames.keys();
+ while (names.hasMoreElements()) {
+ String name = (String) names.nextElement();
+ Object value = indexedFileNames.get(name);
+ if (value instanceof IFile) {
+ manager.add((IFile) value);
+ } else
+ if (value == DELETED) {
+ manager.remove(name, project);
+ }
+ }
+ } catch (CoreException e) {
+ return FAILED;
+ } catch (IOException e) {
+ return FAILED;
+ } finally {
+ monitor.exitRead(); // free read lock
+ }
+ return COMPLETE;
+ }
+
+ public String toString() {
+ return "indexing project " + project.getName();
+ }
+
+}
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
new file mode 100644
index 0000000000..f158e89ba7
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
@@ -0,0 +1,400 @@
+package org.eclipse.jdt.internal.core.search.indexing;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.search.indexing.*;
+import org.eclipse.jdt.internal.core.search.processing.*;
+import org.eclipse.jdt.internal.core.*;
+import org.eclipse.jdt.internal.core.index.impl.*;
+
+import org.eclipse.jdt.core.JavaCore;
+
+import java.io.*;
+import java.util.*;
+import java.util.zip.*;
+
+public class IndexManager extends JobManager implements IIndexConstants {
+ /* number of file contents in memory */
+ public static int MAX_FILES_IN_MEMORY = 0;
+
+ public IWorkspace workspace;
+
+ /* indexes */
+ Hashtable indexes = new Hashtable(5);
+
+ /* read write monitors */
+ private Hashtable monitors = new Hashtable(5);
+
+ /* need to save ? */
+ private boolean needToSave = false;
+ private static final CRC32 checksumCalculator = new CRC32();
+ private IPath javaPluginLocation = null;
+ /**
+ * Before processing all jobs, need to ensure that the indexes are up to date.
+ */
+ public void activateProcessing() {
+ try {
+ Thread.currentThread().sleep(10000);
+ // wait 10 seconds so as not to interfere with plugin startup
+ } catch (InterruptedException ie) {
+ }
+ checkIndexConsistency();
+ }
+
+ /**
+ * Trigger addition of a resource to an index
+ * Note: the actual operation is performed in background
+ */
+ public void add(IFile resource) {
+ if (JavaCore.getPlugin() == null || this.workspace == null)
+ return;
+ String extension = resource.getFileExtension();
+ if ("java".equals(extension)) {
+ AddCompilationUnitToIndex job = new AddCompilationUnitToIndex(resource, this);
+ if (this.awaitingJobsCount() < MAX_FILES_IN_MEMORY) {
+ job.initializeContents();
+ }
+ request(job);
+ } else
+ if ("class".equals(extension)) {
+ AddClassFileToIndex job = new AddClassFileToIndex(resource, this);
+ if (this.awaitingJobsCount() < MAX_FILES_IN_MEMORY) {
+ job.initializeContents();
+ }
+ request(job);
+ }
+ }
+
+ /**
+ * Ensures that indexes are up to date with workbench content. Typically
+ * it is invoked in background when activate the job processing.
+ */
+ public void checkIndexConsistency() {
+
+ if (VERBOSE)
+ System.out.println("STARTING - ensuring consistency");
+
+ boolean wasEnabled = isEnabled();
+ try {
+ disable();
+
+ if (this.workspace == null)
+ return;
+ IProject[] projects = this.workspace.getRoot().getProjects();
+ for (int i = 0, max = projects.length; i < max; i++) {
+ IProject project = projects[i];
+ // not only java project, given at startup nature may not have been set yet
+ if (project.isOpen()) {
+ indexAll(project);
+ }
+ }
+ } finally {
+ if (wasEnabled)
+ enable();
+ if (VERBOSE)
+ System.out.println("DONE - ensuring consistency");
+ }
+ }
+
+ private String computeIndexName(String pathString) {
+ byte[] pathBytes = pathString.getBytes();
+ checksumCalculator.reset();
+ checksumCalculator.update(pathBytes);
+ String fileName = Long.toString(checksumCalculator.getValue()) + ".index";
+ if (VERBOSE)
+ System.out.println(" index name: " + pathString + " <----> " + fileName);
+ IPath indexPath = getJavaPluginWorkingLocation();
+ String indexDirectory = indexPath.toOSString();
+ if (indexDirectory.endsWith(File.separator)) {
+ return indexDirectory + fileName;
+ } else {
+ return indexDirectory + File.separator + fileName;
+ }
+ }
+
+ /**
+ * About to delete a project.
+ */
+ public void deleting(IProject project) {
+ discardJobsUntilNextProjectAddition(project.getName());
+
+ IPath path = project.getFullPath();
+ IIndex index = (IIndex) indexes.get(path);
+ if (index != null) {
+ indexes.remove(path);
+ monitors.remove(index);
+ }
+ }
+
+ /**
+ * Remove the index from cache for a given project.
+ * Passing null as a job family discards them all.
+ */
+ public void discardJobsUntilNextProjectAddition(String jobFamily) {
+ boolean wasEnabled = isEnabled();
+ try {
+ disable();
+
+ // wait until current job has completed
+ while (thread != null && executing) {
+ try {
+ Thread.currentThread().sleep(50);
+ } catch (InterruptedException e) {
+ }
+ }
+
+ // flush and compact awaiting jobs
+ int loc = -1;
+ boolean foundProjectAddition = false;
+ for (int i = jobStart; i <= jobEnd; i++) {
+ IJob currentJob = awaitingJobs[i];
+ awaitingJobs[i] = null;
+ if (jobFamily == null)
+ continue; // discard
+ if (currentJob.belongsTo(jobFamily)) { // might discard
+ if (!(foundProjectAddition
+ || (foundProjectAddition = currentJob instanceof IndexAllProject)))
+ continue; // discard
+ }
+ awaitingJobs[++loc] = currentJob;
+ }
+ jobStart = 0;
+ jobEnd = loc;
+ } finally {
+ if (wasEnabled)
+ enable();
+ }
+ }
+
+ /**
+ * Returns the index for a given project, if none then create an empty one.
+ * Note: if there is an existing index file already, it will be reused.
+ * Warning: Does not check whether index is consistent (not being used)
+ */
+ public IIndex getIndex(IPath path) {
+ return this.getIndex(path, true);
+ }
+
+ /**
+ * Returns the index for a given project, if none and asked for then create an empty one.
+ * Note: if there is an existing index file already, it will be reused.
+ * Warning: Does not check whether index is consistent (not being used)
+ */
+ public synchronized IIndex getIndex(IPath path, boolean mustCreate) {
+ IIndex index = (IIndex) indexes.get(path);
+ if (index == null) {
+ try {
+ // Compute canonical path
+ IPath canonicalPath = JavaProject.canonicalizedPath(path);
+ index = (IIndex) indexes.get(canonicalPath);
+ if (!mustCreate)
+ return index;
+ if (index == null) {
+ // New index: add same index for given path and canonical path
+ String indexPath = computeIndexName(canonicalPath.toOSString());
+ index =
+ IndexFactory.newIndex(indexPath, "Index for " + canonicalPath.toOSString());
+ indexes.put(canonicalPath, index);
+ indexes.put(path, index);
+ monitors.put(index, new ReadWriteMonitor());
+ } else {
+ // Index existed for canonical path, add it for given path
+ indexes.put(path, index);
+ }
+ } catch (IOException e) {
+ // The file could not be created. Possible reason: the project has been deleted.
+ return null;
+ }
+ }
+ //System.out.println(" index name: " + path.toOSString() + " <----> " + index.getIndexFile().getName());
+ return index;
+ }
+
+ private IPath getJavaPluginWorkingLocation() {
+ if (javaPluginLocation == null) {
+ javaPluginLocation = JavaCore.getPlugin().getStateLocation();
+ }
+ return javaPluginLocation;
+ }
+
+ /**
+ * Index access is controlled through a read-write monitor so as
+ * to ensure there is no concurrent read and write operations
+ * (only concurrent reading is allowed).
+ */
+ public ReadWriteMonitor getMonitorFor(IIndex index) {
+
+ return (ReadWriteMonitor) monitors.get(index);
+ }
+
+ /**
+ * Trigger addition of the entire content of a project
+ * Note: the actual operation is performed in background
+ */
+ public void indexAll(IProject project) {
+ if (JavaCore.getPlugin() == null || this.workspace == null)
+ return;
+
+ // Also request indexing of binaries on the classpath
+ // determine the new children
+ try {
+ IJavaModel model = JavaModelManager.getJavaModel(this.workspace);
+ IJavaProject javaProject = ((JavaModel) model).getJavaProject(project);
+ IClasspathEntry[] entries = javaProject.getResolvedClasspath(true);
+ for (int i = 0; i < entries.length; i++) {
+ IClasspathEntry entry = entries[i];
+ IPackageFragmentRoot[] roots = javaProject.getPackageFragmentRoots(entry);
+ for (int j = 0; j < roots.length; j++) {
+ IPackageFragmentRoot root = roots[j];
+ if (root.exists()) {
+ if (root.isArchive()) {
+ IResource rsc = root.getUnderlyingResource();
+ if (rsc == null) {
+ indexJarFile(root, project.getName());
+ } else {
+ indexJarFile((IFile) rsc, project.getName());
+ }
+ }
+ }
+ }
+ }
+ } catch (JavaModelException e) { // cannot retrieve classpath info
+ }
+ request(new IndexAllProject(project, this));
+ }
+
+ /**
+ * Trigger addition of a resource to an index
+ * Note: the actual operation is performed in background
+ */
+ public void indexJarFile(IFile resource, String projectName) {
+ if (JavaCore.getPlugin() == null || this.workspace == null)
+ return;
+ request(new AddJarFileToIndex(resource, this, projectName));
+ }
+
+ /**
+ * Trigger addition of a resource to an index
+ * Note: the actual operation is performed in background
+ */
+ public void indexJarFile(IPackageFragmentRoot root, String projectName) {
+ if (JavaCore.getPlugin() == null || this.workspace == null)
+ return;
+ // we want to request a indexing only if this index doesn't already exist
+ request(new AddJarFileToIndex(root, this, projectName));
+ }
+
+ /**
+ * Advance to the next available job, once the current one has been completed.
+ * Note: clients awaiting until the job count is zero are still waiting at this point.
+ */
+ protected synchronized void moveToNextJob() {
+
+ // remember that one job was executed, and we will need to save indexes at some point
+ needToSave = true;
+ super.moveToNextJob();
+ }
+
+ /**
+ * No more job awaiting.
+ */
+ protected void notifyIdle(long idlingTime) {
+ if (idlingTime > 1000 && needToSave)
+ saveIndexes();
+ }
+
+ /**
+ * Name of the background process
+ */
+ public String processName() {
+ return "Java indexing: " + IndexManager.class.getName();
+ }
+
+ /**
+ * Recreates the index for a given path, keeping the same read-write monitor.
+ * Returns the new empty index or null if it didn't exist before.
+ * Warning: Does not check whether index is consistent (not being used)
+ */
+ public synchronized IIndex recreateIndex(IPath path) {
+ IIndex index = (IIndex) indexes.get(path);
+ if (index != null) {
+ try {
+ // Compute canonical path
+ IPath canonicalPath = JavaProject.canonicalizedPath(path);
+ // Add same index for given path and canonical path
+ String indexPath = computeIndexName(canonicalPath.toOSString());
+ ReadWriteMonitor monitor = (ReadWriteMonitor) monitors.remove(index);
+ index =
+ IndexFactory.newIndex(indexPath, "Index for " + canonicalPath.toOSString());
+ index.empty();
+ indexes.put(canonicalPath, index);
+ indexes.put(path, index);
+ monitors.put(index, monitor);
+ } catch (IOException e) {
+ // The file could not be created. Possible reason: the project has been deleted.
+ return null;
+ }
+ }
+ //System.out.println(" index name: " + path.toOSString() + " <----> " + index.getIndexFile().getName());
+ return index;
+ }
+
+ /**
+ * Trigger removal of a resource to an index
+ * Note: the actual operation is performed in background
+ */
+ public void remove(String resourceName, IProject project) {
+ request(new RemoveFromIndex(resourceName, project, this));
+ }
+
+ /**
+ * Flush current state
+ */
+ public void reset() {
+
+ super.reset();
+ if (indexes != null) {
+ indexes = new Hashtable(5);
+ monitors = new Hashtable(5);
+ }
+ javaPluginLocation = null;
+ }
+
+ /**
+ * Commit all index memory changes to disk
+ */
+ public void saveIndexes() {
+ Enumeration indexList = indexes.elements();
+ while (indexList.hasMoreElements()) {
+ try {
+ IIndex index = (IIndex) indexList.nextElement();
+ if (index == null)
+ continue; // index got deleted since acquired
+ ReadWriteMonitor monitor = getMonitorFor(index);
+ if (monitor == null)
+ continue; // index got deleted since acquired
+ try {
+ monitor.enterWrite();
+ if (IndexManager.VERBOSE)
+ System.out.println("-> merging index : " + index.getIndexFile());
+ index.save();
+ } finally {
+ monitor.exitWrite();
+ }
+ } catch (IOException e) {
+ // Index file has been deleted
+ }
+ }
+ needToSave = false;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/ReadWriteMonitor.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/ReadWriteMonitor.java
new file mode 100644
index 0000000000..6524658c58
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/ReadWriteMonitor.java
@@ -0,0 +1,60 @@
+package org.eclipse.jdt.internal.core.search.indexing;
+
+public class ReadWriteMonitor {
+
+ /**
+ * <0 : writing (cannot go beyond -1, i.e one concurrent writer)
+ * =0 : idle
+ * >0 : reading (number of concurrent readers)
+ */
+ private int status = 0;
+ /**
+ * Concurrent reading is allowed
+ * Blocking only when already writing.
+ */
+ public synchronized void enterRead() {
+
+ while (status < 0) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ status++;
+ }
+
+ /**
+ * Only one writer at a time is allowed to perform
+ * Blocking only when already writing or reading.
+ */
+ public synchronized void enterWrite() {
+
+ while (status != 0) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ status--;
+ }
+
+ /**
+ * Only notify waiting writer(s) if last reader
+ */
+ public synchronized void exitRead() {
+
+ if (--status == 0)
+ notifyAll();
+ }
+
+ /**
+ * When writing is over, all readers and possible
+ * writers are granted permission to restart concurrently
+ */
+ public synchronized void exitWrite() {
+
+ if (++status == 0)
+ notifyAll();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/RemoveFromIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/RemoveFromIndex.java
new file mode 100644
index 0000000000..fd9edcb2c1
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/RemoveFromIndex.java
@@ -0,0 +1,61 @@
+package org.eclipse.jdt.internal.core.search.indexing;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.resources.*;
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.internal.core.search.processing.*;
+
+import org.eclipse.core.resources.*;
+
+import java.io.*;
+
+class RemoveFromIndex implements IJob, IJobConstants {
+ String resourceName;
+ IProject project;
+ IndexManager manager;
+ public RemoveFromIndex(
+ String resourceName,
+ IProject project,
+ IndexManager manager) {
+ this.resourceName = resourceName;
+ this.project = project;
+ this.manager = manager;
+ }
+
+ public boolean belongsTo(String jobFamily) {
+ return jobFamily.equals(project.getName());
+ }
+
+ public boolean execute() {
+ try {
+ if (project.exists() && project.isOpen()) {
+ IIndex index = manager.getIndex(project.getFullPath());
+ if (index == null)
+ return COMPLETE;
+
+ /* ensure no concurrent write access to index */
+ ReadWriteMonitor monitor = manager.getMonitorFor(index);
+ if (monitor == null)
+ return COMPLETE; // index got deleted since acquired
+ try {
+ monitor.enterWrite(); // ask permission to write
+ index.remove(resourceName);
+ } finally {
+ monitor.exitWrite(); // free write lock
+ }
+ }
+ } catch (IOException e) {
+ return FAILED;
+ }
+ return COMPLETE;
+ }
+
+ public String toString() {
+ return "removing from index " + resourceName;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexer.java
new file mode 100644
index 0000000000..02b019bb82
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexer.java
@@ -0,0 +1,80 @@
+package org.eclipse.jdt.internal.core.search.indexing;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.internal.compiler.parser.InvalidInputException;
+import org.eclipse.jdt.internal.compiler.parser.Scanner;
+import org.eclipse.jdt.internal.compiler.parser.TerminalSymbols;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.core.jdom.CompilationUnit;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * A SourceIndexer indexes java files using a java parser. The following items are indexed:
+ * Declarations of:
+ * - Classes<br>
+ * - Interfaces; <br>
+ * - Methods;<br>
+ * - Fields;<br>
+ * References to:
+ * - Methods (with number of arguments); <br>
+ * - Fields;<br>
+ * - Types;<br>
+ * - Constructors.
+ */
+public class SourceIndexer extends AbstractIndexer {
+
+ public static final String[] FILE_TYPES = new String[] { "java" };
+ protected DefaultProblemFactory problemFactory =
+ new DefaultProblemFactory(Locale.getDefault());
+
+ /**
+ * Returns the file types the <code>IIndexer</code> handles.
+ */
+
+ public String[] getFileTypes() {
+ return FILE_TYPES;
+ }
+
+ protected void indexFile(IDocument document) throws IOException {
+
+ // Add the name of the file to the index
+ output.addDocument(document);
+
+ // Create a new Parser
+ SourceIndexerRequestor requestor = new SourceIndexerRequestor(this, document);
+ SourceElementParser parser = new SourceElementParser(requestor, problemFactory);
+
+ // Launch the parser
+ char[] source = null;
+ char[] name = null;
+ try {
+ source = document.getCharContent();
+ name = document.getName().toCharArray();
+ } catch (Exception e) {
+ }
+ if (source == null || name == null)
+ return; // could not retrieve document info (e.g. resource was discarded)
+ CompilationUnit compilationUnit = new CompilationUnit(source, name);
+ try {
+ parser.parseCompilationUnit(compilationUnit, true);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Sets the document types the <code>IIndexer</code> handles.
+ */
+
+ public void setFileTypes(String[] fileTypes) {
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexerRequestor.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexerRequestor.java
new file mode 100644
index 0000000000..9268483152
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexerRequestor.java
@@ -0,0 +1,335 @@
+package org.eclipse.jdt.internal.core.search.indexing;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+import org.eclipse.jdt.internal.core.index.impl.*;
+
+import java.io.File;
+
+/**
+ * This class is used by the JavaParserIndexer. When parsing the java file, the requestor
+ * recognises the java elements (methods, fields, ...) and add them to an index.
+ */
+public class SourceIndexerRequestor
+ implements ISourceElementRequestor, IIndexConstants {
+ SourceIndexer indexer;
+ IDocument document;
+
+ char[] packageName;
+ char[][] enclosingTypeNames = new char[5][];
+ int depth = 0;
+ public SourceIndexerRequestor(SourceIndexer indexer, IDocument document) {
+ super();
+ this.indexer = indexer;
+ this.document = document;
+ }
+
+ /**
+ * acceptConstructorReference method comment.
+ */
+ public void acceptConstructorReference(
+ char[] typeName,
+ int argCount,
+ int sourcePosition) {
+ this.indexer.addConstructorReference(typeName, argCount);
+ int lastDot = CharOperation.lastIndexOf('.', typeName);
+ if (lastDot != -1) {
+ char[][] qualification =
+ CharOperation.splitOn('.', CharOperation.subarray(typeName, 0, lastDot));
+ for (int i = 0, length = qualification.length; i < length; i++) {
+ this.indexer.addNameReference(qualification[i]);
+ }
+ }
+ }
+
+ /**
+ * acceptFieldReference method comment.
+ */
+ public void acceptFieldReference(char[] fieldName, int sourcePosition) {
+ this.indexer.addFieldReference(fieldName);
+ }
+
+ /**
+ * acceptImport method comment.
+ */
+ public void acceptImport(
+ int declarationStart,
+ int declarationEnd,
+ char[] name,
+ boolean onDemand) {
+ char[][] qualification =
+ CharOperation.splitOn(
+ '.',
+ CharOperation.subarray(name, 0, CharOperation.lastIndexOf('.', name)));
+ for (int i = 0, length = qualification.length; i < length; i++) {
+ this.indexer.addNameReference(qualification[i]);
+ }
+ }
+
+ /**
+ * acceptInitializer method comment.
+ */
+ public void acceptInitializer(
+ int modifiers,
+ int declarationSourceStart,
+ int declarationSourceEnd) {
+ }
+
+ /**
+ * acceptLineSeparatorPositions method comment.
+ */
+ public void acceptLineSeparatorPositions(int[] positions) {
+ }
+
+ /**
+ * acceptMethodReference method comment.
+ */
+ public void acceptMethodReference(
+ char[] methodName,
+ int argCount,
+ int sourcePosition) {
+ this.indexer.addMethodReference(methodName, argCount);
+ }
+
+ /**
+ * acceptPackage method comment.
+ */
+ public void acceptPackage(
+ int declarationStart,
+ int declarationEnd,
+ char[] name) {
+ this.packageName = name;
+ }
+
+ /**
+ * acceptProblem method comment.
+ */
+ public void acceptProblem(IProblem problem) {
+ }
+
+ /**
+ * acceptTypeReference method comment.
+ */
+ public void acceptTypeReference(
+ char[][] typeName,
+ int sourceStart,
+ int sourceEnd) {
+ int length = typeName.length;
+ for (int i = 0; i < length - 1; i++)
+ acceptUnknownReference(typeName[i], 0); // ?
+ acceptTypeReference(typeName[length - 1], 0);
+ }
+
+ /**
+ * acceptTypeReference method comment.
+ */
+ public void acceptTypeReference(char[] simpleTypeName, int sourcePosition) {
+ this.indexer.addTypeReference(simpleTypeName);
+ }
+
+ /**
+ * acceptUnknownReference method comment.
+ */
+ public void acceptUnknownReference(
+ char[][] name,
+ int sourceStart,
+ int sourceEnd) {
+ for (int i = 0; i < name.length; i++) {
+ acceptUnknownReference(name[i], 0);
+ }
+ }
+
+ /**
+ * acceptUnknownReference method comment.
+ */
+ public void acceptUnknownReference(char[] name, int sourcePosition) {
+ this.indexer.addNameReference(name);
+ }
+
+ /*
+ * Rebuild the proper qualification for the current source type:
+ *
+ * java.lang.Object ---> null
+ * java.util.Hashtable$Entry --> [Hashtable]
+ * x.y.A$B$C --> [A, B]
+ */
+ public char[][] enclosingTypeNames() {
+
+ if (depth == 0)
+ return null;
+
+ char[][] qualification = new char[this.depth][];
+ System.arraycopy(this.enclosingTypeNames, 0, qualification, 0, this.depth);
+ return qualification;
+ }
+
+ /**
+ * enterClass method comment.
+ */
+ public void enterClass(
+ int declarationStart,
+ int modifiers,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[] superclass,
+ char[][] superinterfaces) {
+
+ // eliminate possible qualifications, given they need to be fully resolved again
+ if (superclass != null) {
+ superclass = CharOperation.lastSegment(superclass, '.');
+ }
+ if (superinterfaces != null) {
+ for (int i = 0, length = superinterfaces.length; i < length; i++) {
+ superinterfaces[i] = CharOperation.lastSegment(superinterfaces[i], '.');
+ }
+ }
+ this.indexer.addClassDeclaration(
+ modifiers,
+ packageName,
+ name,
+ enclosingTypeNames(),
+ superclass,
+ superinterfaces);
+ this.pushTypeName(name);
+ }
+
+ /**
+ * enterCompilationUnit method comment.
+ */
+ public void enterCompilationUnit() {
+ }
+
+ /**
+ * enterConstructor method comment.
+ */
+ public void enterConstructor(
+ int declarationStart,
+ int modifiers,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[][] parameterTypes,
+ char[][] parameterNames,
+ char[][] exceptionTypes) {
+ this.indexer.addConstructorDeclaration(name, parameterTypes, exceptionTypes);
+ }
+
+ /**
+ * enterField method comment.
+ */
+ public void enterField(
+ int declarationStart,
+ int modifiers,
+ char[] type,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd) {
+ this.indexer.addFieldDeclaration(type, name);
+ }
+
+ /**
+ * enterInterface method comment.
+ */
+ public void enterInterface(
+ int declarationStart,
+ int modifiers,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[][] superinterfaces) {
+ // eliminate possible qualifications, given they need to be fully resolved again
+ if (superinterfaces != null) {
+ for (int i = 0, length = superinterfaces.length; i < length; i++) {
+ superinterfaces[i] = CharOperation.lastSegment(superinterfaces[i], '.');
+ }
+ }
+ this.indexer.addInterfaceDeclaration(
+ modifiers,
+ packageName,
+ name,
+ enclosingTypeNames(),
+ superinterfaces);
+ this.pushTypeName(name);
+ }
+
+ /**
+ * enterMethod method comment.
+ */
+ public void enterMethod(
+ int declarationStart,
+ int modifiers,
+ char[] returnType,
+ char[] name,
+ int nameSourceStart,
+ int nameSourceEnd,
+ char[][] parameterTypes,
+ char[][] parameterNames,
+ char[][] exceptionTypes) {
+ this.indexer.addMethodDeclaration(
+ name,
+ parameterTypes,
+ returnType,
+ exceptionTypes);
+ }
+
+ /**
+ * exitClass method comment.
+ */
+ public void exitClass(int declarationEnd) {
+ popTypeName();
+ }
+
+ /**
+ * exitCompilationUnit method comment.
+ */
+ public void exitCompilationUnit(int declarationEnd) {
+ }
+
+ /**
+ * exitConstructor method comment.
+ */
+ public void exitConstructor(int declarationEnd) {
+ }
+
+ /**
+ * exitField method comment.
+ */
+ public void exitField(int declarationEnd) {
+ }
+
+ /**
+ * exitInterface method comment.
+ */
+ public void exitInterface(int declarationEnd) {
+ popTypeName();
+ }
+
+ /**
+ * exitMethod method comment.
+ */
+ public void exitMethod(int declarationEnd) {
+ }
+
+ public void popTypeName() {
+ enclosingTypeNames[depth--] = null;
+ }
+
+ public void pushTypeName(char[] typeName) {
+ if (depth == enclosingTypeNames.length) {
+ System.arraycopy(
+ enclosingTypeNames,
+ 0,
+ enclosingTypeNames = new char[depth * 2][],
+ 0,
+ depth);
+ }
+ enclosingTypeNames[depth++] = typeName;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/AndPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/AndPattern.java
new file mode 100644
index 0000000000..e4aa770ce3
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/AndPattern.java
@@ -0,0 +1,121 @@
+package org.eclipse.jdt.internal.core.search.matching;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.search.*;
+import org.eclipse.jdt.internal.core.index.impl.*;
+
+import java.io.IOException;
+
+/**
+ * Query the index multiple times and do an 'and' on the results.
+ */
+public abstract class AndPattern extends SearchPattern {
+ public AndPattern(int matchMode, boolean isCaseSensitive) {
+ super(matchMode, isCaseSensitive);
+ }
+
+ /**
+ * Query a given index for matching entries.
+ */
+ public void findIndexMatches(
+ IndexInput input,
+ IIndexSearchRequestor requestor,
+ int detailLevel,
+ IProgressMonitor progressMonitor,
+ IJavaSearchScope scope)
+ throws IOException {
+
+ if (progressMonitor != null && progressMonitor.isCanceled())
+ throw new OperationCanceledException();
+
+ /* narrow down a set of entries using prefix criteria */
+ long[] potentialRefs = null;
+ int maxRefs = -1;
+ this.resetQuery();
+ do {
+ IEntryResult[] entries = input.queryEntriesPrefixedBy(indexEntryPrefix());
+ if (entries == null)
+ break;
+
+ int numFiles = input.getNumFiles();
+ long[] references = null;
+ int referencesLength = -1;
+ for (int i = 0, max = entries.length; i < max; i++) {
+
+ if (progressMonitor != null && progressMonitor.isCanceled())
+ throw new OperationCanceledException();
+
+ /* retrieve and decode entry */
+ IEntryResult entry = entries[i];
+ decodeIndexEntry(entry);
+ if (matchIndexEntry()) {
+ /* accumulate references in an array of bits : 1 if the reference is present, 0 otherwise */
+ int[] fileReferences = entry.getFileReferences();
+ for (int j = 0, refLength = fileReferences.length; j < refLength; j++) {
+ int fileReference = fileReferences[j];
+ int vectorIndex = fileReference / 64; // a long has 64 bits
+ if (references == null) {
+ referencesLength = (numFiles / 64) + 1;
+ references = new long[referencesLength];
+ }
+ long mask = 1L << (fileReference % 64);
+ references[vectorIndex] |= mask;
+ }
+ }
+ }
+
+ /* only select entries which actually match the entire search pattern */
+ if (references == null) {
+ /* no references */
+ return;
+ } else {
+ if (potentialRefs == null) {
+ /* first query : these are the potential references */
+ potentialRefs = references;
+ maxRefs = numFiles;
+ } else {
+ /* eliminate potential references that don't match the current references */
+ for (int i = 0, length = references.length; i < length; i++) {
+ if (i < potentialRefs.length) {
+ potentialRefs[i] &= references[i];
+ } else {
+ potentialRefs[i] = 0;
+ }
+ }
+ }
+ }
+ } while (this.hasNextQuery());
+
+ /* report potential references that remain */
+ if (potentialRefs != null) {
+ int[] refs = new int[maxRefs];
+ int refsLength = 0;
+ for (int reference = 1; reference <= maxRefs; reference++) {
+ int vectorIndex = reference / 64; // a long has 64 bits
+ if ((potentialRefs[vectorIndex] & (1L << (reference % 64))) != 0) {
+ refs[refsLength++] = reference;
+ }
+
+ }
+ System.arraycopy(refs, 0, refs = new int[refsLength], 0, refsLength);
+ this.feedIndexRequestor(requestor, detailLevel, refs, input, scope);
+ }
+ }
+
+ /**
+ * Returns whether another query must be done.
+ */
+ protected abstract boolean hasNextQuery();
+ /**
+ * Resets the query and prepares this pattern to be queried.
+ */
+ protected abstract void resetQuery();
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorDeclarationPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorDeclarationPattern.java
new file mode 100644
index 0000000000..3b07ebb5f7
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorDeclarationPattern.java
@@ -0,0 +1,326 @@
+package org.eclipse.jdt.internal.core.search.matching;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+import org.eclipse.jdt.core.Signature;
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.search.indexing.*;
+import org.eclipse.jdt.internal.core.index.impl.*;
+import org.eclipse.jdt.internal.core.search.*;
+
+import java.io.*;
+
+/**
+ * The selector is unused, the constructor name is specified by the type simple name.
+ */
+public class ConstructorDeclarationPattern extends MethodDeclarationPattern {
+
+ private char[] decodedTypeName;
+ public ConstructorDeclarationPattern(
+ char[] declaringSimpleName,
+ int matchMode,
+ boolean isCaseSensitive,
+ char[] declaringQualification,
+ char[][] parameterQualifications,
+ char[][] parameterSimpleNames) {
+ super(
+ null,
+ matchMode,
+ isCaseSensitive,
+ declaringQualification,
+ declaringSimpleName,
+ null,
+ null,
+ parameterQualifications,
+ parameterSimpleNames);
+ }
+
+ public void decodeIndexEntry(IEntryResult entryResult) {
+
+ char[] word = entryResult.getWord();
+ int size = word.length;
+ int lastSeparatorIndex = CharOperation.lastIndexOf(SEPARATOR, word);
+
+ decodedParameterCount =
+ Integer.parseInt(
+ new String(word, lastSeparatorIndex + 1, size - lastSeparatorIndex - 1));
+ decodedTypeName =
+ CharOperation.subarray(word, CONSTRUCTOR_DECL.length, lastSeparatorIndex);
+ }
+
+ /**
+ * see SearchPattern.feedIndexRequestor
+ */
+ public void feedIndexRequestor(
+ IIndexSearchRequestor requestor,
+ int detailLevel,
+ int[] references,
+ IndexInput input,
+ IJavaSearchScope scope)
+ throws IOException {
+ for (int i = 0, max = references.length; i < max; i++) {
+ IndexedFile file = input.getIndexedFile(references[i]);
+ String path;
+ if (file != null
+ && scope.encloses(path = IndexedFile.convertPath(file.getPath()))) {
+ requestor.acceptConstructorDeclaration(
+ path,
+ decodedTypeName,
+ decodedParameterCount);
+ }
+ }
+ }
+
+ /**
+ * @see SearchPattern#indexEntryPrefix
+ */
+ public char[] indexEntryPrefix() {
+
+ return AbstractIndexer.bestConstructorDeclarationPrefix(
+ declaringSimpleName,
+ parameterSimpleNames == null ? -1 : parameterSimpleNames.length,
+ matchMode,
+ isCaseSensitive);
+ }
+
+ /**
+ * @see SearchPattern#matches(AstNode, boolean)
+ */
+ protected boolean matches(AstNode node, boolean resolve) {
+ if (!(node instanceof ConstructorDeclaration))
+ return false;
+
+ ConstructorDeclaration constructor = (ConstructorDeclaration) node;
+
+ // constructor name is stored in selector field
+ if (this.declaringSimpleName != null
+ && !this.matchesName(this.declaringSimpleName, constructor.selector))
+ return false;
+
+ // declaring type
+ MethodBinding binding = constructor.binding;
+ if (resolve && binding != null) {
+ ReferenceBinding declaringBinding = binding.declaringClass;
+ if (!this
+ .matchesType(
+ this.declaringSimpleName,
+ this.declaringQualification,
+ declaringBinding))
+ return false;
+ }
+
+ // argument types
+ int argumentCount =
+ this.parameterSimpleNames == null ? -1 : this.parameterSimpleNames.length;
+ if (argumentCount > -1) {
+ int parameterCount =
+ constructor.arguments == null ? 0 : constructor.arguments.length;
+ if (parameterCount != argumentCount)
+ return false;
+
+ if (resolve && binding != null) {
+ for (int i = 0; i < parameterCount; i++) {
+ char[] qualification = this.parameterQualifications[i];
+ char[] type = this.parameterSimpleNames[i];
+ if (!this.matchesType(type, qualification, binding.parameters[i]))
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @see SearchPattern#matches(Binding)
+ */
+ public boolean matches(Binding binding) {
+ if (!(binding instanceof MethodBinding))
+ return false;
+
+ MethodBinding method = (MethodBinding) binding;
+
+ // must be a constructor
+ if (!method.isConstructor())
+ return false;
+
+ // declaring type
+ ReferenceBinding declaringType = method.declaringClass;
+ if (declaringType != null) {
+ if (!method.isStatic() && !method.isPrivate()) {
+ if (!this
+ .matchesAsSubtype(
+ declaringType,
+ this.declaringSimpleName,
+ this.declaringQualification))
+ return false;
+ } else {
+ if (!this
+ .matchesType(
+ this.declaringSimpleName,
+ this.declaringQualification,
+ declaringType))
+ return false;
+ }
+ }
+
+ // parameter types
+ int parameterCount =
+ this.parameterSimpleNames == null ? -1 : this.parameterSimpleNames.length;
+ if (parameterCount > -1) {
+ int argumentCount = method.parameters == null ? 0 : method.parameters.length;
+ if (parameterCount != argumentCount)
+ return false;
+ for (int i = 0; i < parameterCount; i++) {
+ char[] qualification = this.parameterQualifications[i];
+ char[] type = this.parameterSimpleNames[i];
+ if (!this.matchesType(type, qualification, method.parameters[i]))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @see SearchPattern#matchesBinary(Object, Object)
+ */
+ public boolean matchesBinary(Object binaryInfo, Object enclosingBinaryInfo) {
+ if (!(binaryInfo instanceof IBinaryMethod))
+ return false;
+
+ IBinaryMethod method = (IBinaryMethod) binaryInfo;
+
+ // must be a constructor
+ if (!method.isConstructor())
+ return false;
+
+ // declaring type
+ IBinaryType declaringType = (IBinaryType) enclosingBinaryInfo;
+ if (declaringType != null) {
+ char[] declaringTypeName = (char[]) declaringType.getName().clone();
+ CharOperation.replace(declaringTypeName, '/', '.');
+ if (!this
+ .matchesType(
+ this.declaringSimpleName,
+ this.declaringQualification,
+ declaringTypeName)) {
+ return false;
+ }
+ }
+
+ // parameter types
+ int parameterCount =
+ this.parameterSimpleNames == null ? -1 : this.parameterSimpleNames.length;
+ if (parameterCount > -1) {
+ String methodDescriptor =
+ new String(method.getMethodDescriptor()).replace('/', '.');
+ String[] arguments = Signature.getParameterTypes(methodDescriptor);
+ int argumentCount = arguments.length;
+ if (parameterCount != argumentCount)
+ return false;
+ for (int i = 0; i < parameterCount; i++) {
+ char[] qualification = this.parameterQualifications[i];
+ char[] type = this.parameterSimpleNames[i];
+ if (!this
+ .matchesType(
+ type,
+ qualification,
+ Signature.toString(arguments[i]).toCharArray()))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @see SearchPattern#matchIndexEntry
+ */
+ protected boolean matchIndexEntry() {
+
+ /* check selector matches */
+ if (declaringSimpleName != null) {
+ switch (matchMode) {
+ case EXACT_MATCH :
+ if (!CharOperation
+ .equals(declaringSimpleName, decodedTypeName, isCaseSensitive)) {
+ return false;
+ }
+ break;
+ case PREFIX_MATCH :
+ if (!CharOperation
+ .prefixEquals(declaringSimpleName, decodedTypeName, isCaseSensitive)) {
+ return false;
+ }
+ break;
+ case PATTERN_MATCH :
+ if (!CharOperation
+ .match(declaringSimpleName, decodedTypeName, isCaseSensitive)) {
+ return false;
+ }
+ }
+ }
+ if (parameterSimpleNames != null) {
+ if (parameterSimpleNames.length != decodedParameterCount)
+ return false;
+ }
+ return true;
+ }
+
+ public String toString() {
+
+ StringBuffer buffer = new StringBuffer(20);
+ buffer.append("ConstructorDeclarationPattern: ");
+ if (declaringQualification != null)
+ buffer.append(declaringQualification).append('.');
+ if (declaringSimpleName != null)
+ buffer.append(declaringSimpleName);
+ else
+ if (declaringQualification != null)
+ buffer.append("*");
+
+ buffer.append('(');
+ if (parameterSimpleNames == null) {
+ buffer.append("...");
+ } else {
+ for (int i = 0, max = parameterSimpleNames.length; i < max; i++) {
+ if (i > 0)
+ buffer.append(", ");
+ if (parameterQualifications[i] != null)
+ buffer.append(parameterQualifications[i]).append('.');
+ if (parameterSimpleNames[i] == null)
+ buffer.append('*');
+ else
+ buffer.append(parameterSimpleNames[i]);
+ }
+ }
+ buffer.append(')');
+ buffer.append(", ");
+ switch (matchMode) {
+ case EXACT_MATCH :
+ buffer.append("exact match, ");
+ break;
+ case PREFIX_MATCH :
+ buffer.append("prefix match, ");
+ break;
+ case PATTERN_MATCH :
+ buffer.append("pattern match, ");
+ break;
+ }
+ if (isCaseSensitive)
+ buffer.append("case sensitive");
+ else
+ buffer.append("case insensitive");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorReferencePattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorReferencePattern.java
new file mode 100644
index 0000000000..d27d454544
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorReferencePattern.java
@@ -0,0 +1,271 @@
+package org.eclipse.jdt.internal.core.search.matching;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.search.indexing.*;
+import org.eclipse.jdt.internal.core.index.impl.*;
+import org.eclipse.jdt.internal.core.search.*;
+
+import java.io.*;
+
+/**
+ * The selector is unused, the constructor name is specified by the type simple name.
+ */
+public class ConstructorReferencePattern extends MethodReferencePattern {
+
+ private char[] decodedTypeName;
+ public ConstructorReferencePattern(
+ char[] declaringSimpleName,
+ int matchMode,
+ boolean isCaseSensitive,
+ char[] declaringQualification,
+ char[][] parameterQualifications,
+ char[][] parameterSimpleNames) {
+ super(
+ null,
+ matchMode,
+ isCaseSensitive,
+ declaringQualification,
+ declaringSimpleName,
+ null,
+ null,
+ parameterQualifications,
+ parameterSimpleNames);
+ }
+
+ public void decodeIndexEntry(IEntryResult entryResult) {
+
+ char[] word = entryResult.getWord();
+ int size = word.length;
+ int lastSeparatorIndex = CharOperation.lastIndexOf(SEPARATOR, word);
+
+ decodedParameterCount =
+ Integer.parseInt(
+ new String(word, lastSeparatorIndex + 1, size - lastSeparatorIndex - 1));
+ decodedTypeName =
+ CharOperation.subarray(word, CONSTRUCTOR_REF.length, lastSeparatorIndex);
+ }
+
+ /**
+ * see SearchPattern.feedIndexRequestor
+ */
+ public void feedIndexRequestor(
+ IIndexSearchRequestor requestor,
+ int detailLevel,
+ int[] references,
+ IndexInput input,
+ IJavaSearchScope scope)
+ throws IOException {
+ for (int i = 0, max = references.length; i < max; i++) {
+ IndexedFile file = input.getIndexedFile(references[i]);
+ String path;
+ if (file != null
+ && scope.encloses(path = IndexedFile.convertPath(file.getPath()))) {
+ requestor.acceptConstructorReference(
+ path,
+ decodedTypeName,
+ decodedParameterCount);
+ }
+ }
+ }
+
+ /**
+ * @see SearchPattern#indexEntryPrefix
+ */
+ public char[] indexEntryPrefix() {
+
+ return AbstractIndexer.bestConstructorReferencePrefix(
+ declaringSimpleName,
+ parameterSimpleNames == null ? -1 : parameterSimpleNames.length,
+ matchMode,
+ isCaseSensitive);
+ }
+
+ /**
+ * Returns whether this constructor pattern matches the given allocation expression.
+ * Look at resolved information only if specified.
+ */
+ private boolean matches(AllocationExpression allocation, boolean resolve) {
+
+ // constructor name is simple type name
+ char[][] typeName = allocation.type.getTypeName();
+ if (this.declaringSimpleName != null
+ && !this.matchesName(this.declaringSimpleName, typeName[typeName.length - 1]))
+ return false;
+
+ // declaring type
+ MethodBinding binding = allocation.binding;
+ if (resolve && binding != null) {
+ ReferenceBinding declaringBinding = binding.declaringClass;
+ if (!this
+ .matchesType(
+ this.declaringSimpleName,
+ this.declaringQualification,
+ declaringBinding))
+ return false;
+ }
+
+ // argument types
+ int argumentCount =
+ this.parameterSimpleNames == null ? -1 : this.parameterSimpleNames.length;
+ if (argumentCount > -1) {
+ int parameterCount =
+ allocation.arguments == null ? 0 : allocation.arguments.length;
+ if (parameterCount != argumentCount)
+ return false;
+
+ if (resolve && binding != null) {
+ for (int i = 0; i < parameterCount; i++) {
+ char[] qualification = this.parameterQualifications[i];
+ char[] type = this.parameterSimpleNames[i];
+ if (!this.matchesType(type, qualification, binding.parameters[i]))
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @see SearchPattern#matches(AstNode, boolean)
+ */
+ protected boolean matches(AstNode node, boolean resolve) {
+ if (node instanceof AllocationExpression) {
+ return this.matches((AllocationExpression) node, resolve);
+ } else
+ if (node instanceof ExplicitConstructorCall) {
+ return this.matches((ExplicitConstructorCall) node, resolve);
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether this constructor pattern matches the given explicit constructor call.
+ * Look at resolved information only if specified.
+ */
+ private boolean matches(ExplicitConstructorCall call, boolean resolve) {
+ // TBD: constructor name is super simple type name
+
+ // declaring type
+ MethodBinding binding = call.binding;
+ if (resolve && binding != null) {
+ ReferenceBinding declaringBinding = binding.declaringClass;
+ if (!this
+ .matchesType(
+ this.declaringSimpleName,
+ this.declaringQualification,
+ declaringBinding))
+ return false;
+ }
+
+ // argument types
+ int argumentCount =
+ this.parameterSimpleNames == null ? -1 : this.parameterSimpleNames.length;
+ if (argumentCount > -1) {
+ int parameterCount = call.arguments == null ? 0 : call.arguments.length;
+ if (parameterCount != argumentCount)
+ return false;
+
+ if (resolve && binding != null) {
+ for (int i = 0; i < parameterCount; i++) {
+ char[] qualification = this.parameterQualifications[i];
+ char[] type = this.parameterSimpleNames[i];
+ if (!this.matchesType(type, qualification, binding.parameters[i]))
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @see SearchPattern#matchIndexEntry
+ */
+ protected boolean matchIndexEntry() {
+
+ /* check selector matches */
+ if (declaringSimpleName != null) {
+ switch (matchMode) {
+ case EXACT_MATCH :
+ if (!CharOperation
+ .equals(declaringSimpleName, decodedTypeName, isCaseSensitive)) {
+ return false;
+ }
+ break;
+ case PREFIX_MATCH :
+ if (!CharOperation
+ .prefixEquals(declaringSimpleName, decodedTypeName, isCaseSensitive)) {
+ return false;
+ }
+ break;
+ case PATTERN_MATCH :
+ if (!CharOperation
+ .match(declaringSimpleName, decodedTypeName, isCaseSensitive)) {
+ return false;
+ }
+ }
+ }
+ if (parameterSimpleNames != null) {
+ if (parameterSimpleNames.length != decodedParameterCount)
+ return false;
+ }
+ return true;
+ }
+
+ public String toString() {
+
+ StringBuffer buffer = new StringBuffer(20);
+ buffer.append("ConstructorReferencePattern: ");
+ if (declaringQualification != null)
+ buffer.append(declaringQualification).append('.');
+ if (declaringSimpleName != null)
+ buffer.append(declaringSimpleName);
+ else
+ if (declaringQualification != null)
+ buffer.append("*");
+ buffer.append('(');
+ if (parameterSimpleNames == null) {
+ buffer.append("...");
+ } else {
+ for (int i = 0, max = parameterSimpleNames.length; i < max; i++) {
+ if (i > 0)
+ buffer.append(", ");
+ if (parameterQualifications[i] != null)
+ buffer.append(parameterQualifications[i]).append('.');
+ if (parameterSimpleNames[i] == null)
+ buffer.append('*');
+ else
+ buffer.append(parameterSimpleNames[i]);
+ }
+ }
+ buffer.append(')');
+ buffer.append(", ");
+ switch (matchMode) {
+ case EXACT_MATCH :
+ buffer.append("exact match, ");
+ break;
+ case PREFIX_MATCH :
+ buffer.append("prefix match, ");
+ break;
+ case PATTERN_MATCH :
+ buffer.append("pattern match, ");
+ break;
+ }
+ if (isCaseSensitive)
+ buffer.append("case sensitive");
+ else
+ buffer.append("case insensitive");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldDeclarationPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldDeclarationPattern.java
new file mode 100644
index 0000000000..ea344b45f8
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldDeclarationPattern.java
@@ -0,0 +1,317 @@
+package org.eclipse.jdt.internal.core.search.matching;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+import org.eclipse.jdt.core.Signature;
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.search.indexing.*;
+import org.eclipse.jdt.internal.core.index.impl.*;
+import org.eclipse.jdt.internal.core.search.*;
+
+import java.io.*;
+
+public class FieldDeclarationPattern extends SearchPattern {
+
+ // selector
+ protected char[] name;
+
+ // declaring type
+ protected char[] declaringQualification;
+ protected char[] declaringSimpleName;
+
+ // type
+ protected char[] typeQualification;
+ protected char[] typeSimpleName;
+
+ protected char[] decodedName;
+ public FieldDeclarationPattern(
+ char[] name,
+ int matchMode,
+ boolean isCaseSensitive,
+ char[] declaringQualification,
+ char[] declaringSimpleName,
+ char[] typeQualification,
+ char[] typeSimpleName) {
+
+ super(matchMode, isCaseSensitive);
+
+ this.name = isCaseSensitive ? name : CharOperation.toLowerCase(name);
+ this.declaringQualification =
+ isCaseSensitive
+ ? declaringQualification
+ : CharOperation.toLowerCase(declaringQualification);
+ this.declaringSimpleName =
+ isCaseSensitive
+ ? declaringSimpleName
+ : CharOperation.toLowerCase(declaringSimpleName);
+ this.typeQualification =
+ isCaseSensitive
+ ? typeQualification
+ : CharOperation.toLowerCase(typeQualification);
+ this.typeSimpleName =
+ isCaseSensitive ? typeSimpleName : CharOperation.toLowerCase(typeSimpleName);
+
+ this.needsResolve = this.needsResolve();
+ }
+
+ public void decodeIndexEntry(IEntryResult entryResult) {
+
+ char[] word = entryResult.getWord();
+ decodedName = CharOperation.subarray(word, FIELD_DECL.length, word.length);
+ }
+
+ /**
+ * see SearchPattern.feedIndexRequestor
+ */
+ public void feedIndexRequestor(
+ IIndexSearchRequestor requestor,
+ int detailLevel,
+ int[] references,
+ IndexInput input,
+ IJavaSearchScope scope)
+ throws IOException {
+ for (int i = 0, max = references.length; i < max; i++) {
+ IndexedFile file = input.getIndexedFile(references[i]);
+ String path;
+ if (file != null
+ && scope.encloses(path = IndexedFile.convertPath(file.getPath()))) {
+ requestor.acceptFieldDeclaration(path, decodedName);
+ }
+ }
+ }
+
+ /**
+ * @see SearchPattern#indexEntryPrefix
+ */
+ public char[] indexEntryPrefix() {
+
+ return AbstractIndexer.bestFieldDeclarationPrefix(
+ name,
+ matchMode,
+ isCaseSensitive);
+ }
+
+ /**
+ * @see SearchPattern#matchContainer()
+ */
+ protected int matchContainer() {
+ return CLASS;
+ }
+
+ /**
+ * @see SearchPattern#matches(AstNode, boolean)
+ */
+ protected boolean matches(AstNode node, boolean resolve) {
+ if (!(node instanceof FieldDeclaration))
+ return false;
+
+ FieldDeclaration field = (FieldDeclaration) node;
+ if (!field.isField())
+ return false; // ignore field initializers
+
+ // field name
+ if (!this.matchesName(this.name, field.name))
+ return false;
+
+ // declaring type
+ FieldBinding binding = field.binding;
+ if (resolve && binding != null) {
+ ReferenceBinding declaringBinding = binding.declaringClass;
+ if (declaringBinding != null
+ && !this.matchesType(
+ this.declaringSimpleName,
+ this.declaringQualification,
+ declaringBinding))
+ return false;
+ }
+
+ // field type
+ if (this.typeQualification == null) {
+ TypeReference fieldType = field.type;
+ char[][] fieldTypeName = fieldType.getTypeName();
+ char[] sourceName =
+ this.toArrayName(
+ fieldTypeName[fieldTypeName.length - 1],
+ fieldType.dimensions());
+ if (!this.matchesName(this.typeSimpleName, sourceName))
+ return false;
+ } else {
+ if (resolve
+ && binding != null
+ && !this.matchesType(this.typeSimpleName, this.typeQualification, binding.type))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @see SearchPattern#matches(Binding)
+ */
+ public boolean matches(Binding binding) {
+ if (!(binding instanceof FieldBinding))
+ return false;
+
+ FieldBinding field = (FieldBinding) binding;
+
+ // field name
+ if (!this.matchesName(this.name, field.readableName()))
+ return false;
+
+ // declaring type
+ ReferenceBinding declaringBinding = field.declaringClass;
+ if (declaringBinding != null
+ && !this.matchesType(
+ this.declaringSimpleName,
+ this.declaringQualification,
+ declaringBinding)) {
+
+ return false;
+ }
+
+ // field type
+ if (!this
+ .matchesType(this.typeSimpleName, this.typeQualification, field.type)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @see SearchPattern#matchesBinary(Object, Object)
+ */
+ public boolean matchesBinary(Object binaryInfo, Object enclosingBinaryInfo) {
+ if (!(binaryInfo instanceof IBinaryField))
+ return false;
+
+ IBinaryField field = (IBinaryField) binaryInfo;
+
+ // field name
+ if (!this.matchesName(this.name, field.getName()))
+ return false;
+
+ // declaring type
+ IBinaryType declaringType = (IBinaryType) enclosingBinaryInfo;
+ if (declaringType != null) {
+ char[] declaringTypeName = (char[]) declaringType.getName().clone();
+ CharOperation.replace(declaringTypeName, '/', '.');
+ if (!this
+ .matchesType(
+ this.declaringSimpleName,
+ this.declaringQualification,
+ declaringTypeName)) {
+ return false;
+ }
+ }
+
+ // field type
+ String fieldTypeSignature = new String(field.getTypeName()).replace('/', '.');
+ if (!this
+ .matchesType(
+ this.typeSimpleName,
+ this.typeQualification,
+ Signature.toString(fieldTypeSignature).toCharArray())) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @see SearchPattern#matchIndexEntry
+ */
+ protected boolean matchIndexEntry() {
+
+ /* check name matches */
+ if (name != null) {
+ switch (matchMode) {
+ case EXACT_MATCH :
+ if (!CharOperation.equals(name, decodedName, isCaseSensitive)) {
+ return false;
+ }
+ break;
+ case PREFIX_MATCH :
+ if (!CharOperation.prefixEquals(name, decodedName, isCaseSensitive)) {
+ return false;
+ }
+ break;
+ case PATTERN_MATCH :
+ if (!CharOperation.match(name, decodedName, isCaseSensitive)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns whether a method declaration or message send will need to be resolved to
+ * find out if this method pattern matches it.
+ */
+ private boolean needsResolve() {
+
+ // declaring type
+ if (declaringSimpleName != null || declaringQualification != null)
+ return true;
+
+ // return type
+ if (typeSimpleName != null || typeQualification != null)
+ return true;
+
+ return false;
+ }
+
+ public String toString() {
+
+ StringBuffer buffer = new StringBuffer(20);
+ buffer.append("FieldDeclarationPattern: ");
+ if (declaringQualification != null)
+ buffer.append(declaringQualification).append('.');
+ if (declaringSimpleName != null)
+ buffer.append(declaringSimpleName).append('.');
+ else
+ if (declaringQualification != null)
+ buffer.append("*.");
+ if (name == null) {
+ buffer.append("*");
+ } else {
+ buffer.append(name);
+ }
+ if (typeQualification != null)
+ buffer.append(" --> ").append(typeQualification).append('.');
+ else
+ if (typeSimpleName != null)
+ buffer.append(" --> ");
+ if (typeSimpleName != null)
+ buffer.append(typeSimpleName);
+ else
+ if (typeQualification != null)
+ buffer.append("*");
+ buffer.append(", ");
+ switch (matchMode) {
+ case EXACT_MATCH :
+ buffer.append("exact match, ");
+ break;
+ case PREFIX_MATCH :
+ buffer.append("prefix match, ");
+ break;
+ case PATTERN_MATCH :
+ buffer.append("pattern match, ");
+ break;
+ }
+ if (isCaseSensitive)
+ buffer.append("case sensitive");
+ else
+ buffer.append("case insensitive");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldReferencePattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldReferencePattern.java
new file mode 100644
index 0000000000..ef6fb55fa5
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldReferencePattern.java
@@ -0,0 +1,423 @@
+package org.eclipse.jdt.internal.core.search.matching;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.search.indexing.*;
+import org.eclipse.jdt.internal.core.index.impl.*;
+import org.eclipse.jdt.internal.core.search.*;
+
+import java.io.*;
+
+public class FieldReferencePattern extends MultipleSearchPattern {
+
+ // selector
+ protected char[] name;
+
+ // declaring type
+ protected char[] declaringQualification;
+ protected char[] declaringSimpleName;
+
+ // type
+ protected char[] typeQualification;
+ protected char[] typeSimpleName;
+
+ protected char[] decodedName;
+
+ private static char[][] TAGS = { FIELD_REF, REF };
+ public ReferenceBinding[] declaringTypes;
+
+ public FieldReferencePattern(
+ char[] name,
+ int matchMode,
+ boolean isCaseSensitive,
+ char[] declaringQualification,
+ char[] declaringSimpleName,
+ char[] typeQualification,
+ char[] typeSimpleName) {
+
+ super(matchMode, isCaseSensitive);
+
+ this.name = isCaseSensitive ? name : CharOperation.toLowerCase(name);
+ this.declaringQualification =
+ isCaseSensitive
+ ? declaringQualification
+ : CharOperation.toLowerCase(declaringQualification);
+ this.declaringSimpleName =
+ isCaseSensitive
+ ? declaringSimpleName
+ : CharOperation.toLowerCase(declaringSimpleName);
+ this.typeQualification =
+ isCaseSensitive
+ ? typeQualification
+ : CharOperation.toLowerCase(typeQualification);
+ this.typeSimpleName =
+ isCaseSensitive ? typeSimpleName : CharOperation.toLowerCase(typeSimpleName);
+
+ this.needsResolve = this.needsResolve();
+ }
+
+ /**
+ * Either decode ref/name, fieldRef/name
+ */
+ public void decodeIndexEntry(IEntryResult entryResult) {
+
+ char[] word = entryResult.getWord();
+ int size = word.length;
+ int tagLength = currentTag.length;
+ int nameLength = CharOperation.indexOf(SEPARATOR, word, tagLength);
+ if (nameLength < 0)
+ nameLength = size;
+ decodedName = CharOperation.subarray(word, tagLength, nameLength);
+ }
+
+ /**
+ * see SearchPattern.feedIndexRequestor
+ */
+ public void feedIndexRequestor(
+ IIndexSearchRequestor requestor,
+ int detailLevel,
+ int[] references,
+ IndexInput input,
+ IJavaSearchScope scope)
+ throws IOException {
+ if (currentTag == REF) {
+ foundAmbiguousIndexMatches = true;
+ }
+ for (int i = 0, max = references.length; i < max; i++) {
+ int reference = references[i];
+ if (reference != -1) { // if the reference has not been eliminated
+ IndexedFile file = input.getIndexedFile(reference);
+ String path;
+ if (file != null
+ && scope.encloses(path = IndexedFile.convertPath(file.getPath()))) {
+ requestor.acceptFieldReference(path, decodedName);
+ }
+ }
+ }
+ }
+
+ protected char[][] getPossibleTags() {
+ return TAGS;
+ }
+
+ /**
+ * @see AndPattern#hasNextQuery
+ */
+ protected boolean hasNextQuery() {
+ return false;
+ }
+
+ /**
+ * see SearchPattern.indexEntryPrefix()
+ */
+ public char[] indexEntryPrefix() {
+
+ return AbstractIndexer.bestReferencePrefix(
+ currentTag,
+ name,
+ matchMode,
+ isCaseSensitive);
+ }
+
+ /**
+ * @see SearchPattern#matchContainer()
+ */
+ protected int matchContainer() {
+ return METHOD | FIELD;
+ }
+
+ /**
+ * @see SearchPattern#matches(AstNode, boolean)
+ */
+ protected boolean matches(AstNode node, boolean resolve) {
+ if (node instanceof FieldReference) {
+ return this.matches((FieldReference) node, resolve);
+ } else
+ if (node instanceof NameReference) {
+ return this.matches((NameReference) node, resolve);
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether this field reference pattern matches the given field reference.
+ * Look at resolved information only if specified.
+ */
+ private boolean matches(FieldReference fieldRef, boolean resolve) {
+ // field name
+ if (!this.matchesName(this.name, fieldRef.token))
+ return false;
+
+ if (resolve) {
+ // declaring type and field type
+ FieldBinding binding = fieldRef.binding;
+ if (binding != null && !this.matches(binding))
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns whether this field reference pattern matches the given name reference.
+ * Look at resolved information only if specified.
+ */
+ private boolean matches(NameReference nameRef, boolean resolve) {
+ // field name
+ boolean nameMatch = true;
+ if (this.name != null) {
+ if (nameRef instanceof SingleNameReference) {
+ nameMatch = matchesName(this.name, ((SingleNameReference) nameRef).token);
+ } else { // QualifiedNameReference
+ nameMatch = false;
+ QualifiedNameReference qNameRef = (QualifiedNameReference) nameRef;
+ char[][] tokens = qNameRef.tokens;
+ for (int i = qNameRef.indexOfFirstFieldBinding - 1, max = tokens.length;
+ i < max && !nameMatch;
+ i++) {
+ if (i >= 0)
+ nameMatch = matchesName(this.name, tokens[i]);
+ }
+ }
+ }
+ if (!nameMatch)
+ return false;
+
+ if (resolve) {
+ Binding binding = nameRef.binding;
+ if (binding != null) {
+ if (nameRef instanceof SingleNameReference) {
+ if (binding instanceof FieldBinding) {
+ if (!this.matches((FieldBinding) binding)) {
+ return false;
+ }
+ } else {
+ return false; // must be a field binding
+ }
+ } else { // QualifiedNameReference
+ QualifiedNameReference qNameRef = (QualifiedNameReference) nameRef;
+ if (!(binding instanceof FieldBinding && matches((FieldBinding) binding))) {
+ boolean otherMatch = false;
+ int otherMax =
+ qNameRef.otherBindings == null ? 0 : qNameRef.otherBindings.length;
+ for (int i = 0; i < otherMax && !otherMatch; i++) {
+ otherMatch = matches(qNameRef.otherBindings[i]);
+ }
+ if (!otherMatch)
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns whether this field reference pattern matches the given field binding.
+ * Look at declaring type and filed type.
+ */
+ private boolean matches(FieldBinding binding) {
+ // declaring type
+ ReferenceBinding declaringBinding = binding.declaringClass;
+ if (declaringBinding != null
+ && !this.matchesType(
+ this.declaringSimpleName,
+ this.declaringQualification,
+ declaringBinding)
+ && !this.matchesAsSubtype(this.declaringTypes, declaringBinding)) {
+ return false;
+ }
+
+ // field type
+ if (!this
+ .matchesType(this.typeSimpleName, this.typeQualification, binding.type))
+ return false;
+
+ return true;
+ }
+
+ /**
+ * @see SearchPattern#matchIndexEntry
+ */
+ protected boolean matchIndexEntry() {
+
+ /* check name matches */
+ if (name != null) {
+ switch (matchMode) {
+ case EXACT_MATCH :
+ if (!CharOperation.equals(name, decodedName, isCaseSensitive)) {
+ return false;
+ }
+ break;
+ case PREFIX_MATCH :
+ if (!CharOperation.prefixEquals(name, decodedName, isCaseSensitive)) {
+ return false;
+ }
+ break;
+ case PATTERN_MATCH :
+ if (!CharOperation.match(name, decodedName, isCaseSensitive)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Finds out whether the given ast node matches this search pattern.
+ * Returns IMPOSSIBLE_MATCH if it doesn't.
+ * Returns TRUSTED_MATCH if it matches exactly this search pattern (ie.
+ * it doesn't need to be resolved or it has already been resolved.)
+ * Returns POSSIBLE_MATCH if it potentially matches
+ * this search pattern and it needs to be resolved to get more information.
+ */
+ public int matchLevel(AstNode node) {
+ if (this.matches(node, false)) {
+ if (this.needsResolve
+ || node instanceof NameReference) { // ensure it is a field
+ return POSSIBLE_MATCH;
+ } else {
+ return TRUSTED_MATCH;
+ }
+ }
+ return IMPOSSIBLE_MATCH;
+ }
+
+ /**
+ * @see SearchPattern#matchReportReference
+ */
+ protected void matchReportReference(
+ AstNode reference,
+ IJavaElement element,
+ int accuracy,
+ MatchLocator locator)
+ throws CoreException {
+ char[] declaringTypeName =
+ CharOperation.concat(
+ this.declaringQualification,
+ this.declaringSimpleName,
+ '.');
+ char[][] qualifiedName =
+ CharOperation.splitOn(
+ '.',
+ CharOperation.concat(declaringTypeName, this.name, '.'));
+ locator.reportQualifiedReference(
+ reference.sourceStart,
+ reference.sourceEnd,
+ qualifiedName,
+ element,
+ accuracy);
+ }
+
+ /**
+ * Returns whether a method declaration or message send will need to be resolved to
+ * find out if this method pattern matches it.
+ */
+ private boolean needsResolve() {
+
+ // declaring type
+ if (declaringSimpleName != null || declaringQualification != null)
+ return true;
+
+ // return type
+ if (typeSimpleName != null || typeQualification != null)
+ return true;
+
+ return false;
+ }
+
+ /**
+ * @see AndPattern#resetQuery
+ */
+ protected void resetQuery() {
+ }
+
+ public String toString() {
+
+ StringBuffer buffer = new StringBuffer(20);
+ buffer.append("FieldReferencePattern: ");
+ if (declaringQualification != null)
+ buffer.append(declaringQualification).append('.');
+ if (declaringSimpleName != null)
+ buffer.append(declaringSimpleName).append('.');
+ else
+ if (declaringQualification != null)
+ buffer.append("*.");
+ if (name != null) {
+ buffer.append(name);
+ } else {
+ buffer.append("*");
+ }
+ if (typeQualification != null)
+ buffer.append(" --> ").append(typeQualification).append('.');
+ else
+ if (typeSimpleName != null)
+ buffer.append(" --> ");
+ if (typeSimpleName != null)
+ buffer.append(typeSimpleName);
+ else
+ if (typeQualification != null)
+ buffer.append("*");
+ buffer.append(", ");
+ switch (matchMode) {
+ case EXACT_MATCH :
+ buffer.append("exact match, ");
+ break;
+ case PREFIX_MATCH :
+ buffer.append("prefix match, ");
+ break;
+ case PATTERN_MATCH :
+ buffer.append("pattern match, ");
+ break;
+ }
+ if (isCaseSensitive)
+ buffer.append("case sensitive");
+ else
+ buffer.append("case insensitive");
+ return buffer.toString();
+ }
+
+ public boolean initializeFromLookupEnvironment(LookupEnvironment env) {
+
+ char[][] declaringTypeName = null;
+ if ((this.declaringQualification != null)
+ && (this.declaringSimpleName != null)
+ && (this.matchMode == EXACT_MATCH)) {
+ char[][] qualification =
+ CharOperation.splitOn('.', this.declaringQualification);
+ declaringTypeName =
+ CharOperation.arrayConcat(qualification, this.declaringSimpleName);
+ }
+ if (declaringTypeName != null) {
+ for (int i = 0, max = declaringTypeName.length; i < max; i++) {
+ ReferenceBinding matchingDeclaringType = env.getCachedType(declaringTypeName);
+ if (matchingDeclaringType != null && matchingDeclaringType.isValidBinding()) {
+ this.declaringTypes = new ReferenceBinding[] { matchingDeclaringType };
+ return true;
+ }
+ // if nothing is in the cache, it could have been a member type (A.B.C.D --> A.B.C$D)
+ int last = declaringTypeName.length - 1;
+ if (last == 0)
+ break;
+ declaringTypeName[last - 1] =
+ CharOperation.concat(declaringTypeName[last - 1], declaringTypeName[last], '$');
+ // try nested type
+ declaringTypeName = CharOperation.subarray(declaringTypeName, 0, last);
+ }
+ return false;
+ }
+ return false;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
new file mode 100644
index 0000000000..cb5b14f416
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
@@ -0,0 +1,891 @@
+package org.eclipse.jdt.internal.core.search.matching;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.core.resources.*;
+
+import java.io.*;
+import java.util.*;
+import java.util.zip.ZipFile;
+
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.impl.ITypeRequestor;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.parser.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+
+import org.eclipse.jdt.core.IField;
+import org.eclipse.jdt.core.IMember;
+import org.eclipse.jdt.core.IImportDeclaration;
+import org.eclipse.jdt.core.IInitializer;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.IJavaModelStatusConstants;
+import org.eclipse.jdt.core.IMethod;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.ISourceRange;
+import org.eclipse.jdt.core.Signature;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.internal.core.ClassFile;
+import org.eclipse.jdt.internal.core.*;
+
+import org.eclipse.jdt.core.search.IJavaSearchResultCollector;
+import org.eclipse.jdt.core.search.IJavaSearchScope;
+
+/**
+ * Locate matches in compilation units.
+ */
+public class MatchLocator implements ITypeRequestor {
+ public SearchPattern pattern;
+ public int detailLevel;
+ public IJavaSearchResultCollector collector;
+ public IJavaSearchScope scope;
+
+ private MatchLocatorParser parser;
+ private LookupEnvironment lookupEnvironment;
+ private IResource currentResource;
+ private Openable currentOpenable;
+ public MatchLocator(
+ SearchPattern pattern,
+ int detailLevel,
+ IJavaSearchResultCollector collector,
+ IJavaSearchScope scope) {
+
+ this.pattern = pattern;
+ this.detailLevel = detailLevel;
+ this.collector = collector;
+ this.scope = scope;
+ }
+
+ /**
+ * Add an additional binary type
+ */
+ public void accept(IBinaryType binaryType, PackageBinding packageBinding) {
+ this.lookupEnvironment.createBinaryTypeFrom(binaryType, packageBinding);
+ }
+
+ /**
+ * Add an additional compilation unit.
+ */
+ public void accept(ICompilationUnit sourceUnit) {
+ CompilationResult result = new CompilationResult(sourceUnit, 1, 1);
+ CompilationUnitDeclaration parsedUnit =
+ this.parser.dietParse(sourceUnit, result);
+
+ this.lookupEnvironment.buildTypeBindings(parsedUnit);
+ this.lookupEnvironment.completeTypeBindings(parsedUnit, true);
+ }
+
+ /**
+ * Add an additional source type
+ */
+ public void accept(ISourceType sourceType, PackageBinding packageBinding) {
+ CompilationResult result =
+ new CompilationResult(sourceType.getFileName(), 1, 1);
+ // need to hold onto this
+ CompilationUnitDeclaration unit =
+ SourceTypeConverter.buildCompilationUnit(
+ sourceType,
+ true,
+ true,
+ lookupEnvironment.problemReporter,
+ result);
+
+ if (unit != null) {
+ this.lookupEnvironment.buildTypeBindings(unit);
+ this.lookupEnvironment.completeTypeBindings(unit, true);
+ }
+ }
+
+ /**
+ * Creates an IField from the given field declaration and simple type names.
+ */
+ private IField createFieldHandle(
+ FieldDeclaration field,
+ char[][] definingTypeNames) {
+ IType type = this.createTypeHandle(definingTypeNames);
+ return type.getField(new String(field.name));
+ }
+
+ /**
+ * Creates an IImportDeclaration from the given import statement
+ */
+ private IImportDeclaration createImportHandle(ImportReference importRef) {
+ char[] importName = CharOperation.concatWith(importRef.getImportName(), '.');
+ if (importRef.onDemand) {
+ importName = CharOperation.concat(importName, ".*".toCharArray());
+ }
+ return ((CompilationUnit) this.currentOpenable).getImport(
+ new String(importName));
+ }
+
+ /**
+ * Creates an IInitializer from the given field declaration and simple type names.
+ */
+ private IInitializer createInitializerHandle(
+ TypeDeclaration typeDecl,
+ FieldDeclaration initializer,
+ char[][] definingTypeNames) {
+ IType type = this.createTypeHandle(definingTypeNames);
+
+ // find occurence count of the given initializer in its type declaration
+ int occurrenceCount = 0;
+ FieldDeclaration[] fields = typeDecl.fields;
+ for (int i = 0, length = fields.length; i < length; i++) {
+ FieldDeclaration field = fields[i];
+ if (!field.isField()) {
+ occurrenceCount++;
+ if (field.equals(initializer)) {
+ break;
+ }
+ }
+ }
+
+ return type.getInitializer(occurrenceCount);
+ }
+
+ /**
+ * Creates an IMethod from the given method declaration and simple type names.
+ */
+ private IMethod createMethodHandle(
+ AbstractMethodDeclaration method,
+ char[][] definingTypeNames) {
+ IType type = this.createTypeHandle(definingTypeNames);
+ Argument[] arguments = method.arguments;
+ int length = arguments == null ? 0 : arguments.length;
+ String[] parameterTypeSignatures = new String[length];
+ for (int i = 0; i < length; i++) {
+ TypeReference parameterType = arguments[i].type;
+ char[] typeName = CharOperation.concatWith(parameterType.getTypeName(), '.');
+ for (int j = 0; j < parameterType.dimensions(); j++) {
+ typeName = CharOperation.concat(typeName, "[]".toCharArray());
+ }
+ parameterTypeSignatures[i] = Signature.createTypeSignature(typeName, false);
+ }
+ return type.getMethod(new String(method.selector), parameterTypeSignatures);
+ }
+
+ /**
+ * Creates an IType from the given simple type names.
+ */
+ private IType createTypeHandle(char[][] simpleTypeNames) {
+ // creates compilation unit
+ CompilationUnit unit = (CompilationUnit) this.currentOpenable;
+
+ // create type
+ int length = simpleTypeNames.length;
+ IType type = unit.getType(new String(simpleTypeNames[0]));
+ for (int i = 1; i < length; i++) {
+ type = type.getType(new String(simpleTypeNames[i]));
+ }
+ return type;
+ }
+
+ private char[] getContents(IFile file) {
+ BufferedInputStream input = null;
+ try {
+ input = new BufferedInputStream(file.getContents(true));
+ StringBuffer buffer = new StringBuffer();
+ int nextChar = input.read();
+ while (nextChar != -1) {
+ buffer.append((char) nextChar);
+ nextChar = input.read();
+ }
+ int length = buffer.length();
+ char[] result = new char[length];
+ buffer.getChars(0, length, result, 0);
+ return result;
+ } catch (IOException e) {
+ return null;
+ } catch (CoreException e) {
+ return null;
+ } finally {
+ if (input != null) {
+ try {
+ input.close();
+ } catch (IOException e) {
+ // nothing can be done if the file cannot be closed
+ }
+ }
+ }
+ }
+
+ protected IResource getCurrentResource() {
+ return this.currentResource;
+ }
+
+ protected Scanner getScanner() {
+ return this.parser == null ? null : this.parser.scanner;
+ }
+
+ /**
+ * Locate the matches in the given files and report them using the search requestor.
+ */
+ public void locateMatches(String[] filePaths, IWorkspace workspace)
+ throws JavaModelException {
+ Util.sort(filePaths); // sort by projects
+ JavaModelManager manager = JavaModelManager.getJavaModelManager();
+ HandleFactory factory = new HandleFactory(workspace.getRoot(), manager);
+ JavaProject previousJavaProject = null;
+ int length = filePaths.length;
+ double increment = 100.0 / length;
+ double totalWork = 0;
+ int lastProgress = 0;
+ boolean couldInitializePattern = false;
+ for (int i = 0; i < length; i++) {
+ IProgressMonitor monitor = this.collector.getProgressMonitor();
+ if (monitor != null && monitor.isCanceled()) {
+ throw new OperationCanceledException();
+ }
+ String pathString = filePaths[i];
+ this.currentOpenable = factory.createOpenable(pathString);
+ if (this.currentOpenable == null)
+ continue; // match is outside classpath
+
+ // create new parser and lookup environment if this is a new project
+ try {
+ JavaProject javaProject = (JavaProject) this.currentOpenable.getJavaProject();
+ this.currentResource = this.currentOpenable.getUnderlyingResource();
+ if (this.currentResource == null) { // case of a file in an external jar
+ this.currentResource = javaProject.getProject();
+ }
+ if (!javaProject.equals(previousJavaProject)) {
+ // create parser for this project
+ couldInitializePattern = this.createParser(javaProject);
+ previousJavaProject = javaProject;
+ }
+ if (!couldInitializePattern)
+ continue;
+ // the pattern could not be initialized: the match cannot be in this project
+ } catch (JavaModelException e) {
+ // file doesn't exist -> skip it
+ continue;
+ }
+
+ // locate matches in current file and report them
+ try {
+ if (this.currentOpenable instanceof CompilationUnit) {
+ this.locateMatchesInCompilationUnit();
+ } else
+ if (this.currentOpenable instanceof org.eclipse.jdt.internal.core.ClassFile) {
+ this.locateMatchesInClassFile();
+ }
+ } catch (AbortCompilation e) {
+ // problem with class path: it could not find base classes
+ throw new JavaModelException(
+ e,
+ IJavaModelStatusConstants.BUILDER_INITIALIZATION_ERROR);
+ } catch (CoreException e) {
+ if (e instanceof JavaModelException) {
+ throw (JavaModelException) e;
+ } else {
+ throw new JavaModelException(e);
+ }
+ }
+ if (monitor != null) {
+ totalWork = totalWork + increment;
+ int worked = (int) totalWork - lastProgress;
+ monitor.worked(worked);
+ lastProgress = (int) totalWork;
+ }
+ }
+ }
+
+ /**
+ * Locate declaration in the current class file. This class file is always in a jar.
+ */
+ private void locateMatchesInClassFile()
+ throws CoreException, JavaModelException {
+ org.eclipse.jdt.internal.core.ClassFile classFile =
+ (org.eclipse.jdt.internal.core.ClassFile) this.currentOpenable;
+ BinaryType binaryType = (BinaryType) classFile.getType();
+ IBinaryType info;
+ if (classFile.isOpen()) {
+ // reuse the info from the java model cache
+ info = (IBinaryType) binaryType.getRawInfo();
+ } else {
+ // create a temporary info
+ try {
+ IJavaElement pkg = classFile.getParent();
+ PackageFragmentRoot root = (PackageFragmentRoot) pkg.getParent();
+ if (root.isArchive()) {
+ // class file in a jar
+ String pkgPath = pkg.getElementName().replace('.', '/');
+ String classFilePath =
+ (pkgPath.length() > 0)
+ ? pkgPath + "/" + classFile.getElementName()
+ : classFile.getElementName();
+ ZipFile zipFile = null;
+ try {
+ zipFile = ((JarPackageFragmentRoot) root).getJar();
+ info =
+ org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader.read(
+ zipFile,
+ classFilePath);
+ } finally {
+ if (zipFile != null) {
+ try {
+ zipFile.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+ } else {
+ // class file in a directory
+ String osPath = this.currentResource.getFullPath().toOSString();
+ info = org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader.read(osPath);
+ }
+ } catch (org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException e) {
+ e.printStackTrace();
+ return;
+ } catch (java.io.IOException e) {
+ throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
+ }
+
+ }
+
+ // check class definition
+ if (this.pattern.matchesBinary(info, null)) {
+ this.reportBinaryMatch(
+ binaryType,
+ info,
+ IJavaSearchResultCollector.EXACT_MATCH);
+ }
+
+ boolean compilationAborted = false;
+ if (this.pattern.needsResolve) {
+ // resolve
+ BinaryTypeBinding binding = null;
+ try {
+ binding = this.lookupEnvironment.cacheBinaryType(info);
+ if (binding == null) {
+ // it was already cached as a result of a previous query
+ char[][] compoundName =
+ CharOperation.splitOn('.', binaryType.getFullyQualifiedName().toCharArray());
+ ReferenceBinding referenceBinding =
+ this.lookupEnvironment.getCachedType(compoundName);
+ if (referenceBinding != null
+ && (referenceBinding instanceof BinaryTypeBinding)) {
+ // if the binding could be found and if it comes from a source type,
+ binding = (BinaryTypeBinding) referenceBinding;
+ }
+ }
+
+ // check methods
+ if (binding != null) {
+ MethodBinding[] methods = binding.methods();
+ for (int i = 0; i < methods.length; i++) {
+ MethodBinding method = methods[i];
+ if (this.pattern.matches(method)) {
+ IMethod methodHandle =
+ binaryType.getMethod(
+ new String(
+ method.isConstructor()
+ ? binding.compoundName[binding.compoundName.length - 1]
+ : method.selector),
+ Signature.getParameterTypes(new String(method.signature()).replace('/', '.')));
+ this.reportBinaryMatch(
+ methodHandle,
+ info,
+ IJavaSearchResultCollector.EXACT_MATCH);
+ }
+ }
+ }
+
+ // check fields
+ if (binding != null) {
+ FieldBinding[] fields = binding.fields();
+ for (int i = 0; i < fields.length; i++) {
+ FieldBinding field = fields[i];
+ if (this.pattern.matches(field)) {
+ IField fieldHandle = binaryType.getField(new String(field.name));
+ this.reportBinaryMatch(
+ fieldHandle,
+ info,
+ IJavaSearchResultCollector.EXACT_MATCH);
+ }
+ }
+ }
+ } catch (AbortCompilation e) {
+ binding = null;
+ }
+
+ // no need to check binary info if resolve was successful
+ compilationAborted = binding == null;
+ if (!compilationAborted)
+ return;
+ }
+
+ // if compilation was aborted it is a problem with the class path:
+ // report as a potential match if binary info matches the pattern
+ int accuracy =
+ compilationAborted
+ ? IJavaSearchResultCollector.POTENTIAL_MATCH
+ : IJavaSearchResultCollector.EXACT_MATCH;
+
+ // check methods
+ IBinaryMethod[] methods = info.getMethods();
+ int length = methods == null ? 0 : methods.length;
+ for (int i = 0; i < length; i++) {
+ IBinaryMethod method = methods[i];
+ if (this.pattern.matchesBinary(method, info)) {
+ IMethod methodHandle =
+ binaryType.getMethod(
+ new String(method.isConstructor() ? info.getName() : method.getSelector()),
+ Signature.getParameterTypes(
+ new String(method.getMethodDescriptor()).replace('/', '.')));
+ this.reportBinaryMatch(methodHandle, info, accuracy);
+ }
+ }
+
+ // check fields
+ IBinaryField[] fields = info.getFields();
+ length = fields == null ? 0 : fields.length;
+ for (int i = 0; i < length; i++) {
+ IBinaryField field = fields[i];
+ if (this.pattern.matchesBinary(field, info)) {
+ IField fieldHandle = binaryType.getField(new String(field.getName()));
+ this.reportBinaryMatch(fieldHandle, info, accuracy);
+ }
+ }
+ }
+
+ private void locateMatchesInCompilationUnit() throws CoreException {
+ // get source
+ final char[] source = getContents((IFile) this.currentResource);
+
+ // get main type name
+ String pathString = this.currentResource.toString();
+ int lastDot = pathString.lastIndexOf('/');
+ // remove folder path and extension ".java"
+ final char[] mainTypeName =
+ pathString.substring(lastDot + 1, pathString.length() - 5).toCharArray();
+
+ // parse
+ ICompilationUnit sourceUnit = new ICompilationUnit() {
+ public char[] getContents() {
+ return source;
+ }
+ public char[] getFileName() {
+ return MatchLocator.this.currentResource.getName().toCharArray();
+ }
+ public char[] getMainTypeName() {
+ return mainTypeName;
+ }
+ };
+ MatchSet set = new MatchSet(this);
+ this.parser.matchSet = set;
+ CompilationResult compilationResult = new CompilationResult(sourceUnit, 0, 0);
+ CompilationUnitDeclaration parsedUnit =
+ this.parser.parse(sourceUnit, compilationResult);
+
+ if (parsedUnit != null) {
+ // report matches that don't need resolve
+ set.cuHasBeenResolved = false;
+ set.accuracy = IJavaSearchResultCollector.EXACT_MATCH;
+ set.reportMatching(parsedUnit);
+
+ // resolve if needed
+ if (set.needsResolve()) {
+ if (parsedUnit.types != null) {
+ /**
+ * First approximation: reset the lookup environment -> this will recreate the bindings for the current CU
+ * Optimization: the binding resolution should be done for all compilation units at once
+ */
+ this.lookupEnvironment.reset();
+
+ try {
+ lookupEnvironment.buildTypeBindings(parsedUnit);
+ if (parsedUnit.scope != null) {
+ lookupEnvironment.completeTypeBindings(parsedUnit, true);
+ parsedUnit.scope.faultInTypes();
+ parsedUnit.resolve();
+ this.pattern.initializeFromLookupEnvironment(this.lookupEnvironment);
+ }
+ // report matches that needed resolve
+ set.cuHasBeenResolved = true;
+ set.accuracy = IJavaSearchResultCollector.EXACT_MATCH;
+ set.reportMatching(parsedUnit);
+ } catch (AbortCompilation e) {
+ // could not resolve (reasons include "could not find library class") -> ignore and report the unresolved nodes
+ set.cuHasBeenResolved = false;
+ set.accuracy = IJavaSearchResultCollector.POTENTIAL_MATCH;
+ set.reportMatching(parsedUnit);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Locates the package declarations corresponding to this locator's pattern.
+ */
+ public void locatePackageDeclarations(IWorkspace workspace)
+ throws JavaModelException {
+ this.locatePackageDeclarations(this.pattern, workspace);
+ }
+
+ /**
+ * Locates the package declarations corresponding to the search pattern.
+ */
+ private void locatePackageDeclarations(
+ SearchPattern searchPattern,
+ IWorkspace workspace)
+ throws JavaModelException {
+ if (searchPattern instanceof OrPattern) {
+ OrPattern orPattern = (OrPattern) searchPattern;
+ this.locatePackageDeclarations(orPattern.leftPattern, workspace);
+ this.locatePackageDeclarations(orPattern.rightPattern, workspace);
+ } else
+ if (searchPattern instanceof PackageDeclarationPattern) {
+ PackageDeclarationPattern pkgPattern =
+ (PackageDeclarationPattern) searchPattern;
+ String pkgName = new String(pkgPattern.pkgName);
+ IJavaProject[] projects =
+ JavaModelManager.getJavaModel(workspace).getJavaProjects();
+ for (int i = 0, length = projects.length; i < length; i++) {
+ IJavaProject javaProject = projects[i];
+ IPackageFragmentRoot[] roots = javaProject.getPackageFragmentRoots();
+ for (int j = 0, rootsLength = roots.length; j < rootsLength; j++) {
+ IJavaElement[] pkgs = roots[j].getChildren();
+ for (int k = 0, pksLength = pkgs.length; k < pksLength; k++) {
+ IJavaElement pkg = pkgs[k];
+ if (pkgPattern
+ .matchesName(pkgPattern.pkgName, pkg.getElementName().toCharArray())) {
+ this.currentResource = pkg.getUnderlyingResource();
+ if (this.currentResource == null) { // case of a file in an external jar
+ this.currentResource = javaProject.getProject();
+ }
+ try {
+ this.report(-1, -2, pkg, IJavaSearchResultCollector.EXACT_MATCH);
+ } catch (CoreException e) {
+ if (e instanceof JavaModelException) {
+ throw (JavaModelException) e;
+ } else {
+ throw new JavaModelException(e);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public void report(
+ int sourceStart,
+ int sourceEnd,
+ IJavaElement element,
+ int accuracy)
+ throws CoreException {
+ if (this.scope.encloses(element)) {
+ this.collector.accept(
+ this.currentResource,
+ sourceStart,
+ sourceEnd + 1,
+ element,
+ accuracy);
+ }
+ }
+
+ private void reportBinaryMatch(
+ IMember binaryMember,
+ IBinaryType info,
+ int accuracy)
+ throws CoreException, JavaModelException {
+ ISourceRange range = binaryMember.getNameRange();
+ if (range.getOffset() == -1) {
+ ClassFile classFile = (ClassFile) binaryMember.getClassFile();
+ SourceMapper mapper = classFile.getSourceMapper();
+ if (mapper != null) {
+ IType type = classFile.getType();
+ char[] contents = mapper.findSource(type, info);
+ if (contents != null) {
+ range = mapper.mapSource(type, contents, binaryMember);
+ }
+ }
+ }
+ int startIndex = range.getOffset();
+ int endIndex = startIndex + range.getLength() - 1;
+ this.report(startIndex, endIndex, binaryMember, accuracy);
+ }
+
+ /**
+ * Reports the given field declaration to the search requestor.
+ * Its defining types have the given simple names.
+ */
+ public void reportFieldDeclaration(
+ FieldDeclaration fieldDeclaration,
+ char[][] definingTypeNames,
+ int accuracy)
+ throws CoreException {
+
+ // create field handle
+ IType type = this.createTypeHandle(definingTypeNames);
+ IField field = type.getField(new String(fieldDeclaration.name));
+
+ // accept field declaration
+ this.report(
+ fieldDeclaration.sourceStart,
+ fieldDeclaration.sourceEnd,
+ field,
+ accuracy);
+ }
+
+ /**
+ * Reports the given import to the search requestor.
+ */
+ public void reportImport(ImportReference reference, int accuracy)
+ throws CoreException {
+
+ // create defining import handle
+ IImportDeclaration importHandle = this.createImportHandle(reference);
+
+ // accept reference
+ this.pattern.matchReportReference(reference, importHandle, accuracy, this);
+ }
+
+ /**
+ * Reports the given method declaration to the search requestor.
+ * Its defining types have the given simple names.
+ */
+ public void reportMethodDeclaration(
+ AbstractMethodDeclaration methodDeclaration,
+ char[][] definingTypeNames,
+ int accuracy)
+ throws CoreException {
+
+ // create method handle
+ IMethod method = this.createMethodHandle(methodDeclaration, definingTypeNames);
+
+ // compute source positions of the selector
+ Scanner scanner = parser.scanner;
+ int nameSourceStart = methodDeclaration.sourceStart;
+ scanner.resetTo(nameSourceStart, methodDeclaration.sourceEnd);
+ try {
+ scanner.getNextToken();
+ } catch (InvalidInputException e) {
+ }
+ int nameSourceEnd = scanner.currentPosition - 1;
+
+ // accept method declaration
+ this.report(nameSourceStart, nameSourceEnd, method, accuracy);
+ }
+
+ /**
+ * Reports the given package declaration to the search requestor.
+ */
+ public void reportPackageDeclaration(ImportReference node) {
+ // TBD
+ }
+
+ /**
+ * Reports the given package reference to the search requestor.
+ */
+ public void reportPackageReference(ImportReference node) {
+ // TBD
+ }
+
+ /**
+ * Reports the given qualified reference to the search requestor.
+ */
+ public void reportQualifiedReference(
+ int sourceStart,
+ int sourceEnd,
+ char[][] qualifiedName,
+ IJavaElement element,
+ int accuracy)
+ throws CoreException {
+
+ // compute source positions of the qualified reference
+ Scanner scanner = parser.scanner;
+ scanner.resetTo(sourceStart, sourceEnd);
+
+ int refSourceStart = -1, refSourceEnd = -1;
+ int tokenNumber = qualifiedName.length;
+ int token = -1;
+ int previousValid = -1;
+ int i = 0;
+ do {
+ int currentPosition = scanner.currentPosition;
+ // read token
+ try {
+ token = scanner.getNextToken();
+ } catch (InvalidInputException e) {
+ }
+ if (token != TerminalSymbols.TokenNameEOF) {
+ char[] currentTokenSource = scanner.getCurrentTokenSource();
+ while (i < tokenNumber
+ && !CharOperation.equals(currentTokenSource, qualifiedName[i++])) {
+ }
+ if (CharOperation.equals(currentTokenSource, qualifiedName[i - 1])
+ && (previousValid == -1 || previousValid == i - 2)) {
+ previousValid = i - 1;
+ if (refSourceStart == -1) {
+ refSourceStart = currentPosition;
+ }
+ refSourceEnd = scanner.currentPosition - 1;
+ } else {
+ i = 0;
+ refSourceStart = -1;
+ previousValid = -1;
+ }
+ // read '.'
+ try {
+ token = scanner.getNextToken();
+ } catch (InvalidInputException e) {
+ }
+ }
+ }
+ while (token != TerminalSymbols.TokenNameEOF && i < tokenNumber);
+
+ // accept method declaration
+ if (refSourceStart != -1) {
+ this.report(refSourceStart, refSourceEnd, element, accuracy);
+ } else {
+ this.report(sourceStart, sourceEnd, element, accuracy);
+ }
+ }
+
+ /**
+ * Reports the given reference to the search requestor.
+ * It is done in the given method and the method's defining types
+ * have the given simple names.
+ */
+ public void reportReference(
+ AstNode reference,
+ AbstractMethodDeclaration methodDeclaration,
+ char[][] definingTypeNames,
+ int accuracy)
+ throws CoreException {
+
+ // create defining method handle
+ IMethod method = this.createMethodHandle(methodDeclaration, definingTypeNames);
+
+ // accept reference
+ if (reference instanceof QualifiedNameReference
+ || reference instanceof QualifiedTypeReference) {
+ this.pattern.matchReportReference((AstNode) reference, method, accuracy, this);
+ } else {
+ this.report(reference.sourceStart, reference.sourceEnd, method, accuracy);
+ }
+ }
+
+ /**
+ * Reports the given reference to the search requestor.
+ * It is done in the given field and given type.
+ * The field's defining types have the given simple names.
+ */
+ public void reportReference(
+ AstNode reference,
+ TypeDeclaration typeDeclaration,
+ FieldDeclaration fieldDeclaration,
+ char[][] definingTypeNames,
+ int accuracy)
+ throws CoreException {
+
+ if (fieldDeclaration.isField()) {
+ // create defining field handle
+ IField field = this.createFieldHandle(fieldDeclaration, definingTypeNames);
+
+ // accept reference
+ if (reference instanceof QualifiedNameReference
+ || reference instanceof QualifiedTypeReference) {
+ this.pattern.matchReportReference((AstNode) reference, field, accuracy, this);
+ } else {
+ this.report(reference.sourceStart, reference.sourceEnd, field, accuracy);
+ }
+ } else { // initializer
+ // create defining initializer
+ IInitializer initializer =
+ this.createInitializerHandle(
+ typeDeclaration,
+ fieldDeclaration,
+ definingTypeNames);
+
+ // accept reference
+ if (reference instanceof QualifiedNameReference
+ || reference instanceof QualifiedTypeReference) {
+ this.pattern.matchReportReference(
+ (AstNode) reference,
+ initializer,
+ accuracy,
+ this);
+ } else {
+ this.report(reference.sourceStart, reference.sourceEnd, initializer, accuracy);
+ }
+ }
+ }
+
+ /**
+ * Reports the given super type reference to the search requestor.
+ * It is done in the given defining type (with the given simple names).
+ */
+ public void reportSuperTypeReference(
+ TypeReference typeRef,
+ char[][] definingTypeNames,
+ int accuracy)
+ throws CoreException {
+
+ // create defining type handle
+ IType type = this.createTypeHandle(definingTypeNames);
+
+ // accept type reference
+ this.pattern.matchReportReference(typeRef, type, accuracy, this);
+ }
+
+ /**
+ * Reports the given type declaration to the search requestor.
+ * Its simple names are the names of its outer most type to this type.
+ */
+ public void reportTypeDeclaration(
+ TypeDeclaration typeDeclaration,
+ char[][] simpleTypeNames,
+ int accuracy)
+ throws CoreException {
+
+ // create type handle
+ IType type = this.createTypeHandle(simpleTypeNames);
+
+ // accept class or interface declaration
+ this.report(
+ typeDeclaration.sourceStart,
+ typeDeclaration.sourceEnd,
+ type,
+ accuracy);
+ }
+
+ /**
+ * Create a new parser for the given project, as well as a lookup environment.
+ * Asks the pattern to initialize itself from the lookup environment.
+ * Returns whether it was able to initialize the pattern.
+ */
+ private boolean createParser(JavaProject project) throws JavaModelException {
+ INameEnvironment nameEnvironment = project.getSearchableNameEnvironment();
+ IProblemFactory problemFactory = new ProblemFactory();
+
+ CompilerOptions options = new CompilerOptions(null);
+ ProblemReporter problemReporter =
+ new ProblemReporter(
+ DefaultErrorHandlingPolicies.proceedWithAllProblems(),
+ options,
+ problemFactory);
+ this.lookupEnvironment =
+ new LookupEnvironment(this, options, problemReporter, nameEnvironment);
+ this.parser = new MatchLocatorParser(problemReporter);
+ return true;
+ //this.pattern.initializeFromLookupEnvironment(this.lookupEnvironment);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocatorParser.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocatorParser.java
new file mode 100644
index 0000000000..2f36288e06
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocatorParser.java
@@ -0,0 +1,177 @@
+package org.eclipse.jdt.internal.core.search.matching;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.parser.Parser;
+import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+
+import java.util.*;
+
+/**
+ * A parser that locates ast nodes that match a given search pattern.
+ */
+public class MatchLocatorParser extends Parser {
+
+ public MatchSet matchSet;
+ public MatchLocatorParser(ProblemReporter problemReporter) {
+ super(problemReporter);
+ }
+
+ protected void classInstanceCreation(boolean alwaysQualified) {
+ super.classInstanceCreation(alwaysQualified);
+ this.matchSet.checkMatching(this.expressionStack[this.expressionPtr]);
+ }
+
+ protected void consumeExplicitConstructorInvocation(int flag, int recFlag) {
+ super.consumeExplicitConstructorInvocation(flag, recFlag);
+ this.matchSet.checkMatching(this.astStack[this.astPtr]);
+ }
+
+ protected void consumeFieldAccess(boolean isSuperAccess) {
+ super.consumeFieldAccess(isSuperAccess);
+ this.matchSet.checkMatching(this.expressionStack[this.expressionPtr]);
+ }
+
+ protected void consumeMethodInvocationName() {
+ super.consumeMethodInvocationName();
+ this.matchSet.checkMatching(this.expressionStack[this.expressionPtr]);
+ }
+
+ protected void consumeMethodInvocationPrimary() {
+ super.consumeMethodInvocationPrimary();
+ this.matchSet.checkMatching(this.expressionStack[this.expressionPtr]);
+ }
+
+ protected void consumeMethodInvocationSuper() {
+ super.consumeMethodInvocationSuper();
+ this.matchSet.checkMatching(this.expressionStack[this.expressionPtr]);
+ }
+
+ protected void consumeSingleTypeImportDeclarationName() {
+ super.consumeSingleTypeImportDeclarationName();
+ this.matchSet.checkMatching(this.astStack[this.astPtr]);
+ }
+
+ protected void consumeTypeImportOnDemandDeclarationName() {
+ super.consumeTypeImportOnDemandDeclarationName();
+ this.matchSet.checkMatching(this.astStack[this.astPtr]);
+ }
+
+ protected TypeReference getTypeReference(int dim) {
+ TypeReference typeRef = super.getTypeReference(dim);
+ this.matchSet.checkMatching(typeRef);
+ // NB: Don't check container since type reference can happen anywhere
+ return typeRef;
+ }
+
+ protected NameReference getUnspecifiedReference() {
+ NameReference nameRef = super.getUnspecifiedReference();
+ this.matchSet.checkMatching(nameRef);
+ // NB: Don't check container since unspecified reference can happen anywhere
+ return nameRef;
+ }
+
+ protected NameReference getUnspecifiedReferenceOptimized() {
+ NameReference nameRef = super.getUnspecifiedReferenceOptimized();
+ this.matchSet.checkMatching(nameRef);
+ // NB: Don't check container since unspecified reference can happen anywhere
+ return nameRef;
+ }
+
+ /**
+ * Parses the given source unit in 2 times:
+ * - first do a diet parse to determine the structure of the compilation unit
+ * - then do a method body parse of each method to determine the references
+ */
+ public CompilationUnitDeclaration parse(
+ ICompilationUnit sourceUnit,
+ CompilationResult compilationResult) {
+
+ this.diet = true;
+ CompilationUnitDeclaration unit = super.parse(sourceUnit, compilationResult);
+ this.diet = false;
+ this.parseBodies(unit);
+ return unit;
+ }
+
+ /**
+ * Parses the method bodies in the given compilation unit
+ */
+ private void parseBodies(CompilationUnitDeclaration unit) {
+ TypeDeclaration[] types = unit.types;
+ if (types != null) {
+ for (int i = 0; i < types.length; i++) {
+ TypeDeclaration type = types[i];
+ if ((this.matchSet.matchContainer & SearchPattern.COMPILATION_UNIT) != 0
+ // type declaration in compilation unit
+ || (this.matchSet.matchContainer & SearchPattern.CLASS) != 0
+ // or in another type
+ || (this.matchSet.matchContainer & SearchPattern.METHOD) != 0) {
+ // or in a local class
+
+ this.matchSet.checkMatching(type);
+ }
+ this.parseBodies(type, unit);
+ }
+ }
+ }
+
+ /**
+ * Parses the member bodies in the given type.
+ */
+ private void parseBodies(
+ TypeDeclaration type,
+ CompilationUnitDeclaration unit) {
+ // fields
+ FieldDeclaration[] fields = type.fields;
+ if (fields != null) {
+ for (int i = 0; i < fields.length; i++) {
+ FieldDeclaration field = fields[i];
+ if ((this.matchSet.matchContainer & SearchPattern.CLASS) != 0) {
+ this.matchSet.checkMatching(field);
+ }
+ if (field instanceof Initializer) { // initializer block
+ this.parse((Initializer) field, type, unit);
+ }
+ }
+ }
+
+ // methods
+ AbstractMethodDeclaration[] methods = type.methods;
+ if (methods != null) {
+ for (int i = 0; i < methods.length; i++) {
+ AbstractMethodDeclaration method = methods[i];
+ if ((this.matchSet.matchContainer & SearchPattern.CLASS) != 0) {
+ this.matchSet.checkMatching(method);
+ }
+ if (method.sourceStart >= type.bodyStart) { // if not synthetic
+ if (method instanceof MethodDeclaration) {
+ this.parse((MethodDeclaration) method, unit);
+ } else
+ if (method instanceof ConstructorDeclaration) {
+ this.parse((ConstructorDeclaration) method, unit);
+ }
+ }
+ }
+ }
+
+ // member types
+ MemberTypeDeclaration[] memberTypes = type.memberTypes;
+ if (memberTypes != null) {
+ for (int i = 0; i < memberTypes.length; i++) {
+ MemberTypeDeclaration memberType = memberTypes[i];
+ if ((this.matchSet.matchContainer & SearchPattern.CLASS) != 0) {
+ this.matchSet.checkMatching(memberType);
+ }
+ this.parseBodies(memberType, unit);
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchSet.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchSet.java
new file mode 100644
index 0000000000..2b391f8934
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchSet.java
@@ -0,0 +1,332 @@
+package org.eclipse.jdt.internal.core.search.matching;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+import org.eclipse.jdt.internal.core.search.matching.*;
+import org.eclipse.jdt.internal.core.Util;
+
+import java.util.*;
+
+/**
+ * A set of matches and potential matches.
+ */
+public class MatchSet {
+
+ private static final char[][] EMPTY_CHAR_CHAR = new char[0][];
+
+ private MatchLocator locator;
+ int matchContainer;
+ boolean cuHasBeenResolved = false;
+ int accuracy = IJavaSearchResultCollector.POTENTIAL_MATCH;
+
+ /**
+ * Set of matching ast nodes that don't need to be resolved.
+ */
+ private Hashtable matchingNodes = new Hashtable(5);
+
+ /**
+ * Set of potential matching ast nodes. They need to be resolved
+ * to determine if they really match the search pattern.
+ */
+ private Hashtable potentialMatchingNodes = new Hashtable(5);
+
+ public MatchSet(MatchLocator locator) {
+ this.locator = locator;
+ this.matchContainer = locator.pattern.matchContainer();
+ }
+
+ public void addPossibleMatch(AstNode node) {
+ this.potentialMatchingNodes.put(node, node);
+ }
+
+ public void addTrustedMatch(AstNode node) {
+ this.matchingNodes.put(node, node);
+ }
+
+ public void checkMatching(AstNode node) {
+ int matchLevel = this.locator.pattern.matchLevel(node);
+ switch (matchLevel) {
+ case SearchPattern.POSSIBLE_MATCH :
+ this.addPossibleMatch(node);
+ break;
+ case SearchPattern.TRUSTED_MATCH :
+ this.addTrustedMatch(node);
+ }
+ }
+
+ /**
+ * Returns the matching nodes that are in the given range.
+ */
+ private AstNode[] matchingNodes(int start, int end) {
+ return this.nodesInRange(start, end, this.matchingNodes);
+ }
+
+ public boolean needsResolve() {
+ return this.potentialMatchingNodes.size() > 0;
+ }
+
+ /**
+ * Returns the matching nodes that are in the given range in the source order.
+ */
+ private AstNode[] nodesInRange(int start, int end, Hashtable set) {
+ // collect nodes in the given range
+ Vector nodes = new Vector();
+ for (Enumeration keys = set.keys(); keys.hasMoreElements();) {
+ AstNode node = (AstNode) keys.nextElement();
+ if (start <= node.sourceStart && node.sourceEnd <= end) {
+ nodes.addElement(node);
+ }
+ }
+ AstNode[] result = new AstNode[nodes.size()];
+ nodes.copyInto(result);
+
+ // sort nodes by source starts
+ Util.Comparer comparer = new Util.Comparer() {
+ public int compare(Object o1, Object o2) {
+ AstNode node1 = (AstNode) o1;
+ AstNode node2 = (AstNode) o2;
+ return node1.sourceStart - node2.sourceStart;
+ }
+ };
+ Util.sort(result, comparer);
+
+ return result;
+ }
+
+ /**
+ * Returns the potential matching nodes that are in the given range.
+ */
+ private AstNode[] potentialMatchingNodes(int start, int end) {
+ return this.nodesInRange(start, end, this.potentialMatchingNodes);
+ }
+
+ /**
+ * Visit the given method declaration and report the nodes that match exactly the
+ * search pattern (ie. the ones in the matching nodes set)
+ * Note that the method declaration has already been checked.
+ */
+ private void reportMatching(
+ AbstractMethodDeclaration method,
+ char[][] definingTypeNames)
+ throws CoreException {
+ // references in this method
+ AstNode[] nodes =
+ this.matchingNodes(method.declarationSourceStart, method.declarationSourceEnd);
+ for (int i = 0; i < nodes.length; i++) {
+ AstNode node = nodes[i];
+ this.matchingNodes.remove(node);
+ if ((this.matchContainer & SearchPattern.METHOD) != 0) {
+ this.locator.reportReference(node, method, definingTypeNames, this.accuracy);
+ }
+ }
+ if (this
+ .potentialMatchingNodes(
+ method.declarationSourceStart,
+ method.declarationSourceEnd)
+ .length
+ == 0) {
+ // no need to resolve the statements in the method
+ method.statements = null;
+ }
+ }
+
+ /**
+ * Visit the given parse tree and report the nodes that match exactly the
+ * search pattern.
+ */
+ public void reportMatching(CompilationUnitDeclaration unit)
+ throws CoreException {
+ if (this.cuHasBeenResolved) {
+ // move the potential matching nodes that exactly match the search pattern to the matching nodes set
+ for (Enumeration potentialMatches = this.potentialMatchingNodes.keys();
+ potentialMatches.hasMoreElements();
+ ) {
+ AstNode node = (AstNode) potentialMatches.nextElement();
+ if (this.locator.pattern.matches(node)) {
+ this.matchingNodes.put(node, node);
+ }
+ }
+ this.potentialMatchingNodes = new Hashtable();
+ }
+
+ // package declaration
+ ImportReference pkg = unit.currentPackage;
+ if (pkg != null && this.matchingNodes.get(pkg) == pkg) {
+ this.matchingNodes.remove(pkg);
+ if ((this.matchContainer & SearchPattern.COMPILATION_UNIT) != 0) {
+ this.locator.reportPackageDeclaration(pkg);
+ }
+ }
+
+ // import declarations
+ ImportReference[] imports = unit.imports;
+ if (imports != null) {
+ for (int i = 0; i < imports.length; i++) {
+ ImportReference importRef = imports[i];
+ if (this.matchingNodes.get(importRef) == importRef) {
+ this.matchingNodes.remove(importRef);
+ if ((this.matchContainer & SearchPattern.COMPILATION_UNIT) != 0) {
+ this.locator.reportImport(importRef, this.accuracy);
+ }
+ }
+ }
+ }
+
+ // types
+ TypeDeclaration[] types = unit.types;
+ if (types != null) {
+ for (int i = 0; i < types.length; i++) {
+ TypeDeclaration type = types[i];
+ if (this.matchingNodes.get(type) == type) {
+ this.matchingNodes.remove(type);
+ if ((this.matchContainer & SearchPattern.COMPILATION_UNIT) != 0) {
+ this.locator.reportTypeDeclaration(
+ type,
+ new char[][] { type.name },
+ this.accuracy);
+ }
+ }
+ this.reportMatching(type, EMPTY_CHAR_CHAR);
+ }
+ }
+ }
+
+ /**
+ * Visit the given field declaration and report the nodes that match exactly the
+ * search pattern (ie. the ones in the matching nodes set)
+ * Note that the field declaration has already been checked.
+ */
+ private void reportMatching(
+ FieldDeclaration field,
+ char[][] definingTypeNames,
+ TypeDeclaration type)
+ throws CoreException {
+ AstNode[] nodes =
+ this.matchingNodes(field.declarationSourceStart, field.declarationSourceEnd);
+ for (int i = 0; i < nodes.length; i++) {
+ AstNode node = nodes[i];
+ this.matchingNodes.remove(node);
+ if ((this.matchContainer & SearchPattern.FIELD) != 0) {
+ this.locator.reportReference(
+ node,
+ type,
+ field,
+ definingTypeNames,
+ this.accuracy);
+ }
+ }
+ }
+
+ /**
+ * Visit the given type declaration and report the nodes that match exactly the
+ * search pattern (ie. the ones in the matching nodes set)
+ * Note that the type declaration has already been checked.
+ */
+ private void reportMatching(TypeDeclaration type, char[][] enclosingTypeNames)
+ throws CoreException {
+ char[][] definingTypeNames =
+ CharOperation.arrayConcat(enclosingTypeNames, type.name);
+
+ // fields
+ FieldDeclaration[] fields = type.fields;
+ if (fields != null) {
+ for (int i = 0; i < fields.length; i++) {
+ FieldDeclaration field = fields[i];
+ if (this.matchingNodes.get(field) == field) {
+ this.matchingNodes.remove(field);
+ if ((this.matchContainer & SearchPattern.CLASS) != 0) {
+ this.locator.reportFieldDeclaration(field, definingTypeNames, this.accuracy);
+ }
+ }
+ this.reportMatching(field, definingTypeNames, type);
+ }
+ }
+
+ // methods
+ AbstractMethodDeclaration[] methods = type.methods;
+ if (methods != null) {
+ for (int i = 0; i < methods.length; i++) {
+ AbstractMethodDeclaration method = methods[i];
+ if (this.matchingNodes.get(method) == method) {
+ this.matchingNodes.remove(method);
+ if ((this.matchContainer & SearchPattern.CLASS) != 0) {
+ this.locator.reportMethodDeclaration(method, definingTypeNames, this.accuracy);
+ }
+ }
+ this.reportMatching(method, definingTypeNames);
+ }
+ }
+
+ // member types
+ MemberTypeDeclaration[] memberTypes = type.memberTypes;
+ if (memberTypes != null) {
+ for (int i = 0; i < memberTypes.length; i++) {
+ MemberTypeDeclaration memberType = memberTypes[i];
+ if (this.matchingNodes.get(memberType) == memberType) {
+ this.matchingNodes.remove(memberType);
+ if ((this.matchContainer & SearchPattern.CLASS) != 0) {
+ char[][] memberTypeNames =
+ CharOperation.arrayConcat(definingTypeNames, memberType.name);
+ this.locator.reportTypeDeclaration(memberType, memberTypeNames, this.accuracy);
+ }
+ }
+ this.reportMatching(memberType, definingTypeNames);
+ }
+ }
+
+ // super types
+ TypeReference superClass = type.superclass;
+ if (superClass != null && this.matchingNodes.get(superClass) == superClass) {
+ this.matchingNodes.remove(superClass);
+ if ((this.matchContainer & SearchPattern.CLASS) != 0) {
+ this.locator.reportSuperTypeReference(
+ superClass,
+ definingTypeNames,
+ this.accuracy);
+ }
+ }
+ TypeReference[] superInterfaces = type.superInterfaces;
+ if (superInterfaces != null) {
+ for (int i = 0; i < superInterfaces.length; i++) {
+ TypeReference superInterface = superInterfaces[i];
+ if (this.matchingNodes.get(superInterface) == superInterface) {
+ this.matchingNodes.remove(superInterface);
+ if ((this.matchContainer & SearchPattern.CLASS) != 0) {
+ this.locator.reportSuperTypeReference(
+ superInterface,
+ definingTypeNames,
+ this.accuracy);
+ }
+ }
+ }
+ }
+
+ }
+
+ public String toString() {
+ StringBuffer result = new StringBuffer();
+ result.append("Exact matches:");
+ for (Enumeration enum = this.matchingNodes.keys(); enum.hasMoreElements();) {
+ result.append("\n");
+ AstNode node = (AstNode) enum.nextElement();
+ result.append(node.toString(1));
+ }
+ result.append("\nPotential matches:");
+ for (Enumeration enum = this.potentialMatchingNodes.keys();
+ enum.hasMoreElements();
+ ) {
+ result.append("\n");
+ AstNode node = (AstNode) enum.nextElement();
+ result.append(node.toString(1));
+ }
+ return result.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodDeclarationPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodDeclarationPattern.java
new file mode 100644
index 0000000000..c5fc8312b4
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodDeclarationPattern.java
@@ -0,0 +1,331 @@
+package org.eclipse.jdt.internal.core.search.matching;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+import org.eclipse.jdt.core.Signature;
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.search.indexing.*;
+import org.eclipse.jdt.internal.core.index.impl.*;
+import org.eclipse.jdt.internal.core.search.*;
+
+import java.io.*;
+
+public class MethodDeclarationPattern extends MethodPattern {
+ public MethodDeclarationPattern(
+ char[] selector,
+ int matchMode,
+ boolean isCaseSensitive,
+ char[] declaringQualification,
+ char[] declaringSimpleName,
+ char[] returnQualification,
+ char[] returnSimpleName,
+ char[][] parameterQualifications,
+ char[][] parameterSimpleNames) {
+
+ super(matchMode, isCaseSensitive);
+
+ this.selector =
+ isCaseSensitive ? selector : CharOperation.toLowerCase(selector);
+ this.declaringQualification =
+ isCaseSensitive
+ ? declaringQualification
+ : CharOperation.toLowerCase(declaringQualification);
+ this.declaringSimpleName =
+ isCaseSensitive
+ ? declaringSimpleName
+ : CharOperation.toLowerCase(declaringSimpleName);
+ this.returnQualification =
+ isCaseSensitive
+ ? returnQualification
+ : CharOperation.toLowerCase(returnQualification);
+ this.returnSimpleName =
+ isCaseSensitive
+ ? returnSimpleName
+ : CharOperation.toLowerCase(returnSimpleName);
+
+ if (parameterSimpleNames != null) {
+ this.parameterQualifications = new char[parameterSimpleNames.length][];
+ this.parameterSimpleNames = new char[parameterSimpleNames.length][];
+ for (int i = 0, max = parameterSimpleNames.length; i < max; i++) {
+ this.parameterQualifications[i] =
+ isCaseSensitive
+ ? parameterQualifications[i]
+ : CharOperation.toLowerCase(parameterQualifications[i]);
+ this.parameterSimpleNames[i] =
+ isCaseSensitive
+ ? parameterSimpleNames[i]
+ : CharOperation.toLowerCase(parameterSimpleNames[i]);
+ }
+ }
+ this.needsResolve = this.needsResolve();
+ }
+
+ public void decodeIndexEntry(IEntryResult entryResult) {
+
+ char[] word = entryResult.getWord();
+ int size = word.length;
+ int lastSeparatorIndex = CharOperation.lastIndexOf(SEPARATOR, word);
+
+ decodedParameterCount =
+ Integer.parseInt(
+ new String(word, lastSeparatorIndex + 1, size - lastSeparatorIndex - 1));
+ decodedSelector =
+ CharOperation.subarray(word, METHOD_DECL.length, lastSeparatorIndex);
+ }
+
+ /**
+ * see SearchPattern.feedIndexRequestor
+ */
+ public void feedIndexRequestor(
+ IIndexSearchRequestor requestor,
+ int detailLevel,
+ int[] references,
+ IndexInput input,
+ IJavaSearchScope scope)
+ throws IOException {
+ for (int i = 0, max = references.length; i < max; i++) {
+ IndexedFile file = input.getIndexedFile(references[i]);
+ String path;
+ if (file != null
+ && scope.encloses(path = IndexedFile.convertPath(file.getPath()))) {
+ requestor.acceptMethodDeclaration(path, decodedSelector, decodedParameterCount);
+ }
+ }
+ }
+
+ public String getPatternName() {
+ return "MethodDeclarationPattern: ";
+ }
+
+ /**
+ * @see SearchPattern#indexEntryPrefix
+ */
+ public char[] indexEntryPrefix() {
+
+ return AbstractIndexer.bestMethodDeclarationPrefix(
+ selector,
+ parameterSimpleNames == null ? -1 : parameterSimpleNames.length,
+ matchMode,
+ isCaseSensitive);
+ }
+
+ /**
+ * @see SearchPattern#matchContainer()
+ */
+ protected int matchContainer() {
+ return CLASS;
+ }
+
+ /**
+ * @see SearchPattern#matches(AstNode, boolean)
+ */
+ protected boolean matches(AstNode node, boolean resolve) {
+ if (!(node instanceof MethodDeclaration))
+ return false;
+
+ MethodDeclaration method = (MethodDeclaration) node;
+
+ // selector
+ if (!this.matchesName(this.selector, method.selector))
+ return false;
+
+ // declaring type
+ MethodBinding binding = method.binding;
+ if (resolve && binding != null) {
+ ReferenceBinding declaringType = binding.declaringClass;
+ if (declaringType != null) {
+ if (!binding.isStatic() && !binding.isPrivate()) {
+ if (!this
+ .matchesAsSubtype(
+ declaringType,
+ this.declaringSimpleName,
+ this.declaringQualification))
+ return false;
+ } else {
+ if (!this
+ .matchesType(
+ this.declaringSimpleName,
+ this.declaringQualification,
+ declaringType))
+ return false;
+ }
+ }
+ }
+
+ // return type
+ if (this.returnQualification == null) {
+ if (this.returnSimpleName != null) {
+ TypeReference methodReturnType = method.returnType;
+ if (methodReturnType != null) {
+ char[][] methodReturnTypeName = methodReturnType.getTypeName();
+ char[] sourceName =
+ this.toArrayName(
+ methodReturnTypeName[methodReturnTypeName.length - 1],
+ methodReturnType.dimensions());
+ if (!this.matchesName(this.returnSimpleName, sourceName))
+ return false;
+ }
+ }
+ } else {
+ if (resolve
+ && binding != null
+ && !this.matchesType(
+ this.returnSimpleName,
+ this.returnQualification,
+ binding.returnType))
+ return false;
+ }
+
+ // parameter types
+ int parameterCount =
+ this.parameterSimpleNames == null ? -1 : this.parameterSimpleNames.length;
+ if (parameterCount > -1) {
+ int argumentCount = method.arguments == null ? 0 : method.arguments.length;
+ if (parameterCount != argumentCount)
+ return false;
+
+ if (resolve && binding != null) {
+ for (int i = 0; i < parameterCount; i++) {
+ char[] qualification = this.parameterQualifications[i];
+ char[] type = this.parameterSimpleNames[i];
+ if (!this.matchesType(type, qualification, binding.parameters[i]))
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @see SearchPattern#matches(Binding)
+ */
+ public boolean matches(Binding binding) {
+ if (!(binding instanceof MethodBinding))
+ return false;
+
+ MethodBinding method = (MethodBinding) binding;
+
+ // selector
+ if (!this.matchesName(this.selector, method.selector))
+ return false;
+
+ // declaring type
+ ReferenceBinding declaringType = method.declaringClass;
+ if (declaringType != null) {
+ if (!method.isStatic() && !method.isPrivate()) {
+ if (!this
+ .matchesAsSubtype(
+ declaringType,
+ this.declaringSimpleName,
+ this.declaringQualification))
+ return false;
+ } else {
+ if (!this
+ .matchesType(
+ this.declaringSimpleName,
+ this.declaringQualification,
+ declaringType))
+ return false;
+ }
+ }
+
+ // return type
+ if (!this
+ .matchesType(
+ this.returnSimpleName,
+ this.returnQualification,
+ method.returnType)) {
+ return false;
+ }
+
+ // parameter types
+ int parameterCount =
+ this.parameterSimpleNames == null ? -1 : this.parameterSimpleNames.length;
+ if (parameterCount > -1) {
+ int argumentCount = method.parameters == null ? 0 : method.parameters.length;
+ if (parameterCount != argumentCount)
+ return false;
+ for (int i = 0; i < parameterCount; i++) {
+ char[] qualification = this.parameterQualifications[i];
+ char[] type = this.parameterSimpleNames[i];
+ if (!this.matchesType(type, qualification, method.parameters[i]))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @see SearchPattern#matchesBinary(Object, Object)
+ */
+ public boolean matchesBinary(Object binaryInfo, Object enclosingBinaryInfo) {
+ if (!(binaryInfo instanceof IBinaryMethod))
+ return false;
+
+ IBinaryMethod method = (IBinaryMethod) binaryInfo;
+
+ // selector
+ if (!this.matchesName(this.selector, method.getSelector()))
+ return false;
+
+ // declaring type
+ IBinaryType declaringType = (IBinaryType) enclosingBinaryInfo;
+ if (declaringType != null) {
+ char[] declaringTypeName = (char[]) declaringType.getName().clone();
+ CharOperation.replace(declaringTypeName, '/', '.');
+ if (!this
+ .matchesType(
+ this.declaringSimpleName,
+ this.declaringQualification,
+ declaringTypeName)) {
+ return false;
+ }
+ }
+
+ // return type
+ String methodDescriptor =
+ new String(method.getMethodDescriptor()).replace('/', '.');
+ String returnTypeSignature =
+ Signature.toString(Signature.getReturnType(methodDescriptor));
+ if (!this
+ .matchesType(
+ this.returnSimpleName,
+ this.returnQualification,
+ returnTypeSignature.toCharArray())) {
+ return false;
+ }
+
+ // parameter types
+ int parameterCount =
+ this.parameterSimpleNames == null ? -1 : this.parameterSimpleNames.length;
+ if (parameterCount > -1) {
+ String[] arguments = Signature.getParameterTypes(methodDescriptor);
+ int argumentCount = arguments.length;
+ if (parameterCount != argumentCount)
+ return false;
+ for (int i = 0; i < parameterCount; i++) {
+ char[] qualification = this.parameterQualifications[i];
+ char[] type = this.parameterSimpleNames[i];
+ if (!this
+ .matchesType(
+ type,
+ qualification,
+ Signature.toString(arguments[i]).toCharArray()))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodPattern.java
new file mode 100644
index 0000000000..e41cb7a45f
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodPattern.java
@@ -0,0 +1,149 @@
+package org.eclipse.jdt.internal.core.search.matching;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.util.*;
+
+public abstract class MethodPattern extends SearchPattern {
+
+ // selector
+ protected char[] selector;
+
+ // declaring type
+ protected char[] declaringQualification;
+ protected char[] declaringSimpleName;
+
+ // return type
+ protected char[] returnQualification;
+ protected char[] returnSimpleName;
+
+ // parameter types
+ protected char[][] parameterQualifications;
+ protected char[][] parameterSimpleNames;
+
+ protected char[] decodedSelector;
+ protected int decodedParameterCount;
+ public MethodPattern(int matchMode, boolean isCaseSensitive) {
+ super(matchMode, isCaseSensitive);
+ }
+
+ public abstract String getPatternName();
+ /**
+ * @see SearchPattern#matchIndexEntry
+ */
+ protected boolean matchIndexEntry() {
+
+ /* check selector matches */
+ if (selector != null) {
+ switch (matchMode) {
+ case EXACT_MATCH :
+ if (!CharOperation.equals(selector, decodedSelector, isCaseSensitive)) {
+ return false;
+ }
+ break;
+ case PREFIX_MATCH :
+ if (!CharOperation.prefixEquals(selector, decodedSelector, isCaseSensitive)) {
+ return false;
+ }
+ break;
+ case PATTERN_MATCH :
+ if (!CharOperation.match(selector, decodedSelector, isCaseSensitive)) {
+ return false;
+ }
+ }
+ }
+ if (parameterSimpleNames != null) {
+ if (parameterSimpleNames.length != decodedParameterCount)
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns whether a method declaration or message send will need to be resolved to
+ * find out if this method pattern matches it.
+ */
+ protected boolean needsResolve() {
+
+ // declaring type
+ if (declaringSimpleName != null || declaringQualification != null)
+ return true;
+
+ // return type
+ if (returnSimpleName != null || returnQualification != null)
+ return true;
+
+ // parameter types
+ if (parameterSimpleNames != null) {
+ for (int i = 0, max = parameterSimpleNames.length; i < max; i++) {
+ if (parameterQualifications[i] != null || parameterSimpleNames[i] != null)
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public String toString() {
+
+ StringBuffer buffer = new StringBuffer(20);
+ buffer.append(this.getPatternName());
+ if (declaringQualification != null)
+ buffer.append(declaringQualification).append('.');
+ if (declaringSimpleName != null)
+ buffer.append(declaringSimpleName).append('.');
+ else
+ if (declaringQualification != null)
+ buffer.append("*.");
+ if (selector != null) {
+ buffer.append(selector);
+ } else {
+ buffer.append("*");
+ }
+ buffer.append('(');
+ if (parameterSimpleNames == null) {
+ buffer.append("...");
+ } else {
+ for (int i = 0, max = parameterSimpleNames.length; i < max; i++) {
+ if (i > 0)
+ buffer.append(", ");
+ if (parameterQualifications[i] != null)
+ buffer.append(parameterQualifications[i]).append('.');
+ if (parameterSimpleNames[i] == null)
+ buffer.append('*');
+ else
+ buffer.append(parameterSimpleNames[i]);
+ }
+ }
+ buffer.append(')');
+ if (returnQualification != null)
+ buffer.append(" --> ").append(returnQualification).append('.');
+ else
+ if (returnSimpleName != null)
+ buffer.append(" --> ");
+ if (returnSimpleName != null)
+ buffer.append(returnSimpleName);
+ else
+ if (returnQualification != null)
+ buffer.append("*");
+ buffer.append(", ");
+ switch (matchMode) {
+ case EXACT_MATCH :
+ buffer.append("exact match, ");
+ break;
+ case PREFIX_MATCH :
+ buffer.append("prefix match, ");
+ break;
+ case PATTERN_MATCH :
+ buffer.append("pattern match, ");
+ break;
+ }
+ if (isCaseSensitive)
+ buffer.append("case sensitive");
+ else
+ buffer.append("case insensitive");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodReferencePattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodReferencePattern.java
new file mode 100644
index 0000000000..e4f79b838d
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodReferencePattern.java
@@ -0,0 +1,239 @@
+package org.eclipse.jdt.internal.core.search.matching;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.search.indexing.*;
+import org.eclipse.jdt.internal.core.index.impl.*;
+import org.eclipse.jdt.internal.core.search.*;
+
+import java.io.*;
+
+public class MethodReferencePattern extends MethodPattern {
+ public ReferenceBinding[] declaringTypes;
+
+ public MethodReferencePattern(
+ char[] selector,
+ int matchMode,
+ boolean isCaseSensitive,
+ char[] declaringQualification,
+ char[] declaringSimpleName,
+ char[] returnQualification,
+ char[] returnSimpleName,
+ char[][] parameterQualifications,
+ char[][] parameterSimpleNames) {
+
+ super(matchMode, isCaseSensitive);
+
+ this.selector =
+ isCaseSensitive ? selector : CharOperation.toLowerCase(selector);
+ this.declaringQualification =
+ isCaseSensitive
+ ? declaringQualification
+ : CharOperation.toLowerCase(declaringQualification);
+ this.declaringSimpleName =
+ isCaseSensitive
+ ? declaringSimpleName
+ : CharOperation.toLowerCase(declaringSimpleName);
+ this.returnQualification =
+ isCaseSensitive
+ ? returnQualification
+ : CharOperation.toLowerCase(returnQualification);
+ this.returnSimpleName =
+ isCaseSensitive
+ ? returnSimpleName
+ : CharOperation.toLowerCase(returnSimpleName);
+ if (parameterSimpleNames != null) {
+ this.parameterQualifications = new char[parameterSimpleNames.length][];
+ this.parameterSimpleNames = new char[parameterSimpleNames.length][];
+ for (int i = 0, max = parameterSimpleNames.length; i < max; i++) {
+ this.parameterQualifications[i] =
+ isCaseSensitive
+ ? parameterQualifications[i]
+ : CharOperation.toLowerCase(parameterQualifications[i]);
+ this.parameterSimpleNames[i] =
+ isCaseSensitive
+ ? parameterSimpleNames[i]
+ : CharOperation.toLowerCase(parameterSimpleNames[i]);
+ }
+ }
+
+ this.needsResolve = this.needsResolve();
+ }
+
+ public void decodeIndexEntry(IEntryResult entryResult) {
+
+ char[] word = entryResult.getWord();
+ int size = word.length;
+ int lastSeparatorIndex = CharOperation.lastIndexOf(SEPARATOR, word);
+
+ decodedParameterCount =
+ Integer.parseInt(
+ new String(word, lastSeparatorIndex + 1, size - lastSeparatorIndex - 1));
+ decodedSelector =
+ CharOperation.subarray(word, METHOD_REF.length, lastSeparatorIndex);
+ }
+
+ /**
+ * see SearchPattern.feedIndexRequestor
+ */
+ public void feedIndexRequestor(
+ IIndexSearchRequestor requestor,
+ int detailLevel,
+ int[] references,
+ IndexInput input,
+ IJavaSearchScope scope)
+ throws IOException {
+ for (int i = 0, max = references.length; i < max; i++) {
+ IndexedFile file = input.getIndexedFile(references[i]);
+ String path;
+ if (file != null
+ && scope.encloses(path = IndexedFile.convertPath(file.getPath()))) {
+ requestor.acceptMethodReference(path, decodedSelector, decodedParameterCount);
+ }
+ }
+ }
+
+ public String getPatternName() {
+ return "MethodReferencePattern: ";
+ }
+
+ /**
+ * @see SearchPattern#indexEntryPrefix
+ */
+ public char[] indexEntryPrefix() {
+
+ return AbstractIndexer.bestMethodReferencePrefix(
+ selector,
+ parameterSimpleNames == null ? -1 : parameterSimpleNames.length,
+ matchMode,
+ isCaseSensitive);
+ }
+
+ /**
+ * Returns whether the code gen will use an invoke virtual for
+ * this message send or not.
+ */
+ private boolean isVirtualInvoke(MessageSend messageSend) {
+ return !messageSend.binding.isStatic()
+ && !messageSend.isSuperAccess()
+ && !messageSend.binding.isPrivate();
+ }
+
+ /**
+ * @see SearchPattern#matchContainer()
+ */
+ protected int matchContainer() {
+ return METHOD | FIELD;
+ }
+
+ /**
+ * @see SearchPattern#matches(AstNode, boolean)
+ */
+ protected boolean matches(AstNode node, boolean resolve) {
+ if (!(node instanceof MessageSend))
+ return false;
+
+ MessageSend messageSend = (MessageSend) node;
+
+ // selector
+ if (this.selector != null
+ && !this.matchesName(this.selector, messageSend.selector))
+ return false;
+
+ // declaring type
+ MethodBinding binding = messageSend.binding;
+ if (resolve && binding != null) {
+ ReferenceBinding receiverType = binding.declaringClass;
+ if (this.isVirtualInvoke(messageSend)) {
+ if (!this
+ .matchesAsSubtype(
+ receiverType,
+ this.declaringSimpleName,
+ this.declaringQualification)
+ && !this.matchesAsSubtype(this.declaringTypes, receiverType)) {
+ return false;
+ }
+ } else {
+ if (!this
+ .matchesType(
+ this.declaringSimpleName,
+ this.declaringQualification,
+ receiverType))
+ return false;
+ }
+ }
+
+ // return type
+ if (resolve && binding != null) {
+ if (!this
+ .matchesType(
+ this.returnSimpleName,
+ this.returnQualification,
+ binding.returnType))
+ return false;
+ }
+
+ // argument types
+ int argumentCount =
+ this.parameterSimpleNames == null ? -1 : this.parameterSimpleNames.length;
+ if (argumentCount > -1) {
+ int parameterCount =
+ messageSend.arguments == null ? 0 : messageSend.arguments.length;
+ if (parameterCount != argumentCount)
+ return false;
+
+ if (resolve && binding != null) {
+ for (int i = 0; i < parameterCount; i++) {
+ char[] qualification = this.parameterQualifications[i];
+ char[] type = this.parameterSimpleNames[i];
+ if (!this.matchesType(type, qualification, binding.parameters[i]))
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public boolean initializeFromLookupEnvironment(LookupEnvironment env) {
+
+ char[][] declaringTypeName = null;
+ if ((this.declaringQualification != null)
+ && (this.declaringSimpleName != null)
+ && (this.matchMode == EXACT_MATCH)) {
+ char[][] qualification =
+ CharOperation.splitOn('.', this.declaringQualification);
+ declaringTypeName =
+ CharOperation.arrayConcat(qualification, this.declaringSimpleName);
+ }
+ if (declaringTypeName != null) {
+ for (int i = 0, max = declaringTypeName.length; i < max; i++) {
+ ReferenceBinding matchingDeclaringType = env.getCachedType(declaringTypeName);
+ if (matchingDeclaringType != null && matchingDeclaringType.isValidBinding()) {
+ this.declaringTypes = new ReferenceBinding[] { matchingDeclaringType };
+ return true;
+ }
+ // if nothing is in the cache, it could have been a member type (A.B.C.D --> A.B.C$D)
+ int last = declaringTypeName.length - 1;
+ if (last == 0)
+ break;
+ declaringTypeName[last - 1] =
+ CharOperation.concat(declaringTypeName[last - 1], declaringTypeName[last], '$');
+ // try nested type
+ declaringTypeName = CharOperation.subarray(declaringTypeName, 0, last);
+ }
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MultipleSearchPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MultipleSearchPattern.java
new file mode 100644
index 0000000000..864c22db8c
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MultipleSearchPattern.java
@@ -0,0 +1,48 @@
+package org.eclipse.jdt.internal.core.search.matching;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.index.impl.*;
+import org.eclipse.jdt.internal.core.search.*;
+
+import java.io.*;
+
+public abstract class MultipleSearchPattern extends AndPattern {
+
+ protected char[] currentTag;
+ public boolean foundAmbiguousIndexMatches = false;
+ public MultipleSearchPattern(int matchMode, boolean isCaseSensitive) {
+ super(matchMode, isCaseSensitive);
+ }
+
+ /**
+ * Query a given index for matching entries.
+ */
+ public void findIndexMatches(
+ IndexInput input,
+ IIndexSearchRequestor requestor,
+ int detailLevel,
+ IProgressMonitor progressMonitor,
+ IJavaSearchScope scope)
+ throws IOException {
+
+ char[][] possibleTags = getPossibleTags();
+
+ if (progressMonitor != null && progressMonitor.isCanceled())
+ throw new OperationCanceledException();
+
+ /* narrow down a set of entries using prefix criteria */
+ for (int i = 0, max = possibleTags.length; i < max; i++) {
+ currentTag = possibleTags[i];
+ super.findIndexMatches(input, requestor, detailLevel, progressMonitor, scope);
+ }
+ }
+
+ protected abstract char[][] getPossibleTags();
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrNameCombiner.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrNameCombiner.java
new file mode 100644
index 0000000000..ff4410d3a3
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrNameCombiner.java
@@ -0,0 +1,94 @@
+package org.eclipse.jdt.internal.core.search.matching;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+import org.eclipse.jdt.internal.core.search.*;
+
+import java.util.*;
+
+public class OrNameCombiner implements IIndexSearchRequestor {
+
+ IIndexSearchRequestor targetRequestor;
+ HashtableOfObject acceptedAnswers = new HashtableOfObject(5);
+
+ public OrNameCombiner(IIndexSearchRequestor targetRequestor) {
+ this.targetRequestor = targetRequestor;
+ }
+
+ public void acceptClassDeclaration(
+ String resourcePath,
+ char[] simpleTypeName,
+ char[][] enclosingTypeNames,
+ char[] packageName) {
+
+ if (!this
+ .acceptedAnswers
+ .containsKey(CharOperation.concat(packageName, simpleTypeName, '.'))) {
+ this.targetRequestor.acceptClassDeclaration(
+ resourcePath,
+ simpleTypeName,
+ enclosingTypeNames,
+ packageName);
+ }
+ }
+
+ public void acceptConstructorDeclaration(
+ String resourcePath,
+ char[] typeName,
+ int parameterCount) {
+ }
+
+ public void acceptConstructorReference(
+ String resourcePath,
+ char[] typeName,
+ int parameterCount) {
+ }
+
+ public void acceptFieldDeclaration(String resourcePath, char[] fieldName) {
+ }
+
+ public void acceptFieldReference(String resourcePath, char[] fieldName) {
+ }
+
+ public void acceptInterfaceDeclaration(
+ String resourcePath,
+ char[] simpleTypeName,
+ char[][] enclosingTypeNames,
+ char[] packageName) {
+ }
+
+ public void acceptMethodDeclaration(
+ String resourcePath,
+ char[] methodName,
+ int parameterCount) {
+ }
+
+ public void acceptMethodReference(
+ String resourcePath,
+ char[] methodName,
+ int parameterCount) {
+ }
+
+ public void acceptPackageReference(String resourcePath, char[] packageName) {
+ }
+
+ public void acceptSuperTypeReference(
+ String resourcePath,
+ char[] qualification,
+ char[] typeName,
+ char[] enclosingTypeName,
+ char classOrInterface,
+ char[] superQualification,
+ char[] superTypeName,
+ char superClassOrInterface,
+ int modifiers) {
+ }
+
+ public void acceptTypeReference(String resourcePath, char[] typeName) {
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrPathCombiner.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrPathCombiner.java
new file mode 100644
index 0000000000..6453f299e2
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrPathCombiner.java
@@ -0,0 +1,156 @@
+package org.eclipse.jdt.internal.core.search.matching;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.search.*;
+
+import java.util.*;
+
+public class OrPathCombiner implements IIndexSearchRequestor {
+
+ IIndexSearchRequestor targetRequestor;
+ Hashtable acceptedAnswers = new Hashtable(5);
+ public OrPathCombiner(IIndexSearchRequestor targetRequestor) {
+ this.targetRequestor = targetRequestor;
+ }
+
+ public void acceptClassDeclaration(
+ String resourcePath,
+ char[] simpleTypeName,
+ char[][] enclosingTypeNames,
+ char[] packageName) {
+
+ if (!this.acceptedAnswers.containsKey(resourcePath)) {
+ this.acceptedAnswers.put(resourcePath, resourcePath);
+ this.targetRequestor.acceptClassDeclaration(
+ resourcePath,
+ simpleTypeName,
+ enclosingTypeNames,
+ packageName);
+ }
+ }
+
+ public void acceptConstructorDeclaration(
+ String resourcePath,
+ char[] typeName,
+ int parameterCount) {
+ if (!this.acceptedAnswers.containsKey(resourcePath)) {
+ this.acceptedAnswers.put(resourcePath, resourcePath);
+ this.targetRequestor.acceptConstructorDeclaration(
+ resourcePath,
+ typeName,
+ parameterCount);
+ }
+ }
+
+ public void acceptConstructorReference(
+ String resourcePath,
+ char[] typeName,
+ int parameterCount) {
+ if (!this.acceptedAnswers.containsKey(resourcePath)) {
+ this.acceptedAnswers.put(resourcePath, resourcePath);
+ this.targetRequestor.acceptConstructorReference(
+ resourcePath,
+ typeName,
+ parameterCount);
+ }
+ }
+
+ public void acceptFieldDeclaration(String resourcePath, char[] fieldName) {
+ if (!this.acceptedAnswers.containsKey(resourcePath)) {
+ this.acceptedAnswers.put(resourcePath, resourcePath);
+ this.targetRequestor.acceptFieldDeclaration(resourcePath, fieldName);
+ }
+ }
+
+ public void acceptFieldReference(String resourcePath, char[] fieldName) {
+ if (!this.acceptedAnswers.containsKey(resourcePath)) {
+ this.acceptedAnswers.put(resourcePath, resourcePath);
+ this.targetRequestor.acceptFieldReference(resourcePath, fieldName);
+ }
+ }
+
+ public void acceptInterfaceDeclaration(
+ String resourcePath,
+ char[] simpleTypeName,
+ char[][] enclosingTypeNames,
+ char[] packageName) {
+ if (!this.acceptedAnswers.containsKey(resourcePath)) {
+ this.acceptedAnswers.put(resourcePath, resourcePath);
+ this.targetRequestor.acceptInterfaceDeclaration(
+ resourcePath,
+ simpleTypeName,
+ enclosingTypeNames,
+ packageName);
+ }
+ }
+
+ public void acceptMethodDeclaration(
+ String resourcePath,
+ char[] methodName,
+ int parameterCount) {
+ if (!this.acceptedAnswers.containsKey(resourcePath)) {
+ this.acceptedAnswers.put(resourcePath, resourcePath);
+ this.targetRequestor.acceptMethodDeclaration(
+ resourcePath,
+ methodName,
+ parameterCount);
+ }
+ }
+
+ public void acceptMethodReference(
+ String resourcePath,
+ char[] methodName,
+ int parameterCount) {
+ if (!this.acceptedAnswers.containsKey(resourcePath)) {
+ this.acceptedAnswers.put(resourcePath, resourcePath);
+ this.targetRequestor.acceptMethodReference(
+ resourcePath,
+ methodName,
+ parameterCount);
+ }
+ }
+
+ public void acceptPackageReference(String resourcePath, char[] packageName) {
+ if (!this.acceptedAnswers.containsKey(resourcePath)) {
+ this.acceptedAnswers.put(resourcePath, resourcePath);
+ this.targetRequestor.acceptPackageReference(resourcePath, packageName);
+ }
+ }
+
+ public void acceptSuperTypeReference(
+ String resourcePath,
+ char[] qualification,
+ char[] typeName,
+ char[] enclosingTypeName,
+ char classOrInterface,
+ char[] superQualification,
+ char[] superTypeName,
+ char superClassOrInterface,
+ int modifiers) {
+ if (!this.acceptedAnswers.containsKey(resourcePath)) {
+ this.acceptedAnswers.put(resourcePath, resourcePath);
+ this.targetRequestor.acceptSuperTypeReference(
+ resourcePath,
+ qualification,
+ typeName,
+ enclosingTypeName,
+ classOrInterface,
+ superQualification,
+ superTypeName,
+ superClassOrInterface,
+ modifiers);
+ }
+ }
+
+ public void acceptTypeReference(String resourcePath, char[] typeName) {
+ if (!this.acceptedAnswers.containsKey(resourcePath)) {
+ this.acceptedAnswers.put(resourcePath, resourcePath);
+ this.targetRequestor.acceptTypeReference(resourcePath, typeName);
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrPattern.java
new file mode 100644
index 0000000000..b01d4b2988
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrPattern.java
@@ -0,0 +1,119 @@
+package org.eclipse.jdt.internal.core.search.matching;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.core.search.*;
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
+import org.eclipse.jdt.internal.core.index.impl.*;
+import org.eclipse.jdt.internal.core.search.*;
+
+import java.io.*;
+
+public class OrPattern extends SearchPattern {
+
+ public SearchPattern leftPattern;
+ public SearchPattern rightPattern;
+public OrPattern(SearchPattern leftPattern, SearchPattern rightPattern) {
+ super(-1, false); // values ignored for a OrPattern
+
+ this.leftPattern = leftPattern;
+ this.rightPattern = rightPattern;
+
+ this.needsResolve = leftPattern.needsResolve || rightPattern.needsResolve;
+}
+/**
+ * see SearchPattern.decodedIndexEntry
+ */
+protected void decodeIndexEntry(IEntryResult entry) {
+
+ // will never be directly invoked on a composite pattern
+}
+/**
+ * see SearchPattern.feedIndexRequestor
+ */
+public void feedIndexRequestor(IIndexSearchRequestor requestor, int detailLevel, int[] references, IndexInput input, IJavaSearchScope scope) throws IOException {
+ // will never be directly invoked on a composite pattern
+}
+/**
+ * see SearchPattern.findMatches
+ */
+public void findIndexMatches(IndexInput input, IIndexSearchRequestor requestor, int detailLevel, IProgressMonitor progressMonitor, IJavaSearchScope scope) throws IOException {
+
+ if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
+
+ IIndexSearchRequestor orCombiner;
+ if (detailLevel == IInfoConstants.NameInfo) {
+ orCombiner = new OrNameCombiner(requestor);
+ } else {
+ orCombiner = new OrPathCombiner(requestor);
+ }
+ leftPattern.findIndexMatches(input, orCombiner, detailLevel, progressMonitor, scope);
+ if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
+ rightPattern.findIndexMatches(input, orCombiner, detailLevel, progressMonitor, scope);
+}
+/**
+ * see SearchPattern.indexEntryPrefix
+ */
+public char[] indexEntryPrefix() {
+
+ // will never be directly invoked on a composite pattern
+ return null;
+}
+/**
+ * see SearchPattern.initializeFromLookupEnvironment
+ */
+public boolean initializeFromLookupEnvironment(LookupEnvironment env) {
+ return
+ this.leftPattern.initializeFromLookupEnvironment(env)
+ || this.rightPattern.initializeFromLookupEnvironment(env);
+}
+/**
+ * @see SearchPattern#matchContainer()
+ */
+protected int matchContainer() {
+ return leftPattern.matchContainer()
+ | rightPattern.matchContainer();
+}
+/**
+ * @see SearchPattern#matches(AstNode, boolean)
+ */
+protected boolean matches(AstNode node, boolean resolve) {
+ return this.leftPattern.matches(node, resolve) || this.rightPattern.matches(node, resolve);
+}
+/**
+ * @see SearchPattern#matches(Binding)
+ */
+public boolean matches(Binding binding) {
+ return this.leftPattern.matches(binding) || this.rightPattern.matches(binding);
+}
+/**
+ * see SearchPattern.matchIndexEntry
+ */
+protected boolean matchIndexEntry() {
+
+ return leftPattern.matchIndexEntry()
+ || rightPattern.matchIndexEntry();
+}
+/**
+ * @see SearchPattern#matchReportReference
+ */
+protected void matchReportReference(AstNode reference, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
+ if (this.leftPattern.matches(reference)) {
+ this.leftPattern.matchReportReference(reference, element, accuracy, locator);
+ } else {
+ this.rightPattern.matchReportReference(reference, element, accuracy, locator);
+ }
+}
+public String toString(){
+ return this.leftPattern.toString() + "\n| " + this.rightPattern.toString();
+}
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageDeclarationPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageDeclarationPattern.java
new file mode 100644
index 0000000000..b5aeb308ee
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageDeclarationPattern.java
@@ -0,0 +1,114 @@
+package org.eclipse.jdt.internal.core.search.matching;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import java.io.IOException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.internal.compiler.ast.AstNode;
+import org.eclipse.jdt.internal.core.index.impl.IndexInput;
+import org.eclipse.jdt.core.search.IJavaSearchScope;
+import org.eclipse.jdt.internal.core.search.IIndexSearchRequestor;
+import org.eclipse.jdt.internal.core.index.IEntryResult;
+
+public class PackageDeclarationPattern extends SearchPattern {
+ char[] pkgName;
+ public PackageDeclarationPattern(
+ char[] pkgName,
+ int matchMode,
+ boolean isCaseSensitive) {
+ super(matchMode, isCaseSensitive);
+ this.pkgName = pkgName;
+ }
+
+ /**
+ * @see SearchPattern#decodeIndexEntry
+ */
+ protected void decodeIndexEntry(IEntryResult entryResult) {
+ // not used
+ }
+
+ /**
+ * @see SearchPattern#feedIndexRequestor
+ */
+ public void feedIndexRequestor(
+ IIndexSearchRequestor requestor,
+ int detailLevel,
+ int[] references,
+ IndexInput input,
+ IJavaSearchScope scope)
+ throws java.io.IOException {
+ // not used
+ }
+
+ /**
+ * see SearchPattern#findMatches
+ */
+ public void findIndexMatches(
+ IndexInput input,
+ IIndexSearchRequestor requestor,
+ int detailLevel,
+ IProgressMonitor progressMonitor,
+ IJavaSearchScope scope)
+ throws IOException {
+ // package declarations are not indexed
+ }
+
+ /**
+ * @see SearchPattern#indexEntryPrefix
+ */
+ public char[] indexEntryPrefix() {
+ // not used
+ return null;
+ }
+
+ /**
+ * @see SearchPattern#matchContainer
+ */
+ protected int matchContainer() {
+ // used only in the case of a OrPattern
+ return 0;
+ }
+
+ /**
+ * @see SearchPattern#matches(AstNode, boolean)
+ */
+ protected boolean matches(AstNode node, boolean resolve) {
+ // used only in the case of a OrPattern
+ return true;
+ }
+
+ /**
+ * @see SearchPattern#matchIndexEntry
+ */
+ protected boolean matchIndexEntry() {
+ // used only in the case of a OrPattern
+ return true;
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer(20);
+ buffer.append("PackageDeclarationPattern: <");
+ if (this.pkgName != null)
+ buffer.append(this.pkgName);
+ buffer.append(">, ");
+ switch (matchMode) {
+ case EXACT_MATCH :
+ buffer.append("exact match, ");
+ break;
+ case PREFIX_MATCH :
+ buffer.append("prefix match, ");
+ break;
+ case PATTERN_MATCH :
+ buffer.append("pattern match, ");
+ break;
+ }
+ if (isCaseSensitive)
+ buffer.append("case sensitive");
+ else
+ buffer.append("case insensitive");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageReferencePattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageReferencePattern.java
new file mode 100644
index 0000000000..be2671fc79
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageReferencePattern.java
@@ -0,0 +1,341 @@
+package org.eclipse.jdt.internal.core.search.matching;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.core.search.*;
+
+import org.eclipse.jdt.internal.core.index.impl.*;
+import org.eclipse.jdt.internal.core.search.indexing.AbstractIndexer;
+import org.eclipse.jdt.internal.core.search.IIndexSearchRequestor;
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.util.CharOperation;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+import java.io.IOException;
+
+public class PackageReferencePattern extends AndPattern {
+ private static char[][] TAGS = { REF };
+ private char[] pkgName;
+
+ private char[][] segments;
+ private int currentSegment;
+ private char[] decodedSegment;
+ public PackageReferencePattern(
+ char[] pkgName,
+ int matchMode,
+ boolean isCaseSensitive) {
+ super(matchMode, isCaseSensitive);
+ this.pkgName = pkgName;
+ char[][] splittedName = CharOperation.splitOn('.', pkgName);
+ this.segments =
+ splittedName == TypeConstants.NoCharChar ? new char[][] { pkgName }
+ : splittedName;
+ this.needsResolve = pkgName != null;
+ }
+
+ /**
+ * ref/name (where name is the last segment of the package name)
+ * @see SearchPattern#decodeIndexEntry
+ */
+ public void decodeIndexEntry(IEntryResult entryResult) {
+
+ char[] word = entryResult.getWord();
+ int size = word.length;
+ int tagLength = REF.length;
+ int nameLength = CharOperation.indexOf(SEPARATOR, word, tagLength);
+ if (nameLength < 0)
+ nameLength = size;
+ this.decodedSegment = CharOperation.subarray(word, tagLength, nameLength);
+ }
+
+ /**
+ * @see SearchPattern#feedIndexRequestor
+ */
+ public void feedIndexRequestor(
+ IIndexSearchRequestor requestor,
+ int detailLevel,
+ int[] references,
+ IndexInput input,
+ IJavaSearchScope scope)
+ throws IOException {
+ for (int i = 0, max = references.length; i < max; i++) {
+ int reference = references[i];
+ if (reference != -1) { // if the reference has not been eliminated
+ IndexedFile file = input.getIndexedFile(reference);
+ String path;
+ if (file != null
+ && scope.encloses(path = IndexedFile.convertPath(file.getPath()))) {
+ requestor.acceptPackageReference(path, this.pkgName);
+ }
+ }
+ }
+ }
+
+ protected char[][] getPossibleTags() {
+ return TAGS;
+ }
+
+ /**
+ * @see AndPattern#hasNextQuery
+ */
+ protected boolean hasNextQuery() {
+ if (this.segments.length > 2) {
+ // if package has more than 2 segments, don't look at the first 2 since they are mostly
+ // redundant (eg. in 'org.eclipse.jdt.core.*', 'com.ibm' is used all the time)
+ return --this.currentSegment >= 2;
+ } else {
+ return --this.currentSegment >= 0;
+ }
+ }
+
+ /**
+ * @see SearchPattern#indexEntryPrefix
+ */
+ public char[] indexEntryPrefix() {
+ return AbstractIndexer.bestReferencePrefix(
+ REF,
+ this.segments[this.currentSegment],
+ matchMode,
+ isCaseSensitive);
+ }
+
+ /**
+ * @see SearchPattern#matchContainer
+ */
+ protected int matchContainer() {
+ return COMPILATION_UNIT | CLASS | METHOD | FIELD;
+ }
+
+ /**
+ * Returns whether this package reference pattern matches the given tokens.
+ */
+ private boolean matches(char[][] tokens) {
+ char[] name = CharOperation.concatWith(tokens, '.');
+ return this.matchesName(this.pkgName, name);
+ }
+
+ /**
+ * @see SearchPattern#matches(AstNode, boolean)
+ */
+ protected boolean matches(AstNode node, boolean resolve) {
+ if (node instanceof QualifiedTypeReference) {
+ return this.matches((QualifiedTypeReference) node, resolve);
+ } else
+ if (node instanceof ImportReference) {
+ return this.matches((ImportReference) node, resolve);
+ } else
+ if (node instanceof QualifiedNameReference) {
+ return this.matches((QualifiedNameReference) node, resolve);
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether this package reference pattern matches the given import reference.
+ * Look at resolved information only if specified.
+ */
+ private boolean matches(ImportReference importRef, boolean resolve) {
+ if (importRef.onDemand) {
+ return this.matches(importRef.tokens);
+ } else {
+ int length = importRef.tokens.length - 1;
+ char[][] tokens = new char[length][];
+ System.arraycopy(importRef.tokens, 0, tokens, 0, length);
+ return this.matches(tokens);
+ }
+ }
+
+ /**
+ * Returns whether this package reference pattern matches the given qualified name reference.
+ * Look at resolved information only if specified.
+ */
+ private boolean matches(QualifiedNameReference qNameRef, boolean resolve) {
+ Binding binding = qNameRef.binding;
+ if (!resolve || binding == null || !binding.isValidBinding()) {
+ if (this.pkgName != null) {
+ switch (this.matchMode) {
+ case EXACT_MATCH :
+ case PREFIX_MATCH :
+ return CharOperation.prefixEquals(
+ this.pkgName,
+ CharOperation.concatWith(qNameRef.tokens, '.'),
+ this.isCaseSensitive);
+ case PATTERN_MATCH :
+ char[] pattern =
+ this.pkgName[this.pkgName.length - 1] == '*'
+ ? this.pkgName
+ : CharOperation.concat(this.pkgName, ".*".toCharArray());
+ return CharOperation.match(
+ pattern,
+ CharOperation.concatWith(qNameRef.tokens, '.'),
+ this.isCaseSensitive);
+ }
+ }
+ } else {
+ TypeBinding typeBinding = null;
+ char[][] tokens = qNameRef.tokens;
+ int lastIndex = tokens.length - 1;
+ switch (qNameRef.bits & Statement.RestrictiveFlagMASK) {
+ case BindingIds.FIELD : // reading a field
+ typeBinding = ((FieldBinding) binding).declaringClass;
+ // no valid match amongst fields
+ int otherBindingsCount =
+ qNameRef.otherBindings == null ? 0 : qNameRef.otherBindings.length;
+ lastIndex -= otherBindingsCount + 1;
+ if (lastIndex < 0)
+ return false;
+ break;
+ case BindingIds.LOCAL : // reading a local variable
+ return false; // no package match in it
+ case BindingIds.TYPE : //=============only type ==============
+ typeBinding = (TypeBinding) binding;
+ }
+ if (typeBinding instanceof ArrayBinding) {
+ typeBinding = ((ArrayBinding) typeBinding).leafComponentType;
+ }
+ if (typeBinding instanceof ReferenceBinding) {
+ PackageBinding pkgBinding = ((ReferenceBinding) typeBinding).fPackage;
+ return this.matches(pkgBinding.compoundName);
+ }
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns whether this package reference pattern matches the given type reference.
+ * Look at resolved information only if specified.
+ */
+ private boolean matches(QualifiedTypeReference typeRef, boolean resolve) {
+ if (!resolve) {
+ if (this.pkgName != null) {
+ switch (this.matchMode) {
+ case EXACT_MATCH :
+ case PREFIX_MATCH :
+ return CharOperation.prefixEquals(
+ this.pkgName,
+ CharOperation.concatWith(typeRef.tokens, '.'),
+ this.isCaseSensitive);
+ case PATTERN_MATCH :
+ char[] pattern =
+ this.pkgName[this.pkgName.length - 1] == '*'
+ ? this.pkgName
+ : CharOperation.concat(this.pkgName, ".*".toCharArray());
+ return CharOperation.match(
+ pattern,
+ CharOperation.concatWith(typeRef.tokens, '.'),
+ this.isCaseSensitive);
+ }
+ }
+ } else {
+ TypeBinding typeBinding = typeRef.binding;
+ if (typeBinding != null) {
+ if (typeBinding instanceof ArrayBinding) {
+ typeBinding = ((ArrayBinding) typeBinding).leafComponentType;
+ }
+ if (typeBinding instanceof ReferenceBinding) {
+ PackageBinding pkgBinding = ((ReferenceBinding) typeBinding).fPackage;
+ return this.matches(pkgBinding.compoundName);
+ }
+ return false;
+ }
+
+ }
+ return true;
+ }
+
+ /**
+ * @see SearchPattern#matchIndexEntry
+ */
+ protected boolean matchIndexEntry() {
+ switch (matchMode) {
+ case EXACT_MATCH :
+ if (!CharOperation
+ .equals(
+ this.segments[this.currentSegment],
+ this.decodedSegment,
+ isCaseSensitive)) {
+ return false;
+ }
+ break;
+ case PREFIX_MATCH :
+ if (!CharOperation
+ .prefixEquals(
+ this.segments[this.currentSegment],
+ this.decodedSegment,
+ isCaseSensitive)) {
+ return false;
+ }
+ break;
+ case PATTERN_MATCH :
+ if (!CharOperation
+ .match(
+ this.segments[this.currentSegment],
+ this.decodedSegment,
+ isCaseSensitive)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @see SearchPattern#matchReportReference
+ */
+ protected void matchReportReference(
+ AstNode reference,
+ IJavaElement element,
+ int accuracy,
+ MatchLocator locator)
+ throws CoreException {
+ char[][] splitName =
+ CharOperation.splitOn('.', this.pkgName == null ? new char[0] : this.pkgName);
+ locator.reportQualifiedReference(
+ reference.sourceStart,
+ reference.sourceEnd,
+ splitName,
+ element,
+ accuracy);
+ }
+
+ /**
+ * @see AndPattern#resetQuery
+ */
+ protected void resetQuery() {
+ /* walk the segments from end to start as it will find less potential references using 'lang' than 'java' */
+ this.currentSegment = this.segments.length - 1;
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer(20);
+ buffer.append("PackageReferencePattern: <");
+ if (this.pkgName != null)
+ buffer.append(this.pkgName);
+ buffer.append(">, ");
+ switch (matchMode) {
+ case EXACT_MATCH :
+ buffer.append("exact match, ");
+ break;
+ case PREFIX_MATCH :
+ buffer.append("prefix match, ");
+ break;
+ case PATTERN_MATCH :
+ buffer.append("pattern match, ");
+ break;
+ }
+ if (isCaseSensitive)
+ buffer.append("case sensitive");
+ else
+ buffer.append("case insensitive");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SearchPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SearchPattern.java
new file mode 100644
index 0000000000..45b3a22f23
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SearchPattern.java
@@ -0,0 +1,1454 @@
+package org.eclipse.jdt.internal.core.search.matching;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.core.search.*;
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+
+import org.eclipse.jdt.internal.core.index.impl.IndexInput;
+import org.eclipse.jdt.internal.core.index.impl.IndexedFile;
+import org.eclipse.jdt.internal.core.index.impl.BlocksIndexInput;
+import org.eclipse.jdt.internal.core.search.*;
+import org.eclipse.jdt.internal.core.search.indexing.*;
+
+import java.io.*;
+import java.util.*;
+
+public abstract class SearchPattern
+ implements ISearchPattern, IIndexConstants, IJavaSearchConstants {
+
+ protected int matchMode;
+ protected boolean isCaseSensitive;
+ protected boolean needsResolve;
+
+ /* match level */
+ public static final int IMPOSSIBLE_MATCH = 0;
+ public static final int POSSIBLE_MATCH = 1;
+ public static final int TRUSTED_MATCH = 2;
+
+ /* match container */
+ public static final int COMPILATION_UNIT = 1;
+ public static final int CLASS = 2;
+ public static final int FIELD = 4;
+ public static final int METHOD = 8;
+
+ public SearchPattern(int matchMode, boolean isCaseSensitive) {
+ this.matchMode = matchMode;
+ this.isCaseSensitive = isCaseSensitive;
+ }
+
+ /**
+ * Constructor pattern are formed by [declaringQualification.]type[(parameterTypes)]
+ * e.g. java.lang.Runnable.run() void
+ * main(*)
+ */
+ private static SearchPattern createConstructorPattern(
+ String patternString,
+ int limitTo,
+ int matchMode,
+ boolean isCaseSensitive) {
+
+ StringTokenizer tokenizer = new StringTokenizer(patternString, " .(,)", true);
+ final int InsideName = 1;
+ final int InsideParameter = 2;
+ String lastToken = null;
+
+ String declaringQualification = null, typeName = null, parameterType = null;
+ String[] parameterTypes = null;
+ int parameterCount = -1;
+ String returnType = null;
+ boolean foundClosingParenthesis = false;
+ int mode = InsideName;
+ while (tokenizer.hasMoreTokens()) {
+ String token = tokenizer.nextToken();
+ switch (mode) {
+
+ // read declaring type and selector
+ case InsideName :
+ if (token.equals(".")) {
+ if (declaringQualification == null) {
+ if (typeName == null)
+ return null;
+ declaringQualification = typeName;
+ } else {
+ declaringQualification += token + typeName;
+ }
+ typeName = null;
+ } else
+ if (token.equals("(")) {
+ parameterTypes = new String[5];
+ parameterCount = 0;
+ mode = InsideParameter;
+ } else
+ if (token.equals(" ")) {
+ if (!(" ".equals(lastToken) || ".".equals(lastToken))) {
+ break;
+ }
+ } else { // name
+ if (typeName != null)
+ return null;
+ typeName = token;
+ }
+ break;
+ // read parameter types
+ case InsideParameter :
+ if (token.equals(" ")) {
+ } else
+ if (token.equals(",")) {
+ if (parameterType == null)
+ return null;
+ if (parameterTypes.length == parameterCount) {
+ System.arraycopy(
+ parameterTypes,
+ 0,
+ parameterTypes = new String[parameterCount * 2],
+ 0,
+ parameterCount);
+ }
+ parameterTypes[parameterCount++] = parameterType;
+ parameterType = null;
+ } else
+ if (token.equals(")")) {
+ foundClosingParenthesis = true;
+ if (parameterType != null) {
+ if (parameterTypes.length == parameterCount) {
+ System.arraycopy(
+ parameterTypes,
+ 0,
+ parameterTypes = new String[parameterCount * 2],
+ 0,
+ parameterCount);
+ }
+ parameterTypes[parameterCount++] = parameterType;
+ }
+ break;
+ } else {
+ if (parameterType == null) {
+ parameterType = token;
+ } else {
+ if (!(".".equals(lastToken) || ".".equals(token) || "[]".equals(token)))
+ return null;
+ parameterType += token;
+ }
+ }
+ break;
+ }
+ lastToken = token;
+ }
+ // parenthesis mismatch
+ if (parameterCount > 0 && !foundClosingParenthesis)
+ return null;
+ if (typeName == null)
+ return null;
+
+ char[] typeNameChars = typeName.toCharArray();
+ if (typeNameChars.length == 1 && typeNameChars[0] == '*')
+ typeNameChars = null;
+
+ char[] declaringQualificationChars = null;
+ if (declaringQualification != null)
+ declaringQualificationChars = declaringQualification.toCharArray();
+ char[][] parameterTypeQualifications = null, parameterTypeSimpleNames = null;
+
+ // extract parameter types infos
+ if (parameterCount >= 0) {
+ parameterTypeQualifications = new char[parameterCount][];
+ parameterTypeSimpleNames = new char[parameterCount][];
+ for (int i = 0; i < parameterCount; i++) {
+ char[] parameterTypePart = parameterTypes[i].toCharArray();
+ int lastDotPosition = CharOperation.lastIndexOf('.', parameterTypePart);
+ if (lastDotPosition >= 0) {
+ parameterTypeQualifications[i] =
+ CharOperation.subarray(parameterTypePart, 0, lastDotPosition);
+ if (parameterTypeQualifications[i].length == 1
+ && parameterTypeQualifications[i][0] == '*')
+ parameterTypeQualifications[i] = null;
+ parameterTypeSimpleNames[i] =
+ CharOperation.subarray(
+ parameterTypePart,
+ lastDotPosition + 1,
+ parameterTypePart.length);
+ } else {
+ parameterTypeQualifications[i] = null;
+ parameterTypeSimpleNames[i] = parameterTypePart;
+ }
+ if (parameterTypeSimpleNames[i].length == 1
+ && parameterTypeSimpleNames[i][0] == '*')
+ parameterTypeSimpleNames[i] = null;
+ }
+ }
+ SearchPattern searchPattern = null;
+ switch (limitTo) {
+ case IJavaSearchConstants.DECLARATIONS :
+ searchPattern =
+ new ConstructorDeclarationPattern(
+ typeNameChars,
+ matchMode,
+ isCaseSensitive,
+ declaringQualificationChars,
+ parameterTypeQualifications,
+ parameterTypeSimpleNames);
+ break;
+ case IJavaSearchConstants.REFERENCES :
+ searchPattern =
+ new ConstructorReferencePattern(
+ typeNameChars,
+ matchMode,
+ isCaseSensitive,
+ declaringQualificationChars,
+ parameterTypeQualifications,
+ parameterTypeSimpleNames);
+ break;
+ case IJavaSearchConstants.ALL_OCCURRENCES :
+ searchPattern =
+ new OrPattern(
+ new ConstructorDeclarationPattern(
+ typeNameChars,
+ matchMode,
+ isCaseSensitive,
+ declaringQualificationChars,
+ parameterTypeQualifications,
+ parameterTypeSimpleNames),
+ new ConstructorReferencePattern(
+ typeNameChars,
+ matchMode,
+ isCaseSensitive,
+ declaringQualificationChars,
+ parameterTypeQualifications,
+ parameterTypeSimpleNames));
+ break;
+ }
+ return searchPattern;
+
+ }
+
+ /**
+ * Field pattern are formed by [declaringType.]name[type]
+ * e.g. java.lang.Runnable.run() void
+ * main(*)
+ */
+ private static SearchPattern createFieldPattern(
+ String patternString,
+ int limitTo,
+ int matchMode,
+ boolean isCaseSensitive) {
+
+ StringTokenizer tokenizer = new StringTokenizer(patternString, " .(,)", true);
+ final int InsideDeclaringPart = 1;
+ final int InsideType = 2;
+ String lastToken = null;
+
+ String declaringType = null, fieldName = null, parameterType = null;
+ String type = null;
+ boolean foundClosingParenthesis = false;
+ int mode = InsideDeclaringPart;
+ while (tokenizer.hasMoreTokens()) {
+ String token = tokenizer.nextToken();
+ switch (mode) {
+
+ // read declaring type and fieldName
+ case InsideDeclaringPart :
+ if (token.equals(".")) {
+ if (declaringType == null) {
+ if (fieldName == null)
+ return null;
+ declaringType = fieldName;
+ } else {
+ declaringType += token + fieldName;
+ }
+ fieldName = null;
+ } else
+ if (token.equals(" ")) {
+ if (!(" ".equals(lastToken) || ".".equals(lastToken))) {
+ mode = InsideType;
+ }
+ } else { // name
+ if (fieldName != null)
+ return null;
+ fieldName = token;
+ }
+ break;
+ // read type
+ case InsideType :
+ if (!token.equals(" ")) {
+ if (type == null) {
+ type = token;
+ } else {
+ if (!(!(".".equals(lastToken) || ".".equals(token) || "[]".equals(token))))
+ return null;
+ type += token;
+ }
+ }
+ }
+ lastToken = token;
+ }
+ if (fieldName == null)
+ return null;
+
+ char[] fieldNameChars = fieldName.toCharArray();
+ if (fieldNameChars.length == 1 && fieldNameChars[0] == '*')
+ fieldNameChars = null;
+
+ char[] declaringTypeQualification = null, declaringTypeSimpleName = null;
+ char[] typeQualification = null, typeSimpleName = null;
+
+ // extract declaring type infos
+ if (declaringType != null) {
+ char[] declaringTypePart = declaringType.toCharArray();
+ int lastDotPosition = CharOperation.lastIndexOf('.', declaringTypePart);
+ if (lastDotPosition >= 0) {
+ declaringTypeQualification =
+ CharOperation.subarray(declaringTypePart, 0, lastDotPosition);
+ if (declaringTypeQualification.length == 1
+ && declaringTypeQualification[0] == '*')
+ declaringTypeQualification = null;
+ declaringTypeSimpleName =
+ CharOperation.subarray(
+ declaringTypePart,
+ lastDotPosition + 1,
+ declaringTypePart.length);
+ } else {
+ declaringTypeQualification = null;
+ declaringTypeSimpleName = declaringTypePart;
+ }
+ if (declaringTypeSimpleName.length == 1 && declaringTypeSimpleName[0] == '*')
+ declaringTypeSimpleName = null;
+ }
+ // extract type infos
+ if (type != null) {
+ char[] typePart = type.toCharArray();
+ int lastDotPosition = CharOperation.lastIndexOf('.', typePart);
+ if (lastDotPosition >= 0) {
+ typeQualification = CharOperation.subarray(typePart, 0, lastDotPosition);
+ if (typeQualification.length == 1 && typeQualification[0] == '*')
+ typeQualification = null;
+ typeSimpleName =
+ CharOperation.subarray(typePart, lastDotPosition + 1, typePart.length);
+ } else {
+ typeQualification = null;
+ typeSimpleName = typePart;
+ }
+ if (typeSimpleName.length == 1 && typeSimpleName[0] == '*')
+ typeSimpleName = null;
+ }
+ SearchPattern searchPattern = null;
+ switch (limitTo) {
+ case IJavaSearchConstants.DECLARATIONS :
+ searchPattern =
+ new FieldDeclarationPattern(
+ fieldNameChars,
+ matchMode,
+ isCaseSensitive,
+ declaringTypeQualification,
+ declaringTypeSimpleName,
+ typeQualification,
+ typeSimpleName);
+ break;
+ case IJavaSearchConstants.REFERENCES :
+ searchPattern =
+ new FieldReferencePattern(
+ fieldNameChars,
+ matchMode,
+ isCaseSensitive,
+ declaringTypeQualification,
+ declaringTypeSimpleName,
+ typeQualification,
+ typeSimpleName);
+ break;
+ case IJavaSearchConstants.ALL_OCCURRENCES :
+ searchPattern =
+ new OrPattern(
+ new FieldDeclarationPattern(
+ fieldNameChars,
+ matchMode,
+ isCaseSensitive,
+ declaringTypeQualification,
+ declaringTypeSimpleName,
+ typeQualification,
+ typeSimpleName),
+ new FieldReferencePattern(
+ fieldNameChars,
+ matchMode,
+ isCaseSensitive,
+ declaringTypeQualification,
+ declaringTypeSimpleName,
+ typeQualification,
+ typeSimpleName));
+ break;
+ }
+ return searchPattern;
+
+ }
+
+ /**
+ * Method pattern are formed by [declaringType.]selector[(parameterTypes)][returnType]
+ * e.g. java.lang.Runnable.run() void
+ * main(*)
+ */
+ private static SearchPattern createMethodPattern(
+ String patternString,
+ int limitTo,
+ int matchMode,
+ boolean isCaseSensitive) {
+
+ StringTokenizer tokenizer = new StringTokenizer(patternString, " .(,)", true);
+ final int InsideSelector = 1;
+ final int InsideParameter = 2;
+ final int InsideReturnType = 3;
+ String lastToken = null;
+
+ String declaringType = null, selector = null, parameterType = null;
+ String[] parameterTypes = null;
+ int parameterCount = -1;
+ String returnType = null;
+ boolean foundClosingParenthesis = false;
+ int mode = InsideSelector;
+ while (tokenizer.hasMoreTokens()) {
+ String token = tokenizer.nextToken();
+ switch (mode) {
+
+ // read declaring type and selector
+ case InsideSelector :
+ if (token.equals(".")) {
+ if (declaringType == null) {
+ if (selector == null)
+ return null;
+ declaringType = selector;
+ } else {
+ declaringType += token + selector;
+ }
+ selector = null;
+ } else
+ if (token.equals("(")) {
+ parameterTypes = new String[5];
+ parameterCount = 0;
+ mode = InsideParameter;
+ } else
+ if (token.equals(" ")) {
+ if (!(" ".equals(lastToken) || ".".equals(lastToken))) {
+ mode = InsideReturnType;
+ }
+ } else { // name
+ if (selector != null)
+ return null;
+ selector = token;
+ }
+ break;
+ // read parameter types
+ case InsideParameter :
+ if (token.equals(" ")) {
+ } else
+ if (token.equals(",")) {
+ if (parameterType == null)
+ return null;
+ if (parameterTypes.length == parameterCount) {
+ System.arraycopy(
+ parameterTypes,
+ 0,
+ parameterTypes = new String[parameterCount * 2],
+ 0,
+ parameterCount);
+ }
+ parameterTypes[parameterCount++] = parameterType;
+ parameterType = null;
+ } else
+ if (token.equals(")")) {
+ foundClosingParenthesis = true;
+ if (parameterType != null) {
+ if (parameterTypes.length == parameterCount) {
+ System.arraycopy(
+ parameterTypes,
+ 0,
+ parameterTypes = new String[parameterCount * 2],
+ 0,
+ parameterCount);
+ }
+ parameterTypes[parameterCount++] = parameterType;
+ }
+ mode = InsideReturnType;
+ } else {
+ if (parameterType == null) {
+ parameterType = token;
+ } else {
+ if (!(".".equals(lastToken) || ".".equals(token) || "[]".equals(token)))
+ return null;
+ parameterType += token;
+ }
+ }
+ break;
+ // read return type
+ case InsideReturnType :
+ if (!token.equals(" ")) {
+ if (returnType == null) {
+ returnType = token;
+ } else {
+ if (!(!(".".equals(lastToken) || ".".equals(token) || "[]".equals(token))))
+ return null;
+ returnType += token;
+ }
+ }
+ }
+ lastToken = token;
+ }
+ // parenthesis mismatch
+ if (parameterCount > 0 && !foundClosingParenthesis)
+ return null;
+ if (selector == null)
+ return null;
+
+ char[] selectorChars = selector.toCharArray();
+ if (selectorChars.length == 1 && selectorChars[0] == '*')
+ selectorChars = null;
+
+ char[] declaringTypeQualification = null, declaringTypeSimpleName = null;
+ char[] returnTypeQualification = null, returnTypeSimpleName = null;
+ char[][] parameterTypeQualifications = null, parameterTypeSimpleNames = null;
+
+ // extract declaring type infos
+ if (declaringType != null) {
+ char[] declaringTypePart = declaringType.toCharArray();
+ int lastDotPosition = CharOperation.lastIndexOf('.', declaringTypePart);
+ if (lastDotPosition >= 0) {
+ declaringTypeQualification =
+ CharOperation.subarray(declaringTypePart, 0, lastDotPosition);
+ if (declaringTypeQualification.length == 1
+ && declaringTypeQualification[0] == '*')
+ declaringTypeQualification = null;
+ declaringTypeSimpleName =
+ CharOperation.subarray(
+ declaringTypePart,
+ lastDotPosition + 1,
+ declaringTypePart.length);
+ } else {
+ declaringTypeQualification = null;
+ declaringTypeSimpleName = declaringTypePart;
+ }
+ if (declaringTypeSimpleName.length == 1 && declaringTypeSimpleName[0] == '*')
+ declaringTypeSimpleName = null;
+ }
+ // extract parameter types infos
+ if (parameterCount >= 0) {
+ parameterTypeQualifications = new char[parameterCount][];
+ parameterTypeSimpleNames = new char[parameterCount][];
+ for (int i = 0; i < parameterCount; i++) {
+ char[] parameterTypePart = parameterTypes[i].toCharArray();
+ int lastDotPosition = CharOperation.lastIndexOf('.', parameterTypePart);
+ if (lastDotPosition >= 0) {
+ parameterTypeQualifications[i] =
+ CharOperation.subarray(parameterTypePart, 0, lastDotPosition);
+ if (parameterTypeQualifications[i].length == 1
+ && parameterTypeQualifications[i][0] == '*')
+ parameterTypeQualifications[i] = null;
+ parameterTypeSimpleNames[i] =
+ CharOperation.subarray(
+ parameterTypePart,
+ lastDotPosition + 1,
+ parameterTypePart.length);
+ } else {
+ parameterTypeQualifications[i] = null;
+ parameterTypeSimpleNames[i] = parameterTypePart;
+ }
+ if (parameterTypeSimpleNames[i].length == 1
+ && parameterTypeSimpleNames[i][0] == '*')
+ parameterTypeSimpleNames[i] = null;
+ }
+ }
+ // extract return type infos
+ if (returnType != null) {
+ char[] returnTypePart = returnType.toCharArray();
+ int lastDotPosition = CharOperation.lastIndexOf('.', returnTypePart);
+ if (lastDotPosition >= 0) {
+ returnTypeQualification =
+ CharOperation.subarray(returnTypePart, 0, lastDotPosition);
+ if (returnTypeQualification.length == 1 && returnTypeQualification[0] == '*')
+ returnTypeQualification = null;
+ returnTypeSimpleName =
+ CharOperation.subarray(
+ returnTypePart,
+ lastDotPosition + 1,
+ returnTypePart.length);
+ } else {
+ returnTypeQualification = null;
+ returnTypeSimpleName = returnTypePart;
+ }
+ if (returnTypeSimpleName.length == 1 && returnTypeSimpleName[0] == '*')
+ returnTypeSimpleName = null;
+ }
+ SearchPattern searchPattern = null;
+ switch (limitTo) {
+ case IJavaSearchConstants.DECLARATIONS :
+ searchPattern =
+ new MethodDeclarationPattern(
+ selectorChars,
+ matchMode,
+ isCaseSensitive,
+ declaringTypeQualification,
+ declaringTypeSimpleName,
+ returnTypeQualification,
+ returnTypeSimpleName,
+ parameterTypeQualifications,
+ parameterTypeSimpleNames);
+ break;
+ case IJavaSearchConstants.REFERENCES :
+ searchPattern =
+ new MethodReferencePattern(
+ selectorChars,
+ matchMode,
+ isCaseSensitive,
+ declaringTypeQualification,
+ declaringTypeSimpleName,
+ returnTypeQualification,
+ returnTypeSimpleName,
+ parameterTypeQualifications,
+ parameterTypeSimpleNames);
+ break;
+ case IJavaSearchConstants.ALL_OCCURRENCES :
+ searchPattern =
+ new OrPattern(
+ new MethodDeclarationPattern(
+ selectorChars,
+ matchMode,
+ isCaseSensitive,
+ declaringTypeQualification,
+ declaringTypeSimpleName,
+ returnTypeQualification,
+ returnTypeSimpleName,
+ parameterTypeQualifications,
+ parameterTypeSimpleNames),
+ new MethodReferencePattern(
+ selectorChars,
+ matchMode,
+ isCaseSensitive,
+ declaringTypeQualification,
+ declaringTypeSimpleName,
+ returnTypeQualification,
+ returnTypeSimpleName,
+ parameterTypeQualifications,
+ parameterTypeSimpleNames));
+ break;
+ }
+ return searchPattern;
+
+ }
+
+ private static SearchPattern createPackagePattern(
+ String patternString,
+ int limitTo,
+ int matchMode,
+ boolean isCaseSensitive) {
+ SearchPattern searchPattern = null;
+ switch (limitTo) {
+ case IJavaSearchConstants.DECLARATIONS :
+ searchPattern =
+ new PackageDeclarationPattern(
+ patternString.toCharArray(),
+ matchMode,
+ isCaseSensitive);
+ break;
+ case IJavaSearchConstants.REFERENCES :
+ searchPattern =
+ new PackageReferencePattern(
+ patternString.toCharArray(),
+ matchMode,
+ isCaseSensitive);
+ break;
+ case IJavaSearchConstants.ALL_OCCURRENCES :
+ searchPattern =
+ new OrPattern(
+ new PackageDeclarationPattern(
+ patternString.toCharArray(),
+ matchMode,
+ isCaseSensitive),
+ new PackageReferencePattern(
+ patternString.toCharArray(),
+ matchMode,
+ isCaseSensitive));
+ break;
+ }
+ return searchPattern;
+
+ }
+
+ public static SearchPattern createPattern(
+ String patternString,
+ int searchFor,
+ int limitTo,
+ int matchMode,
+ boolean isCaseSensitive) {
+
+ if (patternString == null || patternString.length() == 0)
+ return null;
+
+ SearchPattern searchPattern = null;
+ switch (searchFor) {
+
+ case IJavaSearchConstants.TYPE :
+ searchPattern =
+ createTypePattern(patternString, limitTo, matchMode, isCaseSensitive);
+ break;
+ case IJavaSearchConstants.METHOD :
+ searchPattern =
+ createMethodPattern(patternString, limitTo, matchMode, isCaseSensitive);
+ break;
+ case IJavaSearchConstants.CONSTRUCTOR :
+ searchPattern =
+ createConstructorPattern(patternString, limitTo, matchMode, isCaseSensitive);
+ break;
+ case IJavaSearchConstants.FIELD :
+ searchPattern =
+ createFieldPattern(patternString, limitTo, matchMode, isCaseSensitive);
+ break;
+ case IJavaSearchConstants.PACKAGE :
+ searchPattern =
+ createPackagePattern(patternString, limitTo, matchMode, isCaseSensitive);
+ }
+ return searchPattern;
+ }
+
+ public static SearchPattern createPattern(IJavaElement element, int limitTo) {
+ SearchPattern searchPattern = null;
+ int lastDot;
+ switch (element.getElementType()) {
+ case IJavaElement.FIELD :
+ IField field = (IField) element;
+ String fullDeclaringName =
+ field.getDeclaringType().getFullyQualifiedName().replace('$', '.');
+ ;
+ lastDot = fullDeclaringName.lastIndexOf('.');
+ char[] declaringSimpleName =
+ (lastDot != -1 ? fullDeclaringName.substring(lastDot + 1) : fullDeclaringName)
+ .toCharArray();
+ char[] declaringQualification =
+ lastDot != -1 ? fullDeclaringName.substring(0, lastDot).toCharArray() : null;
+ char[] name = field.getElementName().toCharArray();
+ char[] typeSimpleName;
+ char[] typeQualification;
+ try {
+ String typeSignature =
+ Signature.toString(field.getTypeSignature()).replace('$', '.');
+ lastDot = typeSignature.lastIndexOf('.');
+ typeSimpleName =
+ (lastDot != -1 ? typeSignature.substring(lastDot + 1) : typeSignature)
+ .toCharArray();
+ typeQualification =
+ lastDot != -1 ? typeSignature.substring(0, lastDot).toCharArray() : null;
+ } catch (JavaModelException e) {
+ return null;
+ }
+ switch (limitTo) {
+ case IJavaSearchConstants.DECLARATIONS :
+ searchPattern =
+ new FieldDeclarationPattern(
+ name,
+ EXACT_MATCH,
+ CASE_SENSITIVE,
+ declaringQualification,
+ declaringSimpleName,
+ typeQualification,
+ typeSimpleName);
+ break;
+ case IJavaSearchConstants.REFERENCES :
+ searchPattern =
+ new FieldReferencePattern(
+ name,
+ EXACT_MATCH,
+ CASE_SENSITIVE,
+ declaringQualification,
+ declaringSimpleName,
+ typeQualification,
+ typeSimpleName);
+ break;
+ case IJavaSearchConstants.ALL_OCCURRENCES :
+ searchPattern =
+ new OrPattern(
+ new FieldDeclarationPattern(
+ name,
+ EXACT_MATCH,
+ CASE_SENSITIVE,
+ declaringQualification,
+ declaringSimpleName,
+ typeQualification,
+ typeSimpleName),
+ new FieldReferencePattern(
+ name,
+ EXACT_MATCH,
+ CASE_SENSITIVE,
+ declaringQualification,
+ declaringSimpleName,
+ typeQualification,
+ typeSimpleName));
+ break;
+ }
+ break;
+ case IJavaElement.IMPORT_DECLARATION :
+ String elementName = element.getElementName();
+ IImportDeclaration importDecl = (IImportDeclaration) element;
+ if (importDecl.isOnDemand()) {
+ lastDot = elementName.lastIndexOf('.');
+ if (lastDot == -1)
+ return null; // invalid import declaration
+ searchPattern =
+ createPackagePattern(
+ elementName.substring(0, lastDot),
+ limitTo,
+ EXACT_MATCH,
+ CASE_SENSITIVE);
+ } else {
+ searchPattern = createTypePattern(elementName, limitTo);
+ }
+ break;
+ case IJavaElement.METHOD :
+ IMethod method = (IMethod) element;
+ boolean isConstructor;
+ try {
+ isConstructor = method.isConstructor();
+ } catch (JavaModelException e) {
+ return null;
+ }
+ fullDeclaringName =
+ method.getDeclaringType().getFullyQualifiedName().replace('$', '.');
+ lastDot = fullDeclaringName.lastIndexOf('.');
+ declaringSimpleName =
+ (lastDot != -1 ? fullDeclaringName.substring(lastDot + 1) : fullDeclaringName)
+ .toCharArray();
+ declaringQualification =
+ lastDot != -1 ? fullDeclaringName.substring(0, lastDot).toCharArray() : null;
+ char[] selector = method.getElementName().toCharArray();
+ char[] returnSimpleName;
+ char[] returnQualification;
+ try {
+ String returnType =
+ Signature.toString(method.getReturnType()).replace('$', '.');
+ lastDot = returnType.lastIndexOf('.');
+ returnSimpleName =
+ (lastDot != -1 ? returnType.substring(lastDot + 1) : returnType).toCharArray();
+ returnQualification =
+ lastDot != -1 ? returnType.substring(0, lastDot).toCharArray() : null;
+ } catch (JavaModelException e) {
+ return null;
+ }
+ String[] parameterTypes = method.getParameterTypes();
+ int paramCount = parameterTypes.length;
+ char[][] parameterSimpleNames = new char[paramCount][];
+ char[][] parameterQualifications = new char[paramCount][];
+ for (int i = 0; i < paramCount; i++) {
+ String signature = Signature.toString(parameterTypes[i]).replace('$', '.');
+ lastDot = signature.lastIndexOf('.');
+ parameterSimpleNames[i] =
+ (lastDot != -1 ? signature.substring(lastDot + 1) : signature).toCharArray();
+ parameterQualifications[i] =
+ lastDot != -1 ? signature.substring(0, lastDot).toCharArray() : null;
+ }
+ switch (limitTo) {
+ case IJavaSearchConstants.DECLARATIONS :
+ if (isConstructor) {
+ searchPattern =
+ new ConstructorDeclarationPattern(
+ declaringSimpleName,
+ EXACT_MATCH,
+ CASE_SENSITIVE,
+ declaringQualification,
+ parameterQualifications,
+ parameterSimpleNames);
+ } else {
+ searchPattern =
+ new MethodDeclarationPattern(
+ selector,
+ EXACT_MATCH,
+ CASE_SENSITIVE,
+ declaringQualification,
+ declaringSimpleName,
+ returnQualification,
+ returnSimpleName,
+ parameterQualifications,
+ parameterSimpleNames);
+ }
+ break;
+ case IJavaSearchConstants.REFERENCES :
+ if (isConstructor) {
+ searchPattern =
+ new ConstructorReferencePattern(
+ declaringSimpleName,
+ EXACT_MATCH,
+ CASE_SENSITIVE,
+ declaringQualification,
+ parameterQualifications,
+ parameterSimpleNames);
+ } else {
+ searchPattern =
+ new MethodReferencePattern(
+ selector,
+ EXACT_MATCH,
+ CASE_SENSITIVE,
+ declaringQualification,
+ declaringSimpleName,
+ returnQualification,
+ returnSimpleName,
+ parameterQualifications,
+ parameterSimpleNames);
+ }
+ break;
+ case IJavaSearchConstants.ALL_OCCURRENCES :
+ if (isConstructor) {
+ searchPattern =
+ new OrPattern(
+ new ConstructorDeclarationPattern(
+ declaringSimpleName,
+ EXACT_MATCH,
+ CASE_SENSITIVE,
+ declaringQualification,
+ parameterQualifications,
+ parameterSimpleNames),
+ new ConstructorReferencePattern(
+ declaringSimpleName,
+ EXACT_MATCH,
+ CASE_SENSITIVE,
+ declaringQualification,
+ parameterQualifications,
+ parameterSimpleNames));
+ } else {
+ searchPattern =
+ new OrPattern(
+ new MethodDeclarationPattern(
+ selector,
+ EXACT_MATCH,
+ CASE_SENSITIVE,
+ declaringQualification,
+ declaringSimpleName,
+ returnQualification,
+ returnSimpleName,
+ parameterQualifications,
+ parameterSimpleNames),
+ new MethodReferencePattern(
+ selector,
+ EXACT_MATCH,
+ CASE_SENSITIVE,
+ declaringQualification,
+ declaringSimpleName,
+ returnQualification,
+ returnSimpleName,
+ parameterQualifications,
+ parameterSimpleNames));
+ }
+ break;
+ }
+ break;
+ case IJavaElement.TYPE :
+ IType type = (IType) element;
+ searchPattern = createTypePattern(type.getFullyQualifiedName(), limitTo);
+ break;
+ case IJavaElement.PACKAGE_DECLARATION :
+ case IJavaElement.PACKAGE_FRAGMENT :
+ searchPattern =
+ createPackagePattern(
+ element.getElementName(),
+ limitTo,
+ EXACT_MATCH,
+ CASE_SENSITIVE);
+ break;
+ }
+ return searchPattern;
+ }
+
+ private static SearchPattern createTypePattern(
+ String fullyQualifiedName,
+ int limitTo) {
+ SearchPattern searchPattern = null;
+ int lastDot = fullyQualifiedName.lastIndexOf('.');
+ int lastDollar = fullyQualifiedName.lastIndexOf('$');
+ if (lastDollar < lastDot)
+ lastDollar = -1; // must be in last segment
+ char[] enclosingTypeName, simpleName;
+ if (lastDollar >= 0) {
+ enclosingTypeName =
+ fullyQualifiedName.substring(lastDot + 1, lastDollar).toCharArray();
+ simpleName =
+ fullyQualifiedName
+ .substring(lastDollar + 1, fullyQualifiedName.length())
+ .toCharArray();
+ } else {
+ enclosingTypeName = new char[0];
+ simpleName =
+ (lastDot != -1
+ ? fullyQualifiedName.substring(lastDot + 1)
+ : fullyQualifiedName)
+ .toCharArray();
+ }
+ char[] qualification =
+ lastDot != -1 ? fullyQualifiedName.substring(0, lastDot).toCharArray() : null;
+
+ switch (limitTo) {
+ case IJavaSearchConstants.DECLARATIONS :
+ char[][] enclosingTypeNames = CharOperation.splitOn('$', enclosingTypeName);
+ searchPattern =
+ new TypeDeclarationPattern(
+ qualification,
+ enclosingTypeNames,
+ simpleName,
+ TYPE_SUFFIX,
+ EXACT_MATCH,
+ CASE_SENSITIVE);
+ break;
+ case IJavaSearchConstants.REFERENCES :
+ if (enclosingTypeName.length > 0) {
+ qualification = CharOperation.concat(qualification, enclosingTypeName, '.');
+ }
+ searchPattern =
+ new TypeReferencePattern(
+ qualification,
+ simpleName,
+ EXACT_MATCH,
+ CASE_SENSITIVE);
+ break;
+ case IJavaSearchConstants.IMPLEMENTORS :
+ searchPattern =
+ new SuperInterfaceReferencePattern(
+ qualification,
+ simpleName,
+ EXACT_MATCH,
+ CASE_SENSITIVE);
+ break;
+ case IJavaSearchConstants.ALL_OCCURRENCES :
+ enclosingTypeNames = CharOperation.splitOn('$', enclosingTypeName);
+ searchPattern =
+ new OrPattern(
+ new TypeDeclarationPattern(
+ qualification,
+ enclosingTypeNames,
+ simpleName,
+ TYPE_SUFFIX,
+ EXACT_MATCH,
+ CASE_SENSITIVE),
+ new TypeReferencePattern(
+ qualification,
+ simpleName,
+ EXACT_MATCH,
+ CASE_SENSITIVE));
+ break;
+ }
+ return searchPattern;
+ }
+
+ /**
+ * Type pattern are formed by [package.]type
+ * e.g. java.lang.Object
+ * Runnable
+ *
+ */
+ private static SearchPattern createTypePattern(
+ String patternString,
+ int limitTo,
+ int matchMode,
+ boolean isCaseSensitive) {
+
+ StringTokenizer tokenizer = new StringTokenizer(patternString, " .", true);
+ String type = null;
+ String lastToken = null;
+ while (tokenizer.hasMoreTokens()) {
+ String token = tokenizer.nextToken();
+ if (!token.equals(" ")) {
+ if (type == null) {
+ type = token;
+ } else {
+ if (!(".".equals(lastToken) || ".".equals(token) || "[]".equals(token)))
+ return null;
+ type += token;
+ }
+ }
+ lastToken = token;
+ }
+ if (type == null)
+ return null;
+
+ char[] packageChars = null, typeChars = null;
+
+ // extract declaring type infos
+ if (type != null) {
+ char[] typePart = type.toCharArray();
+ int lastDotPosition = CharOperation.lastIndexOf('.', typePart);
+ if (lastDotPosition >= 0) {
+ packageChars = CharOperation.subarray(typePart, 0, lastDotPosition);
+ if (packageChars.length == 1 && packageChars[0] == '*')
+ packageChars = null;
+ typeChars =
+ CharOperation.subarray(typePart, lastDotPosition + 1, typePart.length);
+ } else {
+ packageChars = null;
+ typeChars = typePart;
+ }
+ if (typeChars.length == 1 && typeChars[0] == '*')
+ typeChars = null;
+ }
+ SearchPattern searchPattern = null;
+ switch (limitTo) {
+ case IJavaSearchConstants.DECLARATIONS :
+ // cannot search for explicit member types
+ searchPattern =
+ new TypeDeclarationPattern(
+ packageChars,
+ null,
+ typeChars,
+ TYPE_SUFFIX,
+ matchMode,
+ isCaseSensitive);
+ break;
+ case IJavaSearchConstants.REFERENCES :
+ searchPattern =
+ new TypeReferencePattern(packageChars, typeChars, matchMode, isCaseSensitive);
+ break;
+ case IJavaSearchConstants.IMPLEMENTORS :
+ searchPattern =
+ new SuperInterfaceReferencePattern(
+ packageChars,
+ typeChars,
+ matchMode,
+ isCaseSensitive);
+ break;
+ case IJavaSearchConstants.ALL_OCCURRENCES :
+ searchPattern =
+ new OrPattern(
+ new TypeDeclarationPattern(
+ packageChars,
+ null,
+ typeChars,
+ TYPE_SUFFIX,
+ matchMode,
+ isCaseSensitive),
+ // cannot search for explicit member types
+ new TypeReferencePattern(packageChars, typeChars, matchMode, isCaseSensitive));
+ break;
+ }
+ return searchPattern;
+
+ }
+
+ protected abstract void decodeIndexEntry(IEntryResult entryResult);
+ /**
+ * Feed the requestor according to the current search pattern
+ */
+ public abstract void feedIndexRequestor(
+ IIndexSearchRequestor requestor,
+ int detailLevel,
+ int[] references,
+ IndexInput input,
+ IJavaSearchScope scope)
+ throws IOException;
+ /**
+ * Query a given index for matching entries.
+ */
+ public void findIndexMatches(
+ IIndex index,
+ IIndexSearchRequestor requestor,
+ int detailLevel,
+ IProgressMonitor progressMonitor,
+ IJavaSearchScope scope)
+ throws IOException {
+
+ if (progressMonitor != null && progressMonitor.isCanceled())
+ throw new OperationCanceledException();
+
+ IndexInput input = new BlocksIndexInput(index.getIndexFile());
+ try {
+ input.open();
+ findIndexMatches(input, requestor, detailLevel, progressMonitor, scope);
+ } finally {
+ input.close();
+ }
+ }
+
+ /**
+ * Query a given index for matching entries.
+ */
+ public void findIndexMatches(
+ IndexInput input,
+ IIndexSearchRequestor requestor,
+ int detailLevel,
+ IProgressMonitor progressMonitor,
+ IJavaSearchScope scope)
+ throws IOException {
+
+ if (progressMonitor != null && progressMonitor.isCanceled())
+ throw new OperationCanceledException();
+
+ /* narrow down a set of entries using prefix criteria */
+ IEntryResult[] entries = input.queryEntriesPrefixedBy(indexEntryPrefix());
+ if (entries == null)
+ return;
+
+ /* only select entries which actually match the entire search pattern */
+ for (int i = 0, max = entries.length; i < max; i++) {
+
+ if (progressMonitor != null && progressMonitor.isCanceled())
+ throw new OperationCanceledException();
+
+ /* retrieve and decode entry */
+ IEntryResult entry = entries[i];
+ decodeIndexEntry(entry);
+ if (matchIndexEntry()) {
+ feedIndexRequestor(
+ requestor,
+ detailLevel,
+ entry.getFileReferences(),
+ input,
+ scope);
+ }
+ }
+ }
+
+ /**
+ * Answers the suitable prefix that should be used in order
+ * to query indexes for the corresponding item.
+ * The more accurate the prefix and the less false hits will have
+ * to be eliminated later on.
+ */
+ public abstract char[] indexEntryPrefix();
+ /**
+ * Returns the type of container of this pattern, i.e. is it in compilation unit,
+ * in class declarations, field declarations, or in method declarations.
+ */
+ protected abstract int matchContainer();
+ /**
+ * Finds out whether the given resolved ast node matches this search pattern.
+ */
+ public boolean matches(AstNode node) {
+ return this.matches(node, true);
+ }
+
+ /**
+ * Returns whether this pattern matches the given node.
+ * Look at resolved information only if specified.
+ */
+ protected abstract boolean matches(AstNode node, boolean resolve);
+ /**
+ * Finds out whether the given binding matches this search pattern.
+ * Default is to return false.
+ */
+ public boolean matches(Binding binding) {
+ return false;
+ }
+
+ /**
+ * Finds out whether the given binary info matches this search pattern.
+ * Default is to return false.
+ */
+ public boolean matchesBinary(Object binaryInfo, Object enclosingBinaryInfo) {
+ return false;
+ }
+
+ /**
+ * Returns whether the given name matches the given pattern.
+ */
+ protected boolean matchesName(char[] pattern, char[] name) {
+ if (name != null) {
+ switch (this.matchMode) {
+ case EXACT_MATCH :
+ return CharOperation.equals(pattern, name, this.isCaseSensitive);
+ case PREFIX_MATCH :
+ return CharOperation.prefixEquals(pattern, name, this.isCaseSensitive);
+ case PATTERN_MATCH :
+ return CharOperation.match(pattern, name, this.isCaseSensitive);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether the given type binding matches the given simple name pattern
+ * and qualification pattern.
+ */
+ protected boolean matchesType(
+ char[] simpleNamePattern,
+ char[] qualificationPattern,
+ char[] fullyQualifiedTypeName) {
+ char[] pattern;
+ if (simpleNamePattern == null) {
+ if (qualificationPattern == null) {
+ pattern = ONE_STAR;
+ } else {
+ pattern = CharOperation.concat(qualificationPattern, ONE_STAR, '.');
+ }
+ } else {
+ if (qualificationPattern == null) {
+ pattern = CharOperation.concat(ONE_STAR, simpleNamePattern);
+ } else {
+ pattern = CharOperation.concat(qualificationPattern, simpleNamePattern, '.');
+ }
+ }
+ return CharOperation.match(
+ pattern,
+ fullyQualifiedTypeName,
+ this.isCaseSensitive);
+ }
+
+ /**
+ * Returns whether the given type binding matches the given simple name pattern
+ * and qualification pattern.
+ */
+ protected boolean matchesType(
+ char[] simpleNamePattern,
+ char[] qualificationPattern,
+ TypeBinding type) {
+ if (type == null)
+ return false;
+ return this.matchesType(
+ simpleNamePattern,
+ qualificationPattern,
+ type.qualifiedPackageName().length == 0
+ ? type.qualifiedSourceName()
+ : CharOperation.concat(
+ type.qualifiedPackageName(),
+ type.qualifiedSourceName(),
+ '.'));
+ }
+
+ /**
+ * Checks whether an entry matches the current search pattern
+ */
+ protected abstract boolean matchIndexEntry();
+ /**
+ * Finds out whether the given ast node matches this search pattern.
+ * Returns IMPOSSIBLE_MATCH if it doesn't.
+ * Returns TRUSTED_MATCH if it matches exactly this search pattern (ie.
+ * it doesn't need to be resolved or it has already been resolved.)
+ * Returns POSSIBLE_MATCH if it potentially matches
+ * this search pattern and it needs to be resolved to get more information.
+ */
+ public int matchLevel(AstNode node) {
+ if (this.matches(node, false)) {
+ if (this.needsResolve) {
+ return POSSIBLE_MATCH;
+ } else {
+ return TRUSTED_MATCH;
+ }
+ }
+ return IMPOSSIBLE_MATCH;
+ }
+
+ /**
+ * Reports the match of the given reference.
+ */
+ protected void matchReportReference(
+ AstNode reference,
+ IJavaElement element,
+ int accuracy,
+ MatchLocator locator)
+ throws CoreException {
+ // default is to report a match on the whole node.
+ locator.report(reference.sourceStart, reference.sourceEnd, element, accuracy);
+ }
+
+ /**
+ * Add square brackets to the given simple name
+ */
+ protected char[] toArrayName(char[] simpleName, int dimensions) {
+ if (dimensions == 0)
+ return simpleName;
+ char[] result = new char[simpleName.length + dimensions * 2];
+ for (int i = 0; i < dimensions; i++) {
+ result[simpleName.length + i * 2] = '[';
+ result[simpleName.length + i * 2 + 1] = ']';
+ }
+ return result;
+ }
+
+ public String toString() {
+ return "SearchPattern";
+ }
+
+ /**
+ * Initializes this search pattern from the given lookup environment.
+ * Returns whether it could be initialized.
+ */
+ public boolean initializeFromLookupEnvironment(LookupEnvironment env) {
+ return true;
+ }
+
+ /**
+ * Returns whether one of the given declaring types is a sub type of the given super type.
+ */
+ protected boolean matchesAsSubtype(
+ ReferenceBinding declaringTypes[],
+ ReferenceBinding superType) {
+ if (declaringTypes == null) {
+ return true;
+ // we were not able to compute the declaring types, default to true
+ } else {
+ for (int i = 0, max = declaringTypes.length; i < max; i++) {
+ if (this.matchesAsSubtype(declaringTypes[i], superType)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Returns whether the given reference type binding matches or is a subtype of a type
+ * that matches the given simple name pattern and qualification pattern.
+ */
+ protected boolean matchesAsSubtype(
+ ReferenceBinding type,
+ char[] simpleNamePattern,
+ char[] qualificationPattern) {
+ // matches type
+ if (this.matchesType(simpleNamePattern, qualificationPattern, type))
+ return true;
+
+ // matches superclass
+ ReferenceBinding superclass = type.superclass();
+ if (superclass != null) {
+ if (this.matchesAsSubtype(superclass, simpleNamePattern, qualificationPattern))
+ return true;
+ }
+
+ // matches interfaces
+ ReferenceBinding[] interfaces = type.superInterfaces();
+ for (int i = 0; i < interfaces.length; i++) {
+ if (this
+ .matchesAsSubtype(interfaces[i], simpleNamePattern, qualificationPattern))
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns whether the given reference type binding is a subtype of the given super type.
+ */
+ protected boolean matchesAsSubtype(
+ ReferenceBinding type,
+ ReferenceBinding superType) {
+
+ // matches superclass
+ ReferenceBinding superclass = type.superclass();
+ if (superType == superclass)
+ return true;
+ if (superclass != null) {
+ if (this.matchesAsSubtype(superclass, superType))
+ return true;
+ }
+
+ // matches interfaces
+ ReferenceBinding[] interfaces = type.superInterfaces();
+ for (int i = 0; i < interfaces.length; i++) {
+ ReferenceBinding interf = interfaces[i];
+ if (superType == interf)
+ return true;
+ if (this.matchesAsSubtype(interf, superType))
+ return true;
+ }
+
+ return false;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperInterfaceReferencePattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperInterfaceReferencePattern.java
new file mode 100644
index 0000000000..81cdc26384
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperInterfaceReferencePattern.java
@@ -0,0 +1,72 @@
+package org.eclipse.jdt.internal.core.search.matching;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.core.search.indexing.*;
+
+public class SuperInterfaceReferencePattern extends SuperTypeReferencePattern {
+ public SuperInterfaceReferencePattern(
+ char[] superQualification,
+ char[] superSimpleName,
+ int matchMode,
+ boolean isCaseSensitive) {
+ super(superQualification, superSimpleName, matchMode, isCaseSensitive);
+ }
+
+ /**
+ * @see SearchPattern#matches(Binding)
+ */
+ public boolean matches(Binding binding) {
+ if (!(binding instanceof ReferenceBinding))
+ return false;
+
+ ReferenceBinding[] superInterfaces =
+ ((ReferenceBinding) binding).superInterfaces();
+ for (int i = 0, max = superInterfaces.length; i < max; i++) {
+ if (this
+ .matchesType(
+ this.superSimpleName,
+ this.superQualification,
+ superInterfaces[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @see SearchPattern#matchIndexEntry
+ */
+ protected boolean matchIndexEntry() {
+ return this.decodedSuperClassOrInterface == IIndexConstants.INTERFACE_SUFFIX
+ && super.matchIndexEntry();
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer(20);
+ buffer.append("SuperInterfaceReferencePattern: <");
+ if (superSimpleName != null)
+ buffer.append(superSimpleName);
+ buffer.append(">, ");
+ switch (matchMode) {
+ case EXACT_MATCH :
+ buffer.append("exact match, ");
+ break;
+ case PREFIX_MATCH :
+ buffer.append("prefix match, ");
+ break;
+ case PATTERN_MATCH :
+ buffer.append("pattern match, ");
+ break;
+ }
+ if (isCaseSensitive)
+ buffer.append("case sensitive");
+ else
+ buffer.append("case insensitive");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferencePattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferencePattern.java
new file mode 100644
index 0000000000..f02e880845
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferencePattern.java
@@ -0,0 +1,254 @@
+package org.eclipse.jdt.internal.core.search.matching;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.search.indexing.*;
+import org.eclipse.jdt.internal.core.index.impl.*;
+import org.eclipse.jdt.internal.core.search.*;
+
+import java.io.*;
+
+public class SuperTypeReferencePattern extends SearchPattern {
+
+ public char[] superQualification;
+ public char[] superSimpleName;
+
+ protected char[] decodedSuperQualification;
+ protected char[] decodedSuperSimpleName;
+ protected char decodedSuperClassOrInterface;
+ protected char[] decodedQualification;
+ protected char[] decodedSimpleName;
+ protected char[] decodedEnclosingTypeName;
+ protected char decodedClassOrInterface;
+ protected int decodedModifiers;
+ public SuperTypeReferencePattern(
+ char[] superQualification,
+ char[] superSimpleName,
+ int matchMode,
+ boolean isCaseSensitive) {
+
+ super(matchMode, isCaseSensitive);
+
+ this.superQualification =
+ isCaseSensitive
+ ? superQualification
+ : CharOperation.toLowerCase(superQualification);
+ this.superSimpleName =
+ isCaseSensitive ? superSimpleName : CharOperation.toLowerCase(superSimpleName);
+
+ this.needsResolve = superQualification != null;
+ }
+
+ /*
+ * superRef/Object/java.lang/X/p (i.e. class p.X extends java.lang.Object)
+ * superRef/Exception//X/p (i.e. class p.X extends Exception)
+ */
+ public void decodeIndexEntry(IEntryResult entryResult) {
+
+ char[] word = entryResult.getWord();
+ int slash = SUPER_REF.length - 1;
+ int size = word.length;
+ decodedSuperSimpleName =
+ CharOperation.subarray(
+ word,
+ slash + 1,
+ slash = CharOperation.indexOf(SEPARATOR, word, slash + 1));
+ int oldSlash = slash;
+ slash = CharOperation.indexOf(SEPARATOR, word, slash + 1);
+ if (slash == oldSlash + 1) { // could not have been known at index time
+ decodedSuperQualification = null;
+ } else {
+ decodedSuperQualification = CharOperation.subarray(word, oldSlash + 1, slash);
+ }
+ decodedSuperClassOrInterface = word[slash + 1];
+ slash += 2;
+ decodedSimpleName =
+ CharOperation.subarray(
+ word,
+ slash + 1,
+ slash = CharOperation.indexOf(SEPARATOR, word, slash + 1));
+ oldSlash = slash;
+ slash = CharOperation.indexOf(SEPARATOR, word, slash + 1);
+ if (slash == oldSlash + 1) { // could not have been known at index time
+ decodedEnclosingTypeName = null;
+ } else {
+ decodedEnclosingTypeName = CharOperation.subarray(word, oldSlash + 1, slash);
+ }
+ oldSlash = slash;
+ slash = CharOperation.indexOf(SEPARATOR, word, slash + 1);
+ if (slash == oldSlash + 1) { // could not have been known at index time
+ decodedQualification = null;
+ } else {
+ decodedQualification = CharOperation.subarray(word, oldSlash + 1, slash);
+ }
+
+ decodedClassOrInterface = word[slash + 1];
+ decodedModifiers = (int) word[slash + 2];
+ }
+
+ public void feedIndexRequestor(
+ IIndexSearchRequestor requestor,
+ int detailLevel,
+ int[] references,
+ IndexInput input,
+ IJavaSearchScope scope)
+ throws IOException {
+ for (int i = 0, max = references.length; i < max; i++) {
+ IndexedFile file = input.getIndexedFile(references[i]);
+ String path;
+ if (file != null
+ && scope.encloses(path = IndexedFile.convertPath(file.getPath()))) {
+ requestor.acceptSuperTypeReference(
+ path,
+ decodedQualification,
+ decodedSimpleName,
+ decodedEnclosingTypeName,
+ decodedClassOrInterface,
+ decodedSuperQualification,
+ decodedSuperSimpleName,
+ decodedSuperClassOrInterface,
+ decodedModifiers);
+ }
+ }
+ }
+
+ /**
+ * see SearchPattern.indexEntryPrefix()
+ */
+ public char[] indexEntryPrefix() {
+
+ return AbstractIndexer.bestReferencePrefix(
+ SUPER_REF,
+ superSimpleName,
+ matchMode,
+ isCaseSensitive);
+ }
+
+ /**
+ * @see SearchPattern#matchContainer()
+ */
+ protected int matchContainer() {
+ return CLASS;
+ }
+
+ /**
+ * @see SearchPattern#matches(AstNode, boolean)
+ */
+ protected boolean matches(AstNode node, boolean resolve) {
+ if (!(node instanceof TypeReference))
+ return false;
+
+ TypeReference typeRef = (TypeReference) node;
+ if (!resolve) {
+ if (this.superSimpleName != null) {
+ char[] typeRefSimpleName = null;
+ if (typeRef instanceof SingleTypeReference) {
+ typeRefSimpleName = ((SingleTypeReference) typeRef).token;
+ } else { // QualifiedTypeReference
+ char[][] tokens = ((QualifiedTypeReference) typeRef).tokens;
+ typeRefSimpleName = tokens[tokens.length - 1];
+ }
+ if (!this.matchesName(this.superSimpleName, typeRefSimpleName))
+ return false;
+ }
+ } else {
+ TypeBinding binding = typeRef.binding;
+ if (binding != null
+ && !this.matchesType(this.superSimpleName, this.superQualification, binding))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @see SearchPattern#matches(Binding)
+ */
+ public boolean matches(Binding binding) {
+ if (!(binding instanceof ReferenceBinding))
+ return false;
+
+ ReferenceBinding type = (ReferenceBinding) binding;
+ if (this
+ .matchesType(
+ this.superSimpleName,
+ this.superQualification,
+ type.superclass())) {
+ return true;
+ }
+
+ ReferenceBinding[] superInterfaces = type.superInterfaces();
+ for (int i = 0, max = superInterfaces.length; i < max; i++) {
+ if (this
+ .matchesType(
+ this.superSimpleName,
+ this.superQualification,
+ superInterfaces[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @see SearchPattern#matchIndexEntry
+ */
+ protected boolean matchIndexEntry() {
+
+ /* check type name matches */
+ if (superSimpleName != null) {
+ switch (matchMode) {
+ case EXACT_MATCH :
+ if (!CharOperation
+ .equals(superSimpleName, decodedSuperSimpleName, isCaseSensitive)) {
+ return false;
+ }
+ break;
+ case PREFIX_MATCH :
+ if (!CharOperation
+ .prefixEquals(superSimpleName, decodedSuperSimpleName, isCaseSensitive)) {
+ return false;
+ }
+ break;
+ case PATTERN_MATCH :
+ if (!CharOperation
+ .match(superSimpleName, decodedSuperSimpleName, isCaseSensitive)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer(20);
+ buffer.append("SuperTypeReferencePattern: <");
+ if (superSimpleName != null)
+ buffer.append(superSimpleName);
+ buffer.append(">, ");
+ switch (matchMode) {
+ case EXACT_MATCH :
+ buffer.append("exact match, ");
+ break;
+ case PREFIX_MATCH :
+ buffer.append("prefix match, ");
+ break;
+ case PATTERN_MATCH :
+ buffer.append("pattern match, ");
+ break;
+ }
+ if (isCaseSensitive)
+ buffer.append("case sensitive");
+ else
+ buffer.append("case insensitive");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationPattern.java
new file mode 100644
index 0000000000..3c9f2f5140
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationPattern.java
@@ -0,0 +1,393 @@
+package org.eclipse.jdt.internal.core.search.matching;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.search.indexing.*;
+import org.eclipse.jdt.internal.core.index.impl.*;
+import org.eclipse.jdt.internal.core.search.*;
+
+import java.io.*;
+
+public class TypeDeclarationPattern extends SearchPattern {
+
+ private char[] qualification;
+ private char[][] enclosingTypeNames;
+ private char[] simpleName;
+
+ // set to CLASS_SUFFIX for only matching classes
+ // set to INTERFACE_SUFFIX for only matching interfaces
+ // set to TYPE_SUFFIX for matching both classes and interfaces
+ private char classOrInterface;
+
+ private char[] decodedQualification;
+ private char[] decodedSimpleName;
+ private char[][] decodedEnclosingTypeNames;
+ private char decodedClassOrInterface;
+ public TypeDeclarationPattern(
+ char[] qualification,
+ char[][] enclosingTypeNames,
+ char[] simpleName,
+ char classOrInterface,
+ int matchMode,
+ boolean isCaseSensitive) {
+
+ super(matchMode, isCaseSensitive);
+
+ this.qualification =
+ isCaseSensitive ? qualification : CharOperation.toLowerCase(qualification);
+ if (isCaseSensitive || enclosingTypeNames == null) {
+ this.enclosingTypeNames = enclosingTypeNames;
+ } else {
+ int length = enclosingTypeNames.length;
+ this.enclosingTypeNames = new char[length][];
+ for (int i = 0; i < length; i++) {
+ this.enclosingTypeNames[i] = CharOperation.toLowerCase(enclosingTypeNames[i]);
+ }
+ }
+ this.simpleName =
+ isCaseSensitive ? simpleName : CharOperation.toLowerCase(simpleName);
+ this.classOrInterface = classOrInterface;
+
+ this.needsResolve = qualification != null;
+ }
+
+ public void decodeIndexEntry(IEntryResult entryResult) {
+
+ char[] word = entryResult.getWord();
+ int size = word.length;
+
+ decodedClassOrInterface = word[TYPE_DECL_LENGTH];
+ int oldSlash = TYPE_DECL_LENGTH + 1;
+ int slash = CharOperation.indexOf(SEPARATOR, word, oldSlash + 1);
+ if (slash == oldSlash + 1) {
+ decodedQualification = NO_CHAR;
+ } else {
+ decodedQualification = CharOperation.subarray(word, oldSlash + 1, slash);
+ }
+ decodedSimpleName =
+ CharOperation.subarray(
+ word,
+ slash + 1,
+ slash = CharOperation.indexOf(SEPARATOR, word, slash + 1));
+
+ if (slash + 1 < size) {
+ decodedEnclosingTypeNames =
+ CharOperation.splitOn('/', CharOperation.subarray(word, slash + 1, size - 1));
+ } else {
+ decodedEnclosingTypeNames = NO_CHAR_CHAR;
+ }
+ }
+
+ /**
+ * see SearchPattern.feedIndexRequestor
+ */
+ public void feedIndexRequestor(
+ IIndexSearchRequestor requestor,
+ int detailLevel,
+ int[] references,
+ IndexInput input,
+ IJavaSearchScope scope)
+ throws IOException {
+ boolean isClass = decodedClassOrInterface == CLASS_SUFFIX;
+ for (int i = 0, max = references.length; i < max; i++) {
+ IndexedFile file = input.getIndexedFile(references[i]);
+ String path;
+ if (file != null
+ && scope.encloses(path = IndexedFile.convertPath(file.getPath()))) {
+ if (isClass) {
+ requestor.acceptClassDeclaration(
+ path,
+ decodedSimpleName,
+ decodedEnclosingTypeNames,
+ decodedQualification);
+ } else {
+ requestor.acceptInterfaceDeclaration(
+ path,
+ decodedSimpleName,
+ decodedEnclosingTypeNames,
+ decodedQualification);
+ }
+ }
+ }
+ }
+
+ /**
+ * see SearchPattern.indexEntryPrefix()
+ */
+ public char[] indexEntryPrefix() {
+
+ return AbstractIndexer.bestTypeDeclarationPrefix(
+ qualification,
+ simpleName,
+ classOrInterface,
+ matchMode,
+ isCaseSensitive);
+ }
+
+ /**
+ * @see SearchPattern#matchContainer()
+ */
+ protected int matchContainer() {
+ return COMPILATION_UNIT | CLASS;
+ }
+
+ /**
+ * @see SearchPattern#matches(AstNode, boolean)
+ */
+ protected boolean matches(AstNode node, boolean resolve) {
+ if (!(node instanceof TypeDeclaration))
+ return false;
+
+ TypeDeclaration type = (TypeDeclaration) node;
+
+ // type name
+ if (this.simpleName != null && !this.matchesName(this.simpleName, type.name))
+ return false;
+
+ if (resolve) {
+ // fully qualified name
+ TypeBinding binding = type.binding;
+ if (binding != null && !this.matches(binding)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @see SearchPattern#matches(Binding)
+ */
+ public boolean matches(Binding binding) {
+ if (!(binding instanceof TypeBinding))
+ return false;
+
+ TypeBinding type = (TypeBinding) binding;
+
+ // fully qualified name
+ char[] enclosingTypeName =
+ this.enclosingTypeNames == null
+ ? null
+ : CharOperation.concatWith(this.enclosingTypeNames, '.');
+ if (!this
+ .matchesType(this.simpleName, this.qualification, enclosingTypeName, type)) {
+ return false;
+ }
+
+ // class or interface
+ switch (this.classOrInterface) {
+ case CLASS_SUFFIX :
+ if (type.isInterface())
+ return false;
+ break;
+ case INTERFACE_SUFFIX :
+ if (!type.isInterface())
+ return false;
+ break;
+ }
+
+ return true;
+ }
+
+ /**
+ * @see SearchPattern#matchesBinary(Object, Object)
+ */
+ public boolean matchesBinary(Object binaryInfo, Object enclosingBinaryInfo) {
+ if (!(binaryInfo instanceof IBinaryType))
+ return false;
+
+ IBinaryType type = (IBinaryType) binaryInfo;
+
+ // fully qualified name
+ char[] typeName = (char[]) type.getName().clone();
+ CharOperation.replace(typeName, '/', '.');
+ char[] enclosingTypeName =
+ this.enclosingTypeNames == null
+ ? null
+ : CharOperation.concatWith(this.enclosingTypeNames, '.');
+ if (!this
+ .matchesType(
+ this.simpleName,
+ this.qualification,
+ enclosingTypeName,
+ typeName)) {
+ return false;
+ }
+
+ // class or interface
+ switch (this.classOrInterface) {
+ case CLASS_SUFFIX :
+ if (type.isInterface())
+ return false;
+ break;
+ case INTERFACE_SUFFIX :
+ if (!type.isInterface())
+ return false;
+ break;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns whether the given type binding matches the given simple name pattern
+ * qualification pattern and enclosing name pattern.
+ */
+ protected boolean matchesType(
+ char[] simpleNamePattern,
+ char[] qualificationPattern,
+ char[] enclosingNamePattern,
+ char[] fullyQualifiedTypeName) {
+ if (enclosingNamePattern == null) {
+ return this.matchesType(
+ simpleNamePattern,
+ qualificationPattern,
+ fullyQualifiedTypeName);
+ } else {
+ char[] pattern;
+ if (qualificationPattern == null) {
+ pattern = enclosingNamePattern;
+ } else {
+ pattern = CharOperation.concat(qualificationPattern, enclosingNamePattern, '.');
+ }
+ return this.matchesType(simpleNamePattern, pattern, fullyQualifiedTypeName);
+ }
+ }
+
+ /**
+ * Returns whether the given type binding matches the given simple name pattern
+ * qualification pattern and enclosing type name pattern.
+ */
+ protected boolean matchesType(
+ char[] simpleNamePattern,
+ char[] qualificationPattern,
+ char[] enclosingNamePattern,
+ TypeBinding type) {
+ if (enclosingNamePattern == null) {
+ return this.matchesType(simpleNamePattern, qualificationPattern, type);
+ } else {
+ char[] pattern;
+ if (qualificationPattern == null) {
+ return matchesType(simpleNamePattern, enclosingNamePattern, type);
+ } else {
+ // pattern was created from a Java element: qualification is the package name.
+ char[] fullQualificationPattern =
+ CharOperation.concat(qualificationPattern, enclosingNamePattern, '.');
+ return this.matchesType(simpleNamePattern, fullQualificationPattern, type)
+ && CharOperation.equals(
+ qualification,
+ CharOperation.concatWith(type.getPackage().compoundName, '.'));
+ }
+ }
+ }
+
+ /**
+ * see SearchPattern.matchIndexEntry
+ */
+ protected boolean matchIndexEntry() {
+
+ /* check class/interface nature */
+ switch (classOrInterface) {
+ case CLASS_SUFFIX :
+ case INTERFACE_SUFFIX :
+ if (classOrInterface != decodedClassOrInterface)
+ return false;
+ default :
+ }
+ /* check qualification - exact match only */
+ if (qualification != null
+ && !CharOperation.equals(qualification, decodedQualification, isCaseSensitive))
+ return false;
+ /* check enclosingTypeName - exact match only */
+ if (enclosingTypeNames != null) {
+ // empty char[][] means no enclosing type, i.e. the decoded one is the empty char array
+ if (enclosingTypeNames.length == 0) {
+ if (decodedEnclosingTypeNames != NO_CHAR_CHAR)
+ return false;
+ } else {
+ if (!CharOperation
+ .equals(enclosingTypeNames, decodedEnclosingTypeNames, isCaseSensitive))
+ return false;
+ }
+ }
+
+ /* check simple name matches */
+ if (simpleName != null) {
+ switch (matchMode) {
+ case EXACT_MATCH :
+ if (!CharOperation.equals(simpleName, decodedSimpleName, isCaseSensitive)) {
+ return false;
+ }
+ break;
+ case PREFIX_MATCH :
+ if (!CharOperation
+ .prefixEquals(simpleName, decodedSimpleName, isCaseSensitive)) {
+ return false;
+ }
+ break;
+ case PATTERN_MATCH :
+ if (!CharOperation.match(simpleName, decodedSimpleName, isCaseSensitive)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer(20);
+ switch (classOrInterface) {
+ case CLASS_SUFFIX :
+ buffer.append("ClassDeclarationPattern: pkg<");
+ break;
+ case INTERFACE_SUFFIX :
+ buffer.append("InterfaceDeclarationPattern: pkg<");
+ break;
+ default :
+ buffer.append("TypeDeclarationPattern: pkg<");
+ break;
+ }
+ if (qualification != null)
+ buffer.append(qualification);
+ buffer.append(">, enclosing<");
+ if (enclosingTypeNames != null) {
+ for (int i = 0; i < enclosingTypeNames.length; i++) {
+ buffer.append(enclosingTypeNames[i]);
+ if (i < enclosingTypeNames.length - 1)
+ buffer.append('.');
+ }
+ }
+ buffer.append(">, type<");
+ if (simpleName != null)
+ buffer.append(simpleName);
+ buffer.append(">, ");
+ switch (matchMode) {
+ case EXACT_MATCH :
+ buffer.append("exact match, ");
+ break;
+ case PREFIX_MATCH :
+ buffer.append("prefix match, ");
+ break;
+ case PATTERN_MATCH :
+ buffer.append("pattern match, ");
+ break;
+ }
+ if (isCaseSensitive)
+ buffer.append("case sensitive");
+ else
+ buffer.append("case insensitive");
+ return buffer.toString();
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferencePattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferencePattern.java
new file mode 100644
index 0000000000..7d1263549b
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferencePattern.java
@@ -0,0 +1,538 @@
+package org.eclipse.jdt.internal.core.search.matching;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.*;
+
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.util.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+import org.eclipse.jdt.core.IMethod;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.search.indexing.*;
+import org.eclipse.jdt.internal.core.index.impl.*;
+import org.eclipse.jdt.internal.core.search.*;
+
+import java.io.*;
+
+public class TypeReferencePattern extends MultipleSearchPattern {
+
+ private char[] qualification;
+ private char[] simpleName;
+
+ private char[] decodedQualification;
+ private char[] decodedSimpleName;
+
+ private static char[][] TAGS = { TYPE_REF, SUPER_REF, REF, CONSTRUCTOR_REF };
+ private static char[][] REF_TAGS = { REF };
+
+ /* Optimization: case where simpleName == null */
+ private char[][] segments;
+ private int currentSegment;
+ private char[] decodedSegment;
+ public TypeReferencePattern(
+ char[] qualification,
+ char[] simpleName,
+ int matchMode,
+ boolean isCaseSensitive) {
+
+ super(matchMode, isCaseSensitive);
+
+ this.qualification =
+ isCaseSensitive ? qualification : CharOperation.toLowerCase(qualification);
+ this.simpleName =
+ isCaseSensitive ? simpleName : CharOperation.toLowerCase(simpleName);
+
+ if (simpleName == null) {
+ this.segments = CharOperation.splitOn('.', qualification);
+ }
+
+ this.needsResolve = qualification != null;
+ }
+
+ /**
+ * Either decode ref/name, typeRef/name or superRef/superName/name
+ */
+ public void decodeIndexEntry(IEntryResult entryResult) {
+
+ char[] word = entryResult.getWord();
+ int size = word.length;
+ int tagLength = currentTag.length;
+ int nameLength = CharOperation.indexOf(SEPARATOR, word, tagLength);
+ if (nameLength < 0)
+ nameLength = size;
+ if (this.simpleName == null) {
+ // Optimization, eg. type reference is 'org.eclipse.jdt.core.*'
+ this.decodedSegment = CharOperation.subarray(word, tagLength, nameLength);
+ } else {
+ this.decodedSimpleName = CharOperation.subarray(word, tagLength, nameLength);
+ }
+ }
+
+ public void feedIndexRequestor(
+ IIndexSearchRequestor requestor,
+ int detailLevel,
+ int[] references,
+ IndexInput input,
+ IJavaSearchScope scope)
+ throws IOException {
+ if (currentTag == REF) {
+ foundAmbiguousIndexMatches = true;
+ }
+ for (int i = 0, max = references.length; i < max; i++) {
+ int reference = references[i];
+ if (reference != -1) { // if the reference has not been eliminated
+ IndexedFile file = input.getIndexedFile(reference);
+ String path;
+ if (file != null
+ && scope.encloses(path = IndexedFile.convertPath(file.getPath()))) {
+ requestor.acceptTypeReference(path, decodedSimpleName);
+ }
+ }
+ }
+ }
+
+ protected char[][] getPossibleTags() {
+ if (this.simpleName == null) {
+ return REF_TAGS;
+ } else {
+ return TAGS;
+ }
+ }
+
+ /**
+ * @see AndPattern#hasNextQuery
+ */
+ protected boolean hasNextQuery() {
+ if (this.simpleName == null) {
+ // Optimization, eg. type reference is 'org.eclipse.jdt.core.*'
+ if (this.segments.length > 2) {
+ // if package has more than 2 segments, don't look at the first 2 since they are mostly
+ // redundant (eg. in 'org.eclipse.jdt.core.*', 'com.ibm' is used all the time)
+ return --this.currentSegment >= 2;
+ } else {
+ return --this.currentSegment >= 0;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * see SearchPattern.indexEntryPrefix()
+ */
+ public char[] indexEntryPrefix() {
+
+ if (this.simpleName == null) {
+ // Optimization, eg. type reference is 'org.eclipse.jdt.core.*'
+ return AbstractIndexer.bestReferencePrefix(
+ REF,
+ this.segments[this.currentSegment],
+ matchMode,
+ isCaseSensitive);
+ } else {
+ return AbstractIndexer.bestReferencePrefix(
+ currentTag,
+ simpleName,
+ matchMode,
+ isCaseSensitive);
+ }
+ }
+
+ /**
+ * @see SearchPattern#matchContainer()
+ */
+ protected int matchContainer() {
+ return COMPILATION_UNIT | CLASS | METHOD | FIELD;
+ }
+
+ /**
+ * @see SearchPattern#matches(AstNode, boolean)
+ */
+ protected boolean matches(AstNode node, boolean resolve) {
+ if (node instanceof TypeReference) {
+ return this.matches((TypeReference) node, resolve);
+ } else
+ if (node instanceof NameReference) {
+ return this.matches((NameReference) node, resolve);
+ } else
+ if (node instanceof ImportReference) {
+ return this.matches((ImportReference) node, resolve);
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether this type pattern matches the given import reference.
+ * Look at resolved information only if specified.
+ */
+ private boolean matches(ImportReference importRef, boolean resolve) {
+
+ if (importRef.onDemand)
+ return false;
+
+ char[][] tokens = importRef.tokens;
+ int importLength = tokens.length;
+
+ if (this.qualification != null) {
+ char[][] qualificationTokens = CharOperation.splitOn('.', this.qualification);
+ int qualificationLength = qualificationTokens.length;
+ if (qualificationLength + 1 > importLength)
+ return false;
+ for (int i = 0; i < qualificationLength; i++) {
+ if (!this.matchesName(qualificationTokens[i], tokens[i])) {
+ return false;
+ }
+ }
+ if (this.simpleName != null
+ && !this.matchesName(this.simpleName, tokens[qualificationLength])) {
+ return false;
+ }
+ } else {
+ if (this.simpleName != null) {
+ for (int i = 0; i < importLength; i++) {
+ if (this.matchesName(this.simpleName, tokens[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns whether this type pattern matches the given name reference.
+ * Look at resolved information only if specified.
+ */
+ private boolean matches(NameReference nameRef, boolean resolve) {
+ Binding binding = nameRef.binding;
+ if (!resolve || binding == null || !binding.isValidBinding()) {
+ if (this.simpleName != null) {
+ if (nameRef instanceof SingleNameReference) {
+ return this.matchesName(this.simpleName, ((SingleNameReference) nameRef).token);
+ } else { // QualifiedNameReference
+ char[][] tokens = ((QualifiedNameReference) nameRef).tokens;
+ for (int i = 0, max = tokens.length; i < max; i++) {
+ if (this.matchesName(this.simpleName, tokens[i]))
+ return true;
+ }
+ return false;
+ }
+ }
+ } else {
+ if (nameRef instanceof SingleNameReference) {
+ if (binding instanceof TypeBinding) {
+ if (!this
+ .matchesType(this.simpleName, this.qualification, (TypeBinding) binding)) {
+ return false;
+ }
+ } else {
+ return false; // must be a type binding
+ }
+ } else { // QualifiedNameReference
+ TypeBinding typeBinding = null;
+ QualifiedNameReference qNameRef = (QualifiedNameReference) nameRef;
+ char[][] tokens = qNameRef.tokens;
+ int lastIndex = tokens.length - 1;
+ switch (qNameRef.bits & Statement.RestrictiveFlagMASK) {
+ case BindingIds.FIELD : // reading a field
+ typeBinding = ((FieldBinding) binding).declaringClass;
+ // no valid match amongst fields
+ int otherBindingsCount =
+ qNameRef.otherBindings == null ? 0 : qNameRef.otherBindings.length;
+ lastIndex -= otherBindingsCount + 1;
+ if (lastIndex < 0)
+ return false;
+ break;
+ case BindingIds.LOCAL : // reading a local variable
+ return false; // no type match in it
+ case BindingIds.TYPE : //=============only type ==============
+ typeBinding = (TypeBinding) binding;
+ }
+ // try to match all enclosing types for which the token matches as well.
+ while (typeBinding != null && lastIndex >= 0) {
+ if (matchesName(this.simpleName, tokens[lastIndex--])
+ && matchesType(this.simpleName, this.qualification, typeBinding))
+ return true;
+ //&& matchesAsSubtype(this.simpleName, this.qualification, typeBinding)) return true;
+ if (typeBinding instanceof ReferenceBinding) {
+ typeBinding = ((ReferenceBinding) typeBinding).enclosingType();
+ } else {
+ typeBinding = null;
+ }
+ }
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns whether this type pattern matches the given type reference.
+ * Look at resolved information only if specified.
+ */
+ private boolean matches(TypeReference typeRef, boolean resolve) {
+ if (!resolve) {
+ if (this.simpleName != null) {
+ if (typeRef instanceof SingleTypeReference) {
+ return this.matchesName(this.simpleName, ((SingleTypeReference) typeRef).token);
+ } else { // QualifiedTypeReference
+ char[][] tokens = ((QualifiedTypeReference) typeRef).tokens;
+ for (int i = 0, max = tokens.length; i < max; i++) {
+ if (this.matchesName(this.simpleName, tokens[i]))
+ return true;
+ }
+ return false;
+ }
+ }
+ } else {
+
+ TypeBinding typeBinding = typeRef.binding;
+ if (typeBinding != null) {
+ if (typeBinding instanceof ArrayBinding)
+ typeBinding = ((ArrayBinding) typeBinding).leafComponentType;
+ if (typeRef instanceof SingleTypeReference) {
+ if (!this.matchesType(this.simpleName, this.qualification, typeBinding)) {
+ return false;
+ }
+ } else { // QualifiedTypeReference
+ QualifiedTypeReference qNameRef = (QualifiedTypeReference) typeRef;
+ char[][] tokens = qNameRef.tokens;
+ int lastIndex = tokens.length - 1;
+ // try to match all enclosing types for which the token matches as well.
+ while (typeBinding != null && lastIndex >= 0) {
+ if (matchesName(this.simpleName, tokens[lastIndex--])
+ && matchesType(this.simpleName, this.qualification, typeBinding))
+ return true;
+ //&& matchesAsSubtype(this.simpleName, this.qualification, typeBinding)) return true;
+ if (typeBinding instanceof ReferenceBinding) {
+ typeBinding = ((ReferenceBinding) typeBinding).enclosingType();
+ } else {
+ typeBinding = null;
+ }
+ }
+ return false;
+ }
+ }
+
+ }
+ return true;
+ }
+
+ /**
+ * @see SearchPattern#matches(Binding)
+ */
+ public boolean matches(Binding binding) {
+ if (!(binding instanceof ReferenceBinding))
+ return false;
+
+ ReferenceBinding type = (ReferenceBinding) binding;
+ if (this.matchesType(this.simpleName, this.qualification, type.superclass())) {
+ return true;
+ }
+
+ ReferenceBinding[] superInterfaces = type.superInterfaces();
+ for (int i = 0, max = superInterfaces.length; i < max; i++) {
+ if (this
+ .matchesType(this.simpleName, this.qualification, superInterfaces[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @see SearchPattern#matchIndexEntry
+ */
+ protected boolean matchIndexEntry() {
+
+ /* check type name matches */
+ if (simpleName == null) {
+ // Optimization, eg. type reference is 'org.eclipse.jdt.core.*'
+ switch (matchMode) {
+ case EXACT_MATCH :
+ if (!CharOperation
+ .equals(
+ this.segments[this.currentSegment],
+ this.decodedSegment,
+ isCaseSensitive)) {
+ return false;
+ }
+ break;
+ case PREFIX_MATCH :
+ if (!CharOperation
+ .prefixEquals(
+ this.segments[this.currentSegment],
+ this.decodedSegment,
+ isCaseSensitive)) {
+ return false;
+ }
+ break;
+ case PATTERN_MATCH :
+ if (!CharOperation
+ .match(
+ this.segments[this.currentSegment],
+ this.decodedSegment,
+ isCaseSensitive)) {
+ return false;
+ }
+ }
+ } else {
+ switch (matchMode) {
+ case EXACT_MATCH :
+ if (!CharOperation.equals(simpleName, decodedSimpleName, isCaseSensitive)) {
+ return false;
+ }
+ break;
+ case PREFIX_MATCH :
+ if (!CharOperation
+ .prefixEquals(simpleName, decodedSimpleName, isCaseSensitive)) {
+ return false;
+ }
+ break;
+ case PATTERN_MATCH :
+ if (!CharOperation.match(simpleName, decodedSimpleName, isCaseSensitive)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @see SearchPattern#matchLevel
+ */
+ public int matchLevel(AstNode node) {
+ if (node instanceof NameReference) {
+ if (this.matches((NameReference) node, false)) {
+ return POSSIBLE_MATCH; // always need to resolve name reference
+ } else {
+ return IMPOSSIBLE_MATCH;
+ }
+ } else
+ if (node instanceof ImportReference) {
+ if (this.matches((ImportReference) node, false)) {
+ return POSSIBLE_MATCH;
+ } else {
+ return IMPOSSIBLE_MATCH;
+ }
+ } else {
+ return super.matchLevel(node);
+ }
+ }
+
+ /**
+ * @see SearchPattern#matchReportReference
+ */
+ protected void matchReportReference(
+ AstNode reference,
+ IJavaElement element,
+ int accuracy,
+ MatchLocator locator)
+ throws CoreException {
+ if (reference instanceof QualifiedNameReference) {
+ this.matchReportReference(
+ (QualifiedNameReference) reference,
+ element,
+ accuracy,
+ locator);
+ } else
+ if (reference instanceof QualifiedTypeReference) {
+ this.matchReportReference(
+ (QualifiedTypeReference) reference,
+ element,
+ accuracy,
+ locator);
+ } else {
+ super.matchReportReference(reference, element, accuracy, locator);
+ }
+ }
+
+ /**
+ * Reports the match of the given qualified name reference.
+ */
+ private void matchReportReference(
+ QualifiedNameReference nameRef,
+ IJavaElement element,
+ int accuracy,
+ MatchLocator locator)
+ throws CoreException {
+ char[][] qualifiedName =
+ CharOperation.splitOn(
+ '.',
+ this.qualification == null
+ ? this.simpleName
+ : CharOperation.concat(this.qualification, this.simpleName, '.'));
+ locator.reportQualifiedReference(
+ nameRef.sourceStart,
+ nameRef.sourceEnd,
+ qualifiedName,
+ element,
+ accuracy);
+ }
+
+ /**
+ * Reports the match of the given qualified type reference.
+ */
+ private void matchReportReference(
+ QualifiedTypeReference typeRef,
+ IJavaElement element,
+ int accuracy,
+ MatchLocator locator)
+ throws CoreException {
+ char[][] qualifiedName =
+ CharOperation.splitOn(
+ '.',
+ CharOperation.concat(this.qualification, this.simpleName, '.'));
+ locator.reportQualifiedReference(
+ typeRef.sourceStart,
+ typeRef.sourceEnd,
+ qualifiedName,
+ element,
+ accuracy);
+ }
+
+ /**
+ * @see AndPattern#resetQuery
+ */
+ protected void resetQuery() {
+ if (this.simpleName == null) {
+ /* walk the segments from end to start as it will find less potential references using 'lang' than 'java' */
+ this.currentSegment = this.segments.length - 1;
+ }
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer(20);
+ buffer.append("TypeReferencePattern: pkg<");
+ if (qualification != null)
+ buffer.append(qualification);
+ buffer.append(">, type<");
+ if (simpleName != null)
+ buffer.append(simpleName);
+ buffer.append(">, ");
+ switch (matchMode) {
+ case EXACT_MATCH :
+ buffer.append("exact match, ");
+ break;
+ case PREFIX_MATCH :
+ buffer.append("prefix match, ");
+ break;
+ case PATTERN_MATCH :
+ buffer.append("pattern match, ");
+ break;
+ }
+ if (isCaseSensitive)
+ buffer.append("case sensitive");
+ else
+ buffer.append("case insensitive");
+ return buffer.toString();
+ }
+
+}
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
new file mode 100644
index 0000000000..a068153fd5
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/IJob.java
@@ -0,0 +1,14 @@
+package org.eclipse.jdt.internal.core.search.processing;
+
+public interface IJob {
+ /**
+ * Answer true if the job belongs to a given family (tag)
+ */
+ public boolean belongsTo(String jobFamily);
+ /**
+ * Execute the current job, answering:
+ * RESCHEDULE if the job should be rescheduled later on
+ * COMPLETE if the job is over
+ */
+ public boolean execute();
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/IJobConstants.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/IJobConstants.java
new file mode 100644
index 0000000000..794f089a98
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/IJobConstants.java
@@ -0,0 +1,11 @@
+package org.eclipse.jdt.internal.core.search.processing;
+
+public interface IJobConstants {
+
+ int ForceImmediate = 1;
+ int CancelIfNotReady = 2;
+ int WaitUntilReady = 3;
+
+ boolean FAILED = false;
+ boolean COMPLETE = true;
+}
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
new file mode 100644
index 0000000000..55b82d411a
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java
@@ -0,0 +1,285 @@
+package org.eclipse.jdt.internal.core.search.processing;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+import org.eclipse.core.runtime.*;
+
+import java.io.*;
+import java.util.*;
+
+public abstract class JobManager implements Runnable, IJobConstants {
+
+ /* queue of jobs to execute */
+ protected IJob[] awaitingJobs = new IJob[10];
+ protected int jobStart = 0;
+ protected int jobEnd = -1;
+ protected boolean executing = false;
+
+ /* background processing */
+ protected Thread thread;
+
+ /* flag indicating whether job execution is enabled or not */
+ private boolean enabled = true;
+
+ public static boolean VERBOSE = false;
+ /**
+ * Invoked exactly once, in background, before starting processing any job
+ */
+ public abstract void activateProcessing();
+ /**
+ * Answer the amount of awaiting jobs.
+ */
+ public synchronized int awaitingJobsCount() {
+
+ return jobEnd - jobStart + 1;
+ }
+
+ /**
+ * Answers the first job in the queue, or null if there is no job available
+ * Until the job has completed, the job manager will keep answering the same job.
+ */
+ public synchronized IJob currentJob() {
+
+ if (!enabled)
+ return null;
+
+ if (jobStart <= jobEnd) {
+ return awaitingJobs[jobStart];
+ }
+ return null;
+ }
+
+ public synchronized void disable() {
+ enabled = false;
+ }
+
+ /**
+ * Remove the index from cache for a given project.
+ * Passing null as a job family discards them all.
+ */
+ public void discardJobs(String jobFamily) {
+ boolean wasEnabled = isEnabled();
+ try {
+ disable();
+
+ // wait until current job has completed
+ while (thread != null && executing) {
+ try {
+ Thread.currentThread().sleep(50);
+ } catch (InterruptedException e) {
+ }
+ }
+
+ // flush and compact awaiting jobs
+ int loc = -1;
+ for (int i = jobStart; i <= jobEnd; i++) {
+ IJob currentJob = awaitingJobs[i];
+ awaitingJobs[i] = null;
+ if (!(jobFamily == null
+ || currentJob.belongsTo(jobFamily))) { // copy down, compacting
+ awaitingJobs[++loc] = currentJob;
+ }
+ }
+ jobStart = 0;
+ jobEnd = loc;
+ } finally {
+ if (wasEnabled)
+ enable();
+ }
+ }
+
+ public synchronized void enable() {
+ enabled = true;
+ }
+
+ public synchronized boolean isEnabled() {
+ return enabled;
+ }
+
+ /**
+ * Advance to the next available job, once the current one has been completed.
+ * Note: clients awaiting until the job count is zero are still waiting at this point.
+ */
+ protected synchronized void moveToNextJob() {
+
+ //if (!enabled) return;
+
+ if (jobStart <= jobEnd) {
+ awaitingJobs[jobStart++] = null;
+ if (jobStart > jobEnd) {
+ jobStart = 0;
+ jobEnd = -1;
+ }
+ }
+ }
+
+ /**
+ * When idle, give chance to do something
+ */
+ protected void notifyIdle(long idlingTime) {
+ }
+
+ /**
+ * This API is allowing to run one job in concurrence with background processing.
+ * Indeed since other jobs are performed in background, resource sharing might be
+ * an issue.Therefore, this functionality allows a given job to be run without
+ * colliding with background ones.
+ * Note: multiple thread might attempt to perform concurrent jobs at the same time,
+ * and shoud synchronize (it is deliberately left to clients to decide whether
+ * concurrent jobs might interfere or not, i.e. multiple read jobs are ok).
+ *
+ * Waiting policy can be:
+ * IJobConstants.ForceImmediateSearch
+ * IJobConstants.CancelIfNotReadyToSearch
+ * IJobConstants.WaitUntilReadyToSearch
+ *
+ */
+ public boolean performConcurrentJob(
+ IJob searchJob,
+ int waitingPolicy,
+ IProgressMonitor progress) {
+
+ if (VERBOSE)
+ System.out.println("-> performing concurrent job : START - " + searchJob);
+ boolean status = FAILED;
+ if (awaitingJobsCount() > 0) {
+ switch (waitingPolicy) {
+
+ case ForceImmediate :
+ if (VERBOSE)
+ System.out.println(
+ "-> performing concurrent job : NOT READY - ForceImmediate - " + searchJob);
+ boolean wasEnabled = isEnabled();
+ try {
+ disable(); // pause indexing
+ status = searchJob.execute();
+ if (VERBOSE)
+ System.out.println("-> performing concurrent job : END - " + searchJob);
+ } finally {
+ if (wasEnabled)
+ enable();
+ }
+ return status;
+ case CancelIfNotReady :
+ if (VERBOSE)
+ System.out.println(
+ "-> performing concurrent job : NOT READY - CancelIfNotReady - " + searchJob);
+ progress.setCanceled(true);
+ break;
+
+ case WaitUntilReady :
+ int awaitingWork;
+ IJob previousJob = null;
+ IJob currentJob;
+ while ((awaitingWork = awaitingJobsCount()) > 0) {
+ if (progress != null && progress.isCanceled())
+ throw new OperationCanceledException();
+ currentJob = currentJob();
+ // currentJob can be null when jobs have been added to the queue but job manager is not enabled
+ if (currentJob != null && currentJob != previousJob) {
+ if (VERBOSE)
+ System.out.println(
+ "-> performing concurrent job : NOT READY - WaitUntilReady - " + searchJob);
+ if (progress != null) {
+ progress.subTask(awaitingWork + " files to index");
+ }
+ previousJob = currentJob;
+ }
+ try {
+ Thread.currentThread().sleep(50);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ }
+ status = searchJob.execute();
+ if (VERBOSE)
+ System.out.println("-> performing concurrent job : END - " + searchJob);
+ return status;
+ }
+
+ public abstract String processName();
+ public synchronized void request(IJob job) {
+
+ // append the job to the list of ones to process later on
+ int size = awaitingJobs.length;
+ if (++jobEnd == size) { // when growing, relocate jobs starting at position 0
+ jobEnd -= jobStart;
+ System.arraycopy(
+ awaitingJobs,
+ jobStart,
+ (awaitingJobs = new IJob[size * 2]),
+ 0,
+ jobEnd);
+ jobStart = 0;
+ }
+ awaitingJobs[jobEnd] = job;
+ if (VERBOSE)
+ System.out.println("-> requesting job: " + job);
+
+ }
+
+ /**
+ * Flush current state
+ */
+ public void reset() {
+
+ if (thread != null) {
+ discardJobs(null); // discard all jobs
+ } else {
+ /* initiate background processing */
+ thread = new Thread(this, this.processName());
+ thread.setDaemon(true);
+ thread.start();
+ }
+ }
+
+ /**
+ * Infinite loop performing resource indexing
+ */
+ public void run() {
+
+ long idlingStart = -1;
+ activateProcessing();
+ while (true) {
+ try {
+ IJob job;
+ if ((job = currentJob()) == null) {
+ if (idlingStart < 0)
+ idlingStart = System.currentTimeMillis();
+ notifyIdle(System.currentTimeMillis() - idlingStart);
+ Thread.currentThread().sleep(500);
+ continue;
+ } else {
+ idlingStart = -1;
+ }
+ if (VERBOSE) {
+ System.out.println("-> executing: " + job);
+ System.out.println("\t" + awaitingJobsCount() + " awaiting jobs.");
+ }
+ try {
+ executing = true;
+ boolean status = job.execute();
+ //if (status == FAILED) request(job);
+ moveToNextJob();
+ } finally {
+ executing = false;
+ Thread.currentThread().sleep(50);
+ }
+ } catch (InterruptedException e) { // background indexing was interrupted
+ }
+ }
+ }
+
+ /**
+ * Stop background processing, and wait until the current job is completed before returning
+ */
+ public void shutdown() {
+
+ disable();
+ discardJobs(null); // will wait until current executing job has completed
+ }
+
+}

Back to the top