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 | | } |