private void formatError(String message, Object... args) { if (args != null && args.length > 0) { message = String.format(message, args); } message = "Failed to parse `lint.xml` configuration file: " + message; LintDriver driver = new LintDriver( new IssueRegistry() { @Override @NonNull public List<Issue> getIssues() { return Collections.emptyList(); } }, mClient); mClient.report( new Context(driver, mProject, mProject, mConfigFile), IssueRegistry.LINT_ERROR, mProject.getConfiguration().getSeverity(IssueRegistry.LINT_ERROR), Location.create(mConfigFile), message, TextFormat.RAW); }
private void writeConfig() { try { // Write the contents to a new file first such that we don't clobber the // existing file if some I/O error occurs. File file = new File(mConfigFile.getParentFile(), mConfigFile.getName() + ".new"); // $NON-NLS-1$ Writer writer = new BufferedWriter(new FileWriter(file)); writer.write( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + //$NON-NLS-1$ "<lint>\n"); //$NON-NLS-1$ if (!mSuppressed.isEmpty() || !mSeverity.isEmpty()) { // Process the maps in a stable sorted order such that if the // files are checked into version control with the project, // there are no random diffs just because hashing algorithms // differ: Set<String> idSet = new HashSet<String>(); for (String id : mSuppressed.keySet()) { idSet.add(id); } for (String id : mSeverity.keySet()) { idSet.add(id); } List<String> ids = new ArrayList<String>(idSet); Collections.sort(ids); for (String id : ids) { writer.write(" <"); // $NON-NLS-1$ writer.write(TAG_ISSUE); writeAttribute(writer, ATTR_ID, id); Severity severity = mSeverity.get(id); if (severity != null) { writeAttribute(writer, ATTR_SEVERITY, severity.name().toLowerCase(Locale.US)); } List<Pattern> regexps = mRegexps != null ? mRegexps.get(id) : null; List<String> paths = mSuppressed.get(id); if (paths != null && !paths.isEmpty() || regexps != null && !regexps.isEmpty()) { writer.write('>'); writer.write('\n'); // The paths are already kept in sorted order when they are modified // by ignore(...) if (paths != null) { for (String path : paths) { writer.write(" <"); // $NON-NLS-1$ writer.write(TAG_IGNORE); writeAttribute(writer, ATTR_PATH, path.replace('\\', '/')); writer.write(" />\n"); // $NON-NLS-1$ } } if (regexps != null) { for (Pattern regexp : regexps) { writer.write(" <"); // $NON-NLS-1$ writer.write(TAG_IGNORE); writeAttribute(writer, ATTR_REGEXP, regexp.pattern()); writer.write(" />\n"); // $NON-NLS-1$ } } writer.write(" </"); // $NON-NLS-1$ writer.write(TAG_ISSUE); writer.write('>'); writer.write('\n'); } else { writer.write(" />\n"); // $NON-NLS-1$ } } } writer.write("</lint>"); // $NON-NLS-1$ writer.close(); // Move file into place: move current version to lint.xml~ (removing the old ~ file // if it exists), then move the new version to lint.xml. File oldFile = new File(mConfigFile.getParentFile(), mConfigFile.getName() + '~'); // $NON-NLS-1$ if (oldFile.exists()) { oldFile.delete(); } if (mConfigFile.exists()) { mConfigFile.renameTo(oldFile); } boolean ok = file.renameTo(mConfigFile); if (ok && oldFile.exists()) { oldFile.delete(); } } catch (Exception e) { mClient.log(e, null); } }
private void readConfig() { mSuppressed = new HashMap<String, List<String>>(); mSeverity = new HashMap<String, Severity>(); if (!mConfigFile.exists()) { return; } try { Document document = XmlUtils.parseUtfXmlFile(mConfigFile, false); NodeList issues = document.getElementsByTagName(TAG_ISSUE); Splitter splitter = Splitter.on(',').trimResults().omitEmptyStrings(); for (int i = 0, count = issues.getLength(); i < count; i++) { Node node = issues.item(i); Element element = (Element) node; String idList = element.getAttribute(ATTR_ID); if (idList.isEmpty()) { formatError("Invalid lint config file: Missing required issue id attribute"); continue; } Iterable<String> ids = splitter.split(idList); NamedNodeMap attributes = node.getAttributes(); for (int j = 0, n = attributes.getLength(); j < n; j++) { Node attribute = attributes.item(j); String name = attribute.getNodeName(); String value = attribute.getNodeValue(); if (ATTR_ID.equals(name)) { // already handled } else if (ATTR_SEVERITY.equals(name)) { for (Severity severity : Severity.values()) { if (value.equalsIgnoreCase(severity.name())) { for (String id : ids) { mSeverity.put(id, severity); } break; } } } else { formatError("Unexpected attribute \"%1$s\"", name); } } // Look up ignored errors NodeList childNodes = element.getChildNodes(); if (childNodes.getLength() > 0) { for (int j = 0, n = childNodes.getLength(); j < n; j++) { Node child = childNodes.item(j); if (child.getNodeType() == Node.ELEMENT_NODE) { Element ignore = (Element) child; String path = ignore.getAttribute(ATTR_PATH); if (path.isEmpty()) { String regexp = ignore.getAttribute(ATTR_REGEXP); if (regexp.isEmpty()) { formatError( "Missing required attribute %1$s or %2$s under %3$s", ATTR_PATH, ATTR_REGEXP, idList); } else { addRegexp(idList, ids, n, regexp, false); } } else { // Normalize path format to File.separator. Also // handle the file format containing / or \. if (File.separatorChar == '/') { path = path.replace('\\', '/'); } else { path = path.replace('/', File.separatorChar); } if (path.indexOf('*') != -1) { String regexp = globToRegexp(path); addRegexp(idList, ids, n, regexp, false); } else { for (String id : ids) { List<String> paths = mSuppressed.get(id); if (paths == null) { paths = new ArrayList<String>(n / 2 + 1); mSuppressed.put(id, paths); } paths.add(path); } } } } } } } } catch (SAXParseException e) { formatError(e.getMessage()); } catch (Exception e) { mClient.log(e, null); } }
/** * Creates a list of detectors applicable to the given cope, and with the given configuration. * * @param client the client to report errors to * @param configuration the configuration to look up which issues are enabled etc from * @param scope the scope for the analysis, to filter out detectors that require wider analysis * than is currently being performed * @param scopeToDetectors an optional map which (if not null) will be filled by this method to * contain mappings from each scope to the applicable detectors for that scope * @return a list of new detector instances */ @NonNull final List<? extends Detector> createDetectors( @NonNull LintClient client, @NonNull Configuration configuration, @NonNull EnumSet<Scope> scope, @Nullable Map<Scope, List<Detector>> scopeToDetectors) { List<Issue> issues = getIssues(); Set<Class<? extends Detector>> detectorClasses = new HashSet<Class<? extends Detector>>(); Map<Class<? extends Detector>, EnumSet<Scope>> detectorToScope = new HashMap<Class<? extends Detector>, EnumSet<Scope>>(); for (Issue issue : issues) { Class<? extends Detector> detectorClass = issue.getDetectorClass(); EnumSet<Scope> issueScope = issue.getScope(); if (!detectorClasses.contains(detectorClass)) { // Determine if the issue is enabled if (!configuration.isEnabled(issue)) { continue; } // Determine if the scope matches if (!issue.isAdequate(scope)) { continue; } detectorClass = client.replaceDetector(detectorClass); assert detectorClass != null : issue.getId(); detectorClasses.add(detectorClass); } if (scopeToDetectors != null) { EnumSet<Scope> s = detectorToScope.get(detectorClass); if (s == null) { detectorToScope.put(detectorClass, issueScope); } else if (!s.containsAll(issueScope)) { EnumSet<Scope> union = EnumSet.copyOf(s); union.addAll(issueScope); detectorToScope.put(detectorClass, union); } } } List<Detector> detectors = new ArrayList<Detector>(detectorClasses.size()); for (Class<? extends Detector> clz : detectorClasses) { try { Detector detector = clz.newInstance(); detectors.add(detector); if (scopeToDetectors != null) { EnumSet<Scope> union = detectorToScope.get(clz); for (Scope s : union) { List<Detector> list = scopeToDetectors.get(s); if (list == null) { list = new ArrayList<Detector>(); scopeToDetectors.put(s, list); } list.add(detector); } } } catch (Throwable t) { client.log(t, "Can't initialize detector %1$s", clz.getName()); // $NON-NLS-1$ } } return detectors; }