| 161 | | private void checkRoles(Relation n, LinkedList<Role> allroles, HashMap<String, RoleInfo> map) { |
| 162 | | List<String> done = new LinkedList<>(); |
| 163 | | // Remove empty roles if several exist (like in route=hiking, see #9844) |
| 164 | | List<Role> emptyRoles = new LinkedList<>(); |
| 165 | | for (Role r : allroles) { |
| 166 | | if ("".equals(r.key)) { |
| 167 | | emptyRoles.add(r); |
| 168 | | } |
| | 165 | private boolean checkMemberType(Role r, RelationMember member) { |
| | 166 | if (r.types != null) { |
| | 167 | return r.types.contains(member.getDisplayType()); |
| | 168 | } else { |
| | 169 | // if no types specified, then test is passed |
| | 170 | return true; |
| | 171 | } |
| | 172 | } |
| | 173 | |
| | 174 | // |
| | 175 | /** |
| | 176 | * get all role definition for specified key and check, if some definition matches |
| | 177 | * |
| | 178 | * @param rolePreset containing preset for role of the member |
| | 179 | * @param member to be verified |
| | 180 | * @param n relation to be verified |
| | 181 | * @return <tt>true</tt> if member passed any of definition within preset |
| | 182 | * |
| | 183 | */ |
| | 184 | private boolean checkMemberExpressionAndType(RolePreset rolePreset, RelationMember member, Relation n) { |
| | 185 | TestError possibleMatchError = null; |
| | 186 | if (rolePreset == null || rolePreset.roles == null) { |
| | 187 | // no restrictions on role types |
| | 188 | return true; |
| 170 | | if (emptyRoles.size() > 1) { |
| 171 | | allroles.removeAll(emptyRoles); |
| | 190 | // iterate through all of the role definition within preset |
| | 191 | // and look for any matching definition |
| | 192 | for (Role r: rolePreset.roles) { |
| | 193 | if (checkMemberType(r, member)) { |
| | 194 | // member type accepted by role definition |
| | 195 | if (r.memberExpression == null) { |
| | 196 | // no member expression - so all requirements met |
| | 197 | return true; |
| | 198 | } else { |
| | 199 | // verify if preset accepts such member |
| | 200 | OsmPrimitive primitive = member.getMember(); |
| | 201 | if(!primitive.isUsable()) { |
| | 202 | // if member is not usable (i.e. not present in working set) |
| | 203 | // we can't verify expression - so we just skip it |
| | 204 | return true; |
| | 205 | } else { |
| | 206 | // verify expression |
| | 207 | if(r.memberExpression.match(primitive)) { |
| | 208 | return true; |
| | 209 | } else { |
| | 210 | // possible match error |
| | 211 | // we still need to iterate further, as we might have |
| | 212 | // different present, for which memberExpression will match |
| | 213 | // but stash the error in case no better reason will be found later |
| | 214 | String s = marktr("Role member did not match expression {0} in template {1}"); |
| | 215 | possibleMatchError = new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG, |
| | 216 | tr(s, r.memberExpression, rolePreset.name), s, WRONG_TYPE, |
| | 217 | member.getMember().isUsable() ? member.getMember() : n); |
| | 218 | |
| | 219 | } |
| | 220 | } |
| | 221 | } |
| | 222 | } |
| 173 | | for (Role r : allroles) { |
| 174 | | done.add(r.key); |
| 175 | | String keyname = r.key; |
| 176 | | if ("".equals(keyname)) { |
| 177 | | keyname = tr("<empty>"); |
| | 224 | |
| | 225 | if( possibleMatchError != null) { |
| | 226 | // if any error found, then assume that member type was correct |
| | 227 | // and complain about not matching the memberExpression |
| | 228 | // (the only failure, that we could gather) |
| | 229 | errors.add(possibleMatchError); |
| | 230 | } else { |
| | 231 | // no errors found till now. So member at least failed at matching the type |
| | 232 | // it could also fail at memberExpression, but we can't guess at which |
| | 233 | String s = marktr("Role member type {0} did not match accepted list of {1} in template {2}"); |
| | 234 | |
| | 235 | // prepare Set of all accepted types in template |
| | 236 | EnumSet<TaggingPresetType> types = EnumSet.noneOf(TaggingPresetType.class); |
| | 237 | for (Role r: rolePreset.roles) { |
| | 238 | types.addAll(r.types); |
| 179 | | RoleInfo ri = map.get(r.key); |
| 180 | | checkRoleCounts(n, r, keyname, ri); |
| 181 | | if (ri != null) { |
| 182 | | if (r.types != null) { |
| 183 | | checkRoleTypes(n, r, keyname, ri); |
| | 240 | |
| | 241 | // convert in localization friendly way to string of accepted types |
| | 242 | String typesStr = Utils.join("/", Utils.transform(types, new Utils.Function<TaggingPresetType, Object>() { |
| | 243 | public Object apply(TaggingPresetType x) { |
| | 244 | return tr(x.getName()); |
| 185 | | if (r.memberExpression != null) { |
| 186 | | checkRoleMemberExpressions(n, r, keyname, ri); |
| | 246 | })); |
| | 247 | |
| | 248 | errors.add(new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG, |
| | 249 | tr(s, member.getType(), typesStr, rolePreset.name), s, WRONG_TYPE, |
| | 250 | member.getMember().isUsable() ? member.getMember() : n)); |
| | 251 | } |
| | 252 | return false; |
| | 253 | } |
| | 254 | |
| | 255 | |
| | 256 | private void checkRoles(Relation n, HashMap<String, RolePreset> allroles, HashMap<String, RoleInfo> map) { |
| | 257 | Set<String> done = new HashSet<>(); |
| | 258 | |
| | 259 | // go through all members of relation |
| | 260 | for (RelationMember member: n.getMembers()) { |
| | 261 | String role = member.getRole(); |
| | 262 | done.add(role); |
| | 263 | |
| | 264 | // error reporting done inside |
| | 265 | checkMemberExpressionAndType(allroles.get(role), member, n); |
| | 266 | } |
| | 267 | |
| | 268 | // verify role counts based on whole role sets |
| | 269 | for(RolePreset rp: allroles.values()) { |
| | 270 | for (Role r: rp.roles) { |
| | 271 | String keyname = r.key; |
| | 272 | if ("".equals(keyname)) { |
| | 273 | keyname = tr("<empty>"); |
| 205 | | private void checkRoleMemberExpressions(Relation n, Role r, String keyname, RoleInfo ri) { |
| 206 | | Set<OsmPrimitive> notMatching = new HashSet<>(); |
| 207 | | Collection<OsmPrimitive> allPrimitives = new ArrayList<>(); |
| 208 | | allPrimitives.addAll(ri.nodes); |
| 209 | | allPrimitives.addAll(ri.ways); |
| 210 | | allPrimitives.addAll(ri.relations); |
| 211 | | for (OsmPrimitive p : allPrimitives) { |
| 212 | | if (p.isUsable() && !r.memberExpression.match(p)) { |
| 213 | | notMatching.add(p); |
| 214 | | } |
| 215 | | } |
| 216 | | if (!notMatching.isEmpty()) { |
| 217 | | String s = marktr("Member for role ''{0}'' does not match ''{1}''"); |
| 218 | | LinkedList<OsmPrimitive> highlight = new LinkedList<>(notMatching); |
| 219 | | highlight.addFirst(n); |
| 220 | | errors.add(new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG, |
| 221 | | tr(s, keyname, r.memberExpression), MessageFormat.format(s, keyname, r.memberExpression), WRONG_TYPE, |
| 222 | | highlight, notMatching)); |
| 223 | | } |
| 224 | | } |
| 225 | | |
| 226 | | private void checkRoleTypes(Relation n, Role r, String keyname, RoleInfo ri) { |
| 227 | | Set<OsmPrimitive> wrongTypes = new HashSet<>(); |
| 228 | | if (!r.types.contains(TaggingPresetType.WAY)) { |
| 229 | | wrongTypes.addAll(r.types.contains(TaggingPresetType.CLOSEDWAY) ? ri.openways : ri.ways); |
| 230 | | } |
| 231 | | if (!r.types.contains(TaggingPresetType.NODE)) { |
| 232 | | wrongTypes.addAll(ri.nodes); |
| 233 | | } |
| 234 | | if (!r.types.contains(TaggingPresetType.RELATION)) { |
| 235 | | wrongTypes.addAll(ri.relations); |
| 236 | | } |
| 237 | | if (!wrongTypes.isEmpty()) { |
| 238 | | String s = marktr("Member for role {0} of wrong type"); |
| 239 | | LinkedList<OsmPrimitive> highlight = new LinkedList<>(wrongTypes); |
| 240 | | highlight.addFirst(n); |
| 241 | | errors.add(new TestError(this, Severity.WARNING, ROLE_VERIF_PROBLEM_MSG, |
| 242 | | tr(s, keyname), MessageFormat.format(s, keyname), WRONG_TYPE, |
| 243 | | highlight, wrongTypes)); |
| 244 | | } |
| 245 | | } |