Subtypes subtypes = AnalysisContext.currentAnalysisContext().getSubtypes();
	public void propagateThroughClassHierarchy() {		Subtypes subtypes = AnalysisContext.currentAnalysisContext().getSubtypes();				Set<XMethod> methodSet = new HashSet<XMethod>();		methodSet.addAll(propertyMap.keySet());				// Step 1.  Add all target methods (overridden methods or overriding methods,		// depending on which direction we're walking the class hierarchy in.)		for (Iterator<XMethod> i = propertyMap.keySet().iterator(); i.hasNext();) {			XMethod sourceMethod = i.next();			if (sourceMethod.isStatic())				continue;						JavaClass sourceClass = getClassFor(sourceMethod);			if (sourceClass == null)				continue;						Set<XMethod> targetMethods = getTargetMethods(sourceClass, sourceMethod);			methodSet.addAll(targetMethods);		}				// Step 2.  Make sure the database has an entry for all reachable methods.		for (Iterator<XMethod> i = methodSet.iterator(); i.hasNext();) {			XMethod xmethod = i.next();			if (propertyMap.get(xmethod) == null) {				propertyMap.put(xmethod, createDefault());			}		}				// Step 3.  Propagate method properties to super or subtype methods.		// As long as the combine operation is commutative, it doesn't matter		// what order we do this in.		for (Iterator<Map.Entry<XMethod, Property>> i = propertyMap.entrySet().iterator(); i.hasNext();) {			Map.Entry<XMethod, Property> entry = i.next();			XMethod sourceMethod = entry.getKey();			JavaClass sourceClass = getClassFor(sourceMethod);			if (sourceClass == null)				continue;						Property sourceProperty = entry.getValue();						Set<XMethod> targetMethodSet = getTargetMethods(sourceClass, sourceMethod);			for (Iterator<XMethod> j = targetMethodSet.iterator(); j.hasNext();) {				XMethod targetMethod = j.next();				if (targetMethod.isStatic())					continue;								Property targetProperty = propertyMap.get(targetMethod);				Property result = getPropertyCombinator().combine(sourceProperty, targetProperty);				targetProperty.makeSameAs(result);			}		}	}