use of com.android.tools.lint.detector.api.Issue in project android by JetBrains.
the class AndroidLintExternalAnnotator method apply.
@Override
public void apply(@NotNull PsiFile file, State state, @NotNull AnnotationHolder holder) {
if (state.isDirty()) {
return;
}
final Project project = file.getProject();
if (DumbService.isDumb(project))
return;
for (ProblemData problemData : state.getProblems()) {
final Issue issue = problemData.getIssue();
final String message = problemData.getMessage();
final TextRange range = problemData.getTextRange();
if (range.getStartOffset() == range.getEndOffset()) {
continue;
}
final Pair<AndroidLintInspectionBase, HighlightDisplayLevel> pair = AndroidLintUtil.getHighlighLevelAndInspection(project, issue, file);
if (pair == null) {
continue;
}
final AndroidLintInspectionBase inspection = pair.getFirst();
HighlightDisplayLevel displayLevel = pair.getSecond();
if (inspection != null) {
final HighlightDisplayKey key = HighlightDisplayKey.find(inspection.getShortName());
if (key != null) {
final PsiElement startElement = file.findElementAt(range.getStartOffset());
final PsiElement endElement = file.findElementAt(range.getEndOffset() - 1);
if (startElement != null && endElement != null && !inspection.isSuppressedFor(startElement)) {
if (problemData.getConfiguredSeverity() != null) {
HighlightDisplayLevel configuredLevel = AndroidLintInspectionBase.toHighlightDisplayLevel(problemData.getConfiguredSeverity());
if (configuredLevel != null) {
displayLevel = configuredLevel;
}
}
final Annotation annotation = createAnnotation(holder, message, range, displayLevel, issue);
for (AndroidLintQuickFix fix : inspection.getQuickFixes(startElement, endElement, message)) {
if (fix.isApplicable(startElement, endElement, AndroidQuickfixContexts.EditorContext.TYPE)) {
annotation.registerFix(new MyFixingIntention(fix, startElement, endElement));
}
}
for (IntentionAction intention : inspection.getIntentions(startElement, endElement)) {
annotation.registerFix(intention);
}
String id = key.getID();
if (LintIdeIssueRegistry.CUSTOM_ERROR == issue || LintIdeIssueRegistry.CUSTOM_WARNING == issue) {
Issue original = LintIdeClient.findCustomIssue(message);
if (original != null) {
id = original.getId();
}
}
annotation.registerFix(new SuppressLintIntentionAction(id, startElement));
annotation.registerFix(new MyDisableInspectionFix(key));
annotation.registerFix(new MyEditInspectionToolsSettingsAction(key, inspection));
if (issue == DeprecationDetector.ISSUE || issue == GradleDetector.DEPRECATED) {
annotation.setHighlightType(ProblemHighlightType.LIKE_DEPRECATED);
}
if (INCLUDE_IDEA_SUPPRESS_ACTIONS) {
final SuppressQuickFix[] suppressActions = inspection.getBatchSuppressActions(startElement);
for (SuppressQuickFix action : suppressActions) {
if (action.isAvailable(project, startElement)) {
ProblemHighlightType type = annotation.getHighlightType();
annotation.registerFix(action, null, key, InspectionManager.getInstance(project).createProblemDescriptor(startElement, endElement, message, type, true, LocalQuickFix.EMPTY_ARRAY));
}
}
}
}
}
}
}
}
use of com.android.tools.lint.detector.api.Issue in project android by JetBrains.
the class AndroidLintExternalAnnotator method getIssuesFromInspections.
@NotNull
static List<Issue> getIssuesFromInspections(@NotNull Project project, @Nullable PsiElement context) {
final List<Issue> result = new ArrayList<>();
final IssueRegistry fullRegistry = new LintIdeIssueRegistry();
for (Issue issue : fullRegistry.getIssues()) {
final String inspectionShortName = AndroidLintInspectionBase.getInspectionShortNameByIssue(project, issue);
if (inspectionShortName == null) {
continue;
}
final HighlightDisplayKey key = HighlightDisplayKey.find(inspectionShortName);
if (key == null) {
continue;
}
final InspectionProfile profile = InspectionProjectProfileManager.getInstance(project).getCurrentProfile();
final boolean enabled = context != null ? profile.isToolEnabled(key, context) : profile.isToolEnabled(key);
if (!enabled) {
continue;
} else if (!issue.isEnabledByDefault()) {
// If an issue is marked as not enabled by default, lint won't run it, even if it's in the set
// of issues provided by an issue registry. Since in the IDE we're enforcing the enabled-state via
// inspection profiles, mark the issue as enabled to allow users to turn on a lint check directly
// via the inspections UI.
issue.setEnabledByDefault(true);
}
result.add(issue);
}
return result;
}
use of com.android.tools.lint.detector.api.Issue in project android by JetBrains.
the class UnusedResourcesProcessor method computeUnusedDeclarationElements.
@NotNull
private List<PsiElement> computeUnusedDeclarationElements(Map<Issue, Map<File, List<ProblemData>>> map) {
final List<PsiElement> elements = Lists.newArrayList();
// Make sure lint didn't put extra issues into the map
for (Issue issue : Lists.newArrayList(map.keySet())) {
if (issue != UnusedResourceDetector.ISSUE && issue != UnusedResourceDetector.ISSUE_IDS) {
map.remove(issue);
}
}
ApplicationManager.getApplication().assertReadAccessAllowed();
PsiManager manager = PsiManager.getInstance(myProject);
for (Issue issue : new Issue[] { UnusedResourceDetector.ISSUE, UnusedResourceDetector.ISSUE_IDS }) {
Map<File, List<ProblemData>> fileListMap = map.get(issue);
if (fileListMap != null && !fileListMap.isEmpty()) {
Map<File, PsiFile> files = Maps.newHashMap();
for (File file : fileListMap.keySet()) {
VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByIoFile(file);
if (virtualFile != null) {
if (!virtualFile.isDirectory()) {
// Gradle model errors currently don't have source positions
PsiFile psiFile = manager.findFile(virtualFile);
if (psiFile != null) {
files.put(file, psiFile);
}
}
}
}
if (!files.isEmpty()) {
for (File file : files.keySet()) {
PsiFile psiFile = files.get(file);
if (psiFile == null) {
// where we only had the project directory as the location from the Gradle model
continue;
}
if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, psiFile)) {
continue;
}
List<ProblemData> problems = fileListMap.get(file);
if (psiFile.getFileType().isBinary()) {
// Delete the whole file
if (matchesFilter(fileListMap, file)) {
elements.add(psiFile);
}
} else {
ResourceFolderType folderType = ResourceHelper.getFolderType(psiFile);
if (folderType == null) {
// file; see for example http://b.android.com/220069.)
if (psiFile.getFileType() == GroovyFileType.GROOVY_FILE_TYPE && psiFile instanceof GroovyFile) {
((GroovyFile) psiFile).accept(new GroovyRecursiveElementVisitor() {
@Override
public void visitApplicationStatement(GrApplicationStatement applicationStatement) {
super.visitApplicationStatement(applicationStatement);
PsiMethod method = applicationStatement.resolveMethod();
if (method != null && method.getName().equals("resValue")) {
GrExpression[] args = applicationStatement.getArgumentList().getExpressionArguments();
if (args.length >= 3) {
Object typeString = GroovyConstantExpressionEvaluator.evaluate(args[0]);
Object nameString = GroovyConstantExpressionEvaluator.evaluate(args[1]);
// See if this is one of the unused resources
if (typeString != null && nameString != null) {
List<ProblemData> problems = fileListMap.get(VfsUtilCore.virtualToIoFile(psiFile.getVirtualFile()));
if (problems != null) {
for (ProblemData problem : problems) {
String unusedResource = UnusedResourceDetector.getUnusedResource(problem.getMessage(), TextFormat.RAW);
if (unusedResource != null && unusedResource.equals(SdkConstants.R_PREFIX + typeString + '.' + nameString)) {
elements.add(applicationStatement);
}
}
}
}
}
}
}
});
}
continue;
}
if (folderType != ResourceFolderType.VALUES) {
// also being deleted as unused
if (issue == UnusedResourceDetector.ISSUE_IDS) {
Map<File, List<ProblemData>> m = map.get(UnusedResourceDetector.ISSUE);
if (m != null && m.containsKey(file)) {
// Yes - skip
continue;
}
// Delete ranges within the file
addElementsInFile(elements, psiFile, problems);
} else {
// Unused non-value resource file: Delete the whole file
if (matchesFilter(fileListMap, file)) {
elements.add(psiFile);
}
}
} else {
addElementsInFile(elements, psiFile, problems);
}
}
}
}
}
}
return elements;
}
use of com.android.tools.lint.detector.api.Issue in project android by JetBrains.
the class LintNotificationPanel method updateExplanation.
private void updateExplanation(@Nullable IssueData selected) {
// We have the capability to show markup text here, e.g.
// myExplanationPane.setContentType(UIUtil.HTML_MIME)
// and then use an HtmlBuilder to populate it with for
// example issue.getExplanation(HTML). However, the builtin
// HTML formatter ends up using a bunch of weird fonts etc
// so the dialog just ends up looking tacky.
String headerFontColor = HtmlBuilderHelper.getHeaderFontColor();
HtmlBuilder builder = new HtmlBuilder();
builder.openHtmlBody();
if (selected != null) {
builder.addHeading("Message: ", headerFontColor);
builder.add(selected.message).newline();
// Look for quick fixes
AndroidLintInspectionBase inspection = selected.inspection;
AndroidLintQuickFix[] quickFixes = inspection.getQuickFixes(selected.startElement, selected.endElement, selected.message);
IntentionAction[] intentions = inspection.getIntentions(selected.startElement, selected.endElement);
builder.addHeading("Suggested Fixes:", headerFontColor).newline();
builder.beginList();
for (final AndroidLintQuickFix fix : quickFixes) {
builder.listItem();
builder.addLink(fix.getName(), myLinkManager.createRunnableLink(() -> {
myPopup.cancel();
// TODO: Pull in editor context?
WriteCommandAction.runWriteCommandAction(selected.startElement.getProject(), () -> {
fix.apply(selected.startElement, selected.endElement, AndroidQuickfixContexts.BatchContext.getInstance());
});
}));
}
for (final IntentionAction fix : intentions) {
builder.listItem();
builder.addLink(fix.getText(), myLinkManager.createRunnableLink(() -> {
NlModel model = myScreenView.getModel();
Editor editor = PsiEditorUtil.Service.getInstance().findEditorByPsiElement(selected.startElement);
if (editor != null) {
editor.getCaretModel().getCurrentCaret().moveToOffset(selected.startElement.getTextOffset());
myPopup.cancel();
WriteCommandAction.runWriteCommandAction(model.getProject(), () -> {
fix.invoke(model.getProject(), editor, model.getFile());
});
}
}));
}
final SuppressLintIntentionAction suppress = new SuppressLintIntentionAction(selected.issue, selected.startElement);
builder.listItem();
builder.addLink(suppress.getText(), myLinkManager.createRunnableLink(() -> {
myPopup.cancel();
WriteCommandAction.runWriteCommandAction(selected.startElement.getProject(), () -> {
suppress.invoke(selected.startElement.getProject(), null, myScreenView.getModel().getFile());
});
}));
builder.endList();
Issue issue = selected.issue;
builder.addHeading("Priority: ", headerFontColor);
builder.addHtml(String.format("%1$d / 10", issue.getPriority()));
builder.newline();
builder.addHeading("Category: ", headerFontColor);
builder.add(issue.getCategory().getFullName());
builder.newline();
builder.addHeading("Severity: ", headerFontColor);
builder.beginSpan();
// Use converted level instead of *default* severity such that we match any user configured overrides
HighlightDisplayLevel level = selected.level;
builder.add(StringUtil.capitalize(level.getName().toLowerCase(Locale.US)));
builder.endSpan();
builder.newline();
builder.addHeading("Explanation: ", headerFontColor);
String description = issue.getBriefDescription(HTML);
builder.addHtml(description);
if (!description.isEmpty() && Character.isLetter(description.charAt(description.length() - 1))) {
builder.addHtml(".");
}
builder.newline();
String explanationHtml = issue.getExplanation(HTML);
builder.addHtml(explanationHtml);
List<String> moreInfo = issue.getMoreInfo();
builder.newline();
int count = moreInfo.size();
if (count > 1) {
builder.addHeading("More Info: ", headerFontColor);
builder.beginList();
}
for (String uri : moreInfo) {
if (count > 1) {
builder.listItem();
}
builder.addLink(uri, uri);
}
if (count > 1) {
builder.endList();
}
builder.newline();
}
builder.closeHtmlBody();
try {
myExplanationPane.read(new StringReader(builder.getHtml()), null);
HtmlBuilderHelper.fixFontStyles(myExplanationPane);
myExplanationPane.setCaretPosition(0);
} catch (IOException ignore) {
// can't happen for internal string reading
}
}
Aggregations