问题
我正在编写一个自定义棉绒规则(使用此example),以查找使用唯一字符串变量声明的重复字符串。例如,在strings.xml
中,
<string name="cancel">Cancel</string>
<string name="activity_cancel_text">Cancel</string>
期望
将lint
添加到strings.xml中时显示activity_cancel_text
警告
方法
-开发人员首次打开strings.xml
时,请通读整个文件,并将哈希表维护为
key
= "Cancel"
和value
= "cancel"
-访问每个元素,即字符串值(在这种情况下,在第2行上是{Cancel
),如果该键存在于地图中,则发出皮棉问题警告
问题:在调用visitElement()
之前需要阅读strings.xml。该怎么做?
文档稀疏,即使进行单元测试也很难调试(断点永远不会命中)。因此,我所取得的任何进展都是在阅读了数十篇博客后经过反复试验。为了测试我的更改,我将自定义的lint jar安装到~/.android/lint
,然后对一个测试的Android项目进行更改以观察lint警告。
StringDupeDetector.java
package com.example.lint.checks;
import com.android.SdkConstants;
import com.android.resources.ResourceFolderType;
import com.android.tools.lint.detector.api.Category;
import com.android.tools.lint.detector.api.Context;
import com.android.tools.lint.detector.api.Implementation;
import com.android.tools.lint.detector.api.Issue;
import com.android.tools.lint.detector.api.Location;
import com.android.tools.lint.detector.api.ResourceXmlDetector;
import com.android.tools.lint.detector.api.Scope;
import com.android.tools.lint.detector.api.Severity;
import com.android.tools.lint.detector.api.XmlContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.w3c.dom.Element;
import java.io.File;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class StringDupeDetector extends ResourceXmlDetector {
public StringDupeDetector() {}
public static final Issue ISSUE = Issue.create(
// ID: used in @SuppressLint warnings etc
"StringDupe",
// Title -- shown in the IDE's preference dialog, as category headers in the
// Analysis results window, etc
"String Dupe",
// Full explanation of the issue; you can use some markdown markup such as
// `monospace`, *italic*, and **bold**.
"This check highlights string/color/dimen literals in code which duplicates " +
"the string resources. Blah blah blah.\n" +
"\n" +
"Another paragraph here.\n",
Category.CORRECTNESS,
6,
Severity.ERROR,
new Implementation(
StringDupeDetector.class,
Scope.RESOURCE_FILE_SCOPE));
private static final Map<String, String> stringResourceMap = new HashMap<>(); // string, stringId
private static final Map<String, Location> violationsMap = new HashMap(); // string, location
private static final String ISSUE_MSG_FORMAT = "WARNING! %s is already defined as %s.";
@Nullable
@Override
public Collection<String> getApplicableElements() {
return Collections.singletonList(SdkConstants.TAG_STRING);
}
@Override
public boolean appliesTo(ResourceFolderType folderType) {
return folderType == ResourceFolderType.VALUES;
}
@Override
public void visitElement(@NotNull XmlContext context, @NotNull Element element) {
final String string = element.getTextContent();
final String stringId = element.getAttribute(SdkConstants.ATTR_NAME);
if (stringResourceMap.containsKey(string)) {
// found a dupe!
violationsMap.put(string, context.getLocation(element));
context.report(ISSUE, element, context.getLocation(element), String.format(ISSUE_MSG_FORMAT, string, stringId));
} else {
stringResourceMap.put(string, stringId);
}
}
}