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);
    }
  }
예제 #4
0
  /**
   * 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;
  }