Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 111867

Summary: DOM VariableBinding.getConstantValue() and MethodBinding.getDefaultValue() from ASTParser.createAST(IProgressMonitor) returned incorrect value
Product: [Eclipse Project] JDT Reporter: Theodora Yeung <tyeung>
Component: CoreAssignee: JDT-Core-Inbox <jdt-core-inbox>
Status: CLOSED WONTFIX QA Contact:
Severity: normal    
Priority: P3    
Version: 3.1   
Target Milestone: ---   
Hardware: PC   
OS: Windows XP   
Whiteboard:

Description Theodora Yeung CLA 2005-10-06 21:30:44 EDT
Build a DOM AST through the ASTParser.createAST(IProgressMonitor) then 
navigate to the TypeBinding (X) that is referenced by a field declaration ("X 
field;")in the DOM AST that's just been built. The fields and annotation 
methods, if any, of X is always returning null for constants and annotation 
method defaults regardless of actual value in source.

Perhaps SourceTypeBinding.methods() and SourceTypeBinding.fields() needs to 
resolve field initializer and annotation method default, if they exists?

Repro:
1)Create a new java project with 2 java files.

BuildDomAST.java:

package astTest;
public class BuildDomAST{
   ClassWithNestedAnnotation nestedAnno;
}

ClassWithNestedAnnotation.java:

package astTest;
public class ClassWithNestedAnnotation {
	public final int FOUR = 4;
	public @interface NestedAnnotation{
		public enum Character{
			Winnie, Tiger, Piglet, Eore;
		}
		
		Character value() default Character.Eore;
	}
}

2) Build a DOM AST for BuildDomAST.java through the ASTParser.createAST() API 
with resolve binding set to true.

CompilationUnit createAST(){
    ASTParser p = ASTParser.newParser( AST.JLS3 );
    p.setSource(/*the source of BuildDomAST.java */);
    p.setResolveBindings( true );
    p.setProject( /*the java project created earlier*/ );
    p.setUnitName( "BuildDomAST" );
    p.setFocalPosition( 0 );
    p.setKind( ASTParser.K_COMPILATION_UNIT );
    return (CompilationUnit)p.createAST( null );
}

3) Examine the constant value of the field ClassWithNestedAnnotation.FOUR from 
the AST that just got created. 
Starting from the top-level type binding representing "BuildDomAST". Then look 
into the type of field "nestedAnno", which is "ClassWithNestedAnnotation". 
Finally navigate to the variable binding for field "FOUR". VariableBinding
(for "FOUR).getConstantValue() should return Integer 4 but null is returned. A 
similar problem occurs when you examine the default value of the annotation 
method ClassWithNestedAnnotation.NestedAnnotation.value(). The enum constant 
Character.Eore should be returned but got null back.

The code I used to do the navigation is as below.

final List<AbstractTypeDeclaration> typeDecls = createAST().types();
for( AbstractTypeDeclaration typeDecl : typeDecls ){
    final ITypeBinding typeBinding = typeDecl.resolveBinding();
    final IVariableBinding[] fields = typeBinding.getDeclaredFields();
    for(IVariableBinding field : fields){
	final String name = field.getName();
        // only interested at the field named "nestedAnno" 
        // which has type "ClassWithNestedAnnotation"
	if( "nestedAnno".equals(name)){
	    final ITypeBinding fieldType = field.getType();
	    final ITypeBinding[] nestedTypes = fieldType.getDeclaredTypes();
	    for(ITypeBinding nestedType : nestedTypes ){
		if( "NestedAnnotation".equals(nestedType.getName()) ){
		final IMethodBinding[] annotationMethods = 
nestedType.getDeclaredMethods();
		for( IMethodBinding annotationMethod : annotationMethods ){
                    // examine the default value of NestedAnnotation.value() 
		    if( "value".equals(annotationMethod.getName()) ){
                        // This is currently returning null 
                        // The expected value is the enum Character.Eore
	
			Object defValue  = annotationMethod.getDefaultValue();
		    }
		}
	    }
	}
					
	final IVariableBinding[] nestedAnnoFields = fieldType.getDeclaredFields
();
        // The only thing you should find is the field named "FOUR"
	for(IVariableBinding nestedAnnoField : nestedAnnoFields ){
            // This is currently returning null
            // The expected value is Integer 4.
            Object constantValue = nestedAnnoField.getConstantValue() );
	}
    }
}
Comment 1 Jerome Lanneluc CLA 2005-10-10 06:01:36 EDT
Unortunately createAST(IProgressMmonitor) is not designed to resolve all types
reachable from the AST being built. 

In this particular case, you should use createASTs(...) which will ensure that
the constants are correcty initialized even for CUs not directly requested.
Comment 2 Theodora Yeung CLA 2005-10-10 15:59:43 EDT
With the fix to Bugzilla 111822, calling createASTs(...) should resolve the 
problem as Jerome mentioned. Will give that a shot. Again, need the fix to 
Bugzilla 111822 in the APT jdt.core branch. thanks. 
Comment 3 Theodora Yeung CLA 2005-10-13 19:42:08 EDT
Problem fixed in APT land. Closing.