propertyMap.put(targetMethod, combinator.combine(sourceProperty, targetProperty));
propertyMap.put(targetMethod, getPropertyCombinator().combine(sourceProperty, targetProperty));
	public void propagateThroughClassHierarchy(			HierarchyWalkDirection walkDirection, PropertyCombinator<Property> combinator) {		Subtypes subtypes = AnalysisContext.currentAnalysisContext().getSubtypes();				// For each method,property pair...		for (Iterator<Map.Entry<XMethod, Property>> i = propertyMap.entrySet().iterator(); i.hasNext();) {			Map.Entry<XMethod, Property> entry = i.next();			try {				XMethod sourceMethod = entry.getKey();				if (sourceMethod.isStatic())					continue;				Property sourceProperty = entry.getValue();				// Get source class				String sourceClassName = sourceMethod.getClassName();				JavaClass sourceClass = AnalysisContext.currentAnalysisContext().lookupClass(sourceClassName);								// Based on source class, get target classes (either subtypes or supertypes)				Set<JavaClass> targetClassSet = walkDirection.getHierarchyGraphTargets(sourceClass);				// Look for overriding or overridden methods in target classes				for (Iterator<JavaClass> j = targetClassSet.iterator(); j.hasNext(); ) {					JavaClass targetClass = j.next();					XMethod targetMethod = Hierarchy.findXMethod(targetClass, sourceMethod.getName(), sourceMethod.getSignature());					if (targetMethod.isStatic())						continue;										// Combine properties					Property targetProperty = propertyMap.get(targetMethod);					if (targetProperty == null)						propertyMap.put(targetMethod, sourceProperty.duplicate());					else						propertyMap.put(targetMethod, combinator.combine(sourceProperty, targetProperty));				}			} catch (ClassNotFoundException e) {				AnalysisContext.currentAnalysisContext().getLookupFailureCallback().reportMissingClass(e);			}		}	}