Changeset 14727 in josm
- Timestamp:
- 2019-01-24T17:49:13+01:00 (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/validation/tests/TagChecker.java
r14721 r14727 20 20 import java.util.Map.Entry; 21 21 import java.util.Set; 22 import java.util.regex.Matcher;23 import java.util.regex.Pattern;24 import java.util.regex.PatternSyntaxException;25 22 26 23 import javax.swing.JCheckBox; … … 34 31 import org.openstreetmap.josm.data.osm.AbstractPrimitive; 35 32 import org.openstreetmap.josm.data.osm.OsmPrimitive; 36 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;37 import org.openstreetmap.josm.data.osm.OsmUtils;38 33 import org.openstreetmap.josm.data.osm.Tag; 39 34 import org.openstreetmap.josm.data.osm.Tagged; … … 79 74 80 75 /** The TagChecker data */ 81 private static final List<CheckerData> checkerData = new ArrayList<>();82 76 private static final List<String> ignoreDataStartsWith = new ArrayList<>(); 83 77 private static final Set<String> ignoreDataEquals = new HashSet<>(); … … 135 129 protected boolean checkKeys; 136 130 protected boolean checkValues; 131 /** Was used for special configuration file, might be used to disable value spell checker. */ 137 132 protected boolean checkComplex; 138 133 protected boolean checkFixmes; … … 167 162 protected static final int MISSPELLED_VALUE_NO_FIX = 1215; 168 163 // CHECKSTYLE.ON: SingleSpaceSeparator 169 // 1250 and up is used by TagCheckLevel in class CheckerData170 164 171 165 protected EditableList sourcesList; 172 166 173 private static final List<String> DEFAULT_SOURCES = Arrays.asList( /*DATA_FILE, */IGNORE_FILE, SPELL_FILE);167 private static final List<String> DEFAULT_SOURCES = Arrays.asList(IGNORE_FILE, SPELL_FILE); 174 168 175 169 /** … … 219 213 */ 220 214 private static void initializeData() throws IOException { 221 checkerData.clear();222 215 ignoreDataStartsWith.clear(); 223 216 ignoreDataEquals.clear(); … … 243 236 if (line.startsWith("# JOSM TagChecker")) { 244 237 tagcheckerfile = true; 245 if (!DEFAULT_SOURCES.contains(source)) { 246 Logging.info(tr("Adding {0} to tag checker", source)); 247 } 238 Logging.error(tr("Ignoring {0}. Support was dropped", source)); 248 239 } else 249 240 if (line.startsWith("# JOSM IgnoreTags")) { … … 256 247 parseIgnoreFileLine(source, line); 257 248 } else if (tagcheckerfile) { 258 if (!line.isEmpty()) { 259 CheckerData d = new CheckerData(); 260 String err = d.getData(line); 261 262 if (err == null) { 263 checkerData.add(d); 264 } else { 265 Logging.error(tr("Invalid tagchecker line - {0}: {1}", err, line)); 266 } 267 } 249 // ignore 268 250 } else if (line.charAt(0) == '+') { 269 251 okValue = line.substring(1); … … 394 376 } 395 377 378 /** 379 * Get set of preset values for the given key. 380 * @param key the key 381 * @return null if key is not in presets or in additionalPresetsValueData, 382 * else a set which might be empty. 383 */ 396 384 private static Set<String> getPresetValues(String key) { 397 385 Set<String> res = TaggingPresets.getPresetValues(key); … … 400 388 if (additionalPresetsValueData.contains(key)) 401 389 return Collections.emptySet(); 390 // null means key is not known 402 391 return null; 403 392 } … … 490 479 // Just a collection to know if a primitive has been already marked with error 491 480 MultiMap<OsmPrimitive, String> withErrors = new MultiMap<>(); 492 493 if (checkComplex) {494 Map<String, String> keys = p.getKeys();495 for (CheckerData d : checkerData) {496 if (d.match(p, keys)) {497 errors.add(TestError.builder(this, d.getSeverity(), d.getCode())498 .message(tr("Suspicious tag/value combinations"), d.getDescription())499 .primitives(p)500 .build());501 withErrors.put(p, "TC");502 }503 }504 }505 481 506 482 for (Entry<String, String> prop : p.getKeys().entrySet()) { … … 651 627 return; 652 628 String fixedValue = null; 629 List<Set<String>> sets = new ArrayList<>(); 653 630 Set<String> presetValues = getPresetValues(key); 654 Set<String> oftenUsedValues = oftenUsedTags.get(key); 655 for (Set<String> possibleValues: Arrays.asList(presetValues, oftenUsedValues)) { 656 if (possibleValues != null && possibleValues.contains(harmonizedValue)) { 631 if (presetValues != null) 632 sets.add(presetValues); 633 sets.add(oftenUsedTags.get(key)); 634 for (Set<String> possibleValues: sets) { 635 if (possibleValues.contains(harmonizedValue)) { 657 636 fixedValue = harmonizedValue; 658 637 break; … … 665 644 int minDist = MAX_LEVENSHTEIN_DISTANCE + 1; 666 645 String closest = null; 667 for (Set<String> possibleValues: Arrays.asList(presetValues, oftenUsedValues)) { 668 if (possibleValues == null) 669 continue; 646 for (Set<String> possibleValues: sets) { 670 647 for (String possibleVal : possibleValues) { 671 648 if (possibleVal.isEmpty()) … … 765 742 } 766 743 767 checkComplex = Config.getPref().getBoolean(PREF_CHECK_COMPLEX, true) && !checkerData.isEmpty();744 checkComplex = Config.getPref().getBoolean(PREF_CHECK_COMPLEX, true); 768 745 if (isBeforeUpload) { 769 746 checkComplex = checkComplex && Config.getPref().getBoolean(PREF_CHECK_COMPLEX_BEFORE_UPLOAD, true); … … 911 888 return false; 912 889 } 913 914 protected static class CheckerData {915 private String description;916 protected List<CheckerElement> data = new ArrayList<>();917 private OsmPrimitiveType type;918 private TagCheckLevel level;919 protected Severity severity;920 921 private enum TagCheckLevel {922 TAG_CHECK_ERROR(1250),923 TAG_CHECK_WARN(1260),924 TAG_CHECK_INFO(1270);925 926 final int code;927 928 TagCheckLevel(int code) {929 this.code = code;930 }931 }932 933 protected static class CheckerElement {934 Object tag;935 Object value;936 boolean noMatch;937 boolean tagAll;938 boolean valueAll;939 boolean valueBool;940 941 private static Pattern getPattern(String str) {942 if (str.endsWith("/i"))943 return Pattern.compile(str.substring(1, str.length()-2), Pattern.CASE_INSENSITIVE);944 if (str.endsWith("/"))945 return Pattern.compile(str.substring(1, str.length()-1));946 947 throw new IllegalStateException();948 }949 950 CheckerElement(String exp) {951 Matcher m = Pattern.compile("(.+)([!=]=)(.+)").matcher(exp);952 m.matches();953 954 String n = m.group(1).trim();955 956 if ("*".equals(n)) {957 tagAll = true;958 } else {959 tag = n.startsWith("/") ? getPattern(n) : n;960 noMatch = "!=".equals(m.group(2));961 n = m.group(3).trim();962 switch (n) {963 case "*": valueAll = true; break;964 case "BOOLEAN_TRUE":965 valueBool = true;966 value = OsmUtils.TRUE_VALUE;967 break;968 case "BOOLEAN_FALSE":969 valueBool = true;970 value = OsmUtils.FALSE_VALUE;971 break;972 default:973 value = n.startsWith("/") ? getPattern(n) : n;974 }975 }976 }977 978 boolean match(Map<String, String> keys) {979 for (Entry<String, String> prop: keys.entrySet()) {980 String key = prop.getKey();981 String val = valueBool ? OsmUtils.getNamedOsmBoolean(prop.getValue()) : prop.getValue();982 if ((tagAll || (tag instanceof Pattern ? ((Pattern) tag).matcher(key).matches() : key.equals(tag)))983 && (valueAll || (value instanceof Pattern ? ((Pattern) value).matcher(val).matches() : val.equals(value))))984 return !noMatch;985 }986 return noMatch;987 }988 }989 990 private static final Pattern CLEAN_STR_PATTERN = Pattern.compile(" *# *([^#]+) *$");991 private static final Pattern SPLIT_TRIMMED_PATTERN = Pattern.compile(" *: *");992 private static final Pattern SPLIT_ELEMENTS_PATTERN = Pattern.compile(" *&& *");993 994 public String getData(final String str) {995 Matcher m = CLEAN_STR_PATTERN.matcher(str);996 String trimmed = m.replaceFirst("").trim();997 try {998 description = m.group(1);999 if (description != null && description.isEmpty()) {1000 description = null;1001 }1002 } catch (IllegalStateException e) {1003 Logging.error(e);1004 description = null;1005 }1006 String[] n = SPLIT_TRIMMED_PATTERN.split(trimmed, 3);1007 switch (n[0]) {1008 case "way":1009 type = OsmPrimitiveType.WAY;1010 break;1011 case "node":1012 type = OsmPrimitiveType.NODE;1013 break;1014 case "relation":1015 type = OsmPrimitiveType.RELATION;1016 break;1017 case "*":1018 type = null;1019 break;1020 default:1021 return tr("Could not find element type");1022 }1023 if (n.length != 3)1024 return tr("Incorrect number of parameters");1025 1026 switch (n[1]) {1027 case "W":1028 severity = Severity.WARNING;1029 level = TagCheckLevel.TAG_CHECK_WARN;1030 break;1031 case "E":1032 severity = Severity.ERROR;1033 level = TagCheckLevel.TAG_CHECK_ERROR;1034 break;1035 case "I":1036 severity = Severity.OTHER;1037 level = TagCheckLevel.TAG_CHECK_INFO;1038 break;1039 default:1040 return tr("Could not find warning level");1041 }1042 for (String exp: SPLIT_ELEMENTS_PATTERN.split(n[2])) {1043 try {1044 data.add(new CheckerElement(exp));1045 } catch (IllegalStateException e) {1046 Logging.trace(e);1047 return tr("Illegal expression ''{0}''", exp);1048 } catch (PatternSyntaxException e) {1049 Logging.trace(e);1050 return tr("Illegal regular expression ''{0}''", exp);1051 }1052 }1053 return null;1054 }1055 1056 public boolean match(OsmPrimitive osm, Map<String, String> keys) {1057 if (type != null && OsmPrimitiveType.from(osm) != type)1058 return false;1059 1060 for (CheckerElement ce : data) {1061 if (!ce.match(keys))1062 return false;1063 }1064 return true;1065 }1066 1067 /**1068 * Returns the error description.1069 * @return the error description1070 */1071 public String getDescription() {1072 return description;1073 }1074 1075 /**1076 * Returns the error severity.1077 * @return the error severity1078 */1079 public Severity getSeverity() {1080 return severity;1081 }1082 1083 /**1084 * Returns the error code.1085 * @return the error code1086 */1087 public int getCode() {1088 if (type == null)1089 return level.code;1090 1091 return level.code + type.ordinal() + 1;1092 }1093 }1094 890 }
Note:
See TracChangeset
for help on using the changeset viewer.