// If it is like Body.this
// FIXME:
private void annotateInferredType(Tree tree, AnnotatedTypeMirror type) {
        switch (tree.getKind()) {
        case NEW_ARRAY:
        case NEW_CLASS:
            InferenceMain.getInstance().getCurrentExtractor().annotateInferredType(getIdentifier(tree), type);
            break;
        case METHOD:
            ExecutableElement methodElt = TreeUtils.elementFromDeclaration(
                    (MethodTree) tree);
            InferenceMain.getInstance().getCurrentExtractor().annotateInferredType(getIdentifier(methodElt), type);
            break;
        case TYPE_CAST:
            if (!checker.isAnnotated(type)) {
                Tree t = tree;
                while (t.getKind() == Kind.TYPE_CAST) {
                    t = ((TypeCastTree) t).getExpression();
                    if (t instanceof ExpressionTree)
                        t = TreeUtils.skipParens((ExpressionTree) t);
                }
                AnnotatedTypeMirror castType = getAnnotatedType(t);
                InferenceUtils.assignAnnotations(type, castType);
            }
            break;
        case METHOD_INVOCATION:
            if (type.getKind() != TypeKind.VOID) {
                MethodInvocationTree miTree = (MethodInvocationTree) tree;
                ExecutableElement iMethodElt = TreeUtils.elementFromUse(miTree);
                ExpressionTree rcvTree = InferenceUtils.getReceiverTree(miTree);
                if (ElementUtils.isStatic(iMethodElt)) {
//                    System.out.println("WARN: be supported in SFlowVisitor");
                } else {
                    ExecutableElement currentMethod = getCurrentMethodElt();
                    AnnotatedTypeMirror rcvType = null;
                    if (rcvTree != null) {
                        // like x = y.m(z);
                        rcvType = getAnnotatedType(rcvTree); 
                    } else if (currentMethod != null) {
                        rcvType = getAnnotatedType(currentMethod).getReceiverType();
                    }
                    if (rcvType != null) {
                        // Do viewpoint adaptation
						Set<AnnotationMirror> set = checker.adaptFieldSet(
                            rcvType.getAnnotations(), type.getAnnotations());
						if (!set.isEmpty()) {
							type.clearAnnotations();
							type.addAnnotations(set);
						}
                    }
                }
            }
            break;
        case VARIABLE:
            // TODO: Consider using viewpoint adaptation
            VariableElement varElt = TreeUtils.elementFromDeclaration((VariableTree)tree);
            InferenceMain.getInstance().getCurrentExtractor().annotateInferredType(getIdentifier(varElt), type);
            // If there is an initialization for field, we need adapt it from 
            // ClassTree type
            if (varElt.getKind().isField() && !ElementUtils.isStatic(varElt)) {
                ClassTree classTree = this.getVisitorState().getClassTree();
                TypeElement classElt = TreeUtils.elementFromDeclaration(classTree);
                AnnotatedDeclaredType defConstructorType = getAnnotatedType(classElt);
                InferenceMain.getInstance().getCurrentExtractor()
                    .annotateInferredType(getIdentifier(classElt), defConstructorType);
                Set<AnnotationMirror> set = checker.adaptFieldSet(defConstructorType
                        .getAnnotations(), type.getAnnotations());
                if (!set.isEmpty()) {
                    type.clearAnnotations();
                    type.addAnnotations(set);
                }
            }
            break;
        case IDENTIFIER:
            Element idElt = TreeUtils.elementFromUse((IdentifierTree) tree);
            // We don't want to annotate CLASS type
            if (idElt.getKind() != ElementKind.CLASS && idElt.getKind() != ElementKind.INTERFACE) {
                InferenceMain.getInstance().getCurrentExtractor().annotateInferredType(getIdentifier(idElt), type);
                // May need viewpoint adaptation if it is a field
				if (idElt.getKind() == ElementKind.FIELD) {
					// We need to adapt it from PoV of THIS
                    ExecutableElement currentMethod = getCurrentMethodElt();
                    if (currentMethod != null) {
						AnnotatedExecutableType methodType = getAnnotatedType(currentMethod);
						Set<AnnotationMirror> set = checker.adaptFieldSet(methodType
								.getReceiverType().getAnnotations(), type.getAnnotations());
						if (!set.isEmpty()) {
							type.clearAnnotations();
							type.addAnnotations(set);
						}
					} else {
						// This happen in the static initializer 
                        // ignore
					}
				}
            }
            break;
        case ARRAY_ACCESS:
            // WEI: move from ReimAnnotatedTypeFactory on Aug 2. 
            ArrayAccessTree aTree = (ArrayAccessTree) tree;
            ExpressionTree aExpr = aTree.getExpression();
            AnnotatedTypeMirror aExprType = getAnnotatedType(aExpr);
            assert aExprType.getKind() == TypeKind.ARRAY;
            Set<AnnotationMirror> componentAnnos = ((AnnotatedArrayType) aExprType)
                    .getComponentType().getAnnotations();
            Set<AnnotationMirror> adaptedAnnos = checker.adaptFieldSet(
                    aExprType.getAnnotations(), componentAnnos);
            if (!adaptedAnnos.isEmpty()) {
                type.clearAnnotations();
                type.addAnnotations(adaptedAnnos);
            }
            break;	
        case MEMBER_SELECT:
            // WEI: added on Aug 2
            // WEI: Remove the above line, also considering remove the 
            // tree.getKind() == Kind.MEMBER_SELECT in the "default" case
            MemberSelectTree mTree = (MemberSelectTree) tree;
            Element fieldElt = TreeUtils.elementFromUse(mTree);
            if (checker.isAccessOuterThis(mTree)) {
                // If it is like Body.this
                // FIXME:
                MethodTree methodTree = this.getVisitorState().getMethodTree();
                if (methodTree != null) {
                    ExecutableElement currentMethodElt = TreeUtils
                            .elementFromDeclaration(methodTree);
                    Element outerElt = checker.getOuterThisElement(mTree, currentMethodElt);
                    Reference inferredRef = null;
                    if (outerElt != null && outerElt.getKind() == ElementKind.METHOD) {
                        inferredRef = InferenceMain.getInstance().getCurrentExtractor().getInferredReference(getIdentifier(outerElt));
                    } else {
                        inferredRef = InferenceMain.getInstance().getCurrentExtractor().getInferredReference(getIdentifier(currentMethodElt));
                    }
                    if (inferredRef != null)
                        InferenceUtils.annotateReferenceType(type, 
                                ((ExecutableReference) inferredRef).getReceiverRef());
                    else
                        System.err.println("WARN: Cannot annotate " + mTree);
                }
            } else if (!fieldElt.getSimpleName().contentEquals("super")
                    && fieldElt.getKind() == ElementKind.FIELD
                    && !ElementUtils.isStatic(fieldElt)
                    && checker.isAnnotated(type)
                    ) {
                // Do viewpoint adaptation
                ExpressionTree expr = mTree.getExpression();
                AnnotatedTypeMirror exprType = getAnnotatedType(expr);
                AnnotatedTypeMirror fieldType = getAnnotatedType(fieldElt);
                Set<AnnotationMirror> set = checker.adaptFieldSet(
                        exprType.getAnnotations(),
                        fieldType.getAnnotations());
                if (!set.isEmpty()) {
                    type.clearAnnotations();
                    type.addAnnotations(set);
                }
            } else if (!checker.isAnnotated(type) 
                    && fieldElt.getSimpleName().contentEquals("class"))
                type.addAnnotation(checker.BOTTOM);
            break;
        default: 
            if(!checker.isAnnotated(type)) {
                if (tree instanceof UnaryTree) {
                    AnnotatedTypeMirror aType = getAnnotatedType(
                            ((UnaryTree) tree).getExpression());
                    InferenceUtils.assignAnnotations(type, aType);
                } else if (tree instanceof BinaryTree && !checker.isAnnotated(type)) {
                    ExpressionTree left = ((BinaryTree)tree).getLeftOperand();
                    ExpressionTree right = ((BinaryTree)tree).getRightOperand();
                    AnnotatedTypeMirror leftType = getAnnotatedType(left);
                    AnnotatedTypeMirror rightType = getAnnotatedType(right);
                    Set<AnnotationMirror> leftSet = leftType.getAnnotations();
                    Set<AnnotationMirror> rightSet = rightType.getAnnotations();
                    Set<AnnotationMirror> set = qualHierarchy.leastUpperBound(leftSet, rightSet);
                    type.addAnnotations(set);
                }
            }
        }
    }
Element fieldElt = TreeUtils.elementFromUse(mTree);
if (checker.isAccessOuterThis(mTree)) {
// If it is like Body.this
// FIXME:
MethodTree methodTree = this.getVisitorState().getMethodTree();
if (methodTree != null) {
type.addAnnotations(adaptedAnnos);
}
break;
case MEMBER_SELECT:
// WEI: added on Aug 2
// WEI: Remove the above line, also considering remove the
// tree.getKind() == Kind.MEMBER_SELECT in the "default" case
MemberSelectTree mTree = (MemberSelectTree) tree;
Element fieldElt = TreeUtils.elementFromUse(mTree);
if (checker.isAccessOuterThis(mTree)) {
// If it is like Body.this
// FIXME:
MethodTree methodTree = this.getVisitorState().getMethodTree();
if (methodTree != null) {
ExecutableElement currentMethodElt = TreeUtils
.elementFromDeclaration(methodTree);
Element outerElt = checker.getOuterThisElement(mTree, currentMethodElt);
Reference inferredRef = null;
if (outerElt != null && outerElt.getKind() == ElementKind.METHOD) {
inferredRef = InferenceMain.getInstance().getCurrentExtractor().getInferredReference(getIdentifier(outerElt));
} else {
inferredRef = InferenceMain.getInstance().getCurrentExtractor().getInferredReference(getIdentifier(currentMethodElt));
ArrayAccessTree aTree = (ArrayAccessTree) tree;
ExpressionTree aExpr = aTree.getExpression();
AnnotatedTypeMirror aExprType = getAnnotatedType(aExpr);
assert aExprType.getKind() == TypeKind.ARRAY;
Set<AnnotationMirror> componentAnnos = ((AnnotatedArrayType) aExprType)
.getComponentType().getAnnotations();
Set<AnnotationMirror> adaptedAnnos = checker.adaptFieldSet(
aExprType.getAnnotations(), componentAnnos);
if (!adaptedAnnos.isEmpty()) {
type.clearAnnotations();
type.addAnnotations(adaptedAnnos);
}
break;
case MEMBER_SELECT:
// WEI: added on Aug 2
// WEI: Remove the above line, also considering remove the
// tree.getKind() == Kind.MEMBER_SELECT in the "default" case
MemberSelectTree mTree = (MemberSelectTree) tree;
Element fieldElt = TreeUtils.elementFromUse(mTree);
if (checker.isAccessOuterThis(mTree)) {
// If it is like Body.this
// FIXME:
MethodTree methodTree = this.getVisitorState().getMethodTree();
if (methodTree != null) {
ExecutableElement currentMethodElt = TreeUtils
.elementFromDeclaration(methodTree);
Element outerElt = checker.getOuterThisElement(mTree, currentMethodElt);
Reference inferredRef = null;
if (outerElt != null && outerElt.getKind() == ElementKind.METHOD) {
inferredRef = InferenceMain.getInstance().getCurrentExtractor().getInferredReference(getIdentifier(outerElt));
} else {
inferredRef = InferenceMain.getInstance().getCurrentExtractor().getInferredReference(getIdentifier(currentMethodElt));
}
if (inferredRef != null)
InferenceUtils.annotateReferenceType(type,
((ExecutableReference) inferredRef).getReceiverRef());
else
System.err.println("WARN: Cannot annotate " + mTree);
}
} else if (!fieldElt.getSimpleName().contentEquals("super")
&& fieldElt.getKind() == ElementKind.FIELD
&& !ElementUtils.isStatic(fieldElt)