public RerunAction(JComponent comp) { super( InspectionsBundle.message("inspection.action.rerun"), InspectionsBundle.message("inspection.action.rerun"), AllIcons.Actions.Rerun); registerCustomShortcutSet(CommonShortcuts.getRerun(), comp); }
public void showDescription(InspectionTool tool) { if (tool.getShortName().length() == 0) { showEmpty(); return; } @NonNls StringBuffer page = new StringBuffer(); page.append("<table border='0' cellspacing='0' cellpadding='0' width='100%'>"); page.append("<tr><td colspan='2'>"); HTMLComposer.appendHeading( page, InspectionsBundle.message("inspection.tool.in.browser.id.title")); page.append("</td></tr>"); page.append("<tr><td width='37'></td>" + "<td>"); page.append(tool.getShortName()); page.append("</td></tr>"); page.append("<tr height='10'></tr>"); page.append("<tr><td colspan='2'>"); HTMLComposer.appendHeading( page, InspectionsBundle.message("inspection.tool.in.browser.description.title")); page.append("</td></tr>"); page.append("<tr><td width='37'></td>" + "<td>"); @NonNls final String underConstruction = "<b>" + UNDER_CONSTRUCTION + "</b></html>"; try { @NonNls String description = tool.loadDescription(); if (description == null) { description = underConstruction; } page.append(UIUtil.getHtmlBody(description)); page.append("</td></tr></table>"); myHTMLViewer.setText(XmlStringUtil.wrapInHtml(page)); setupStyle(); } finally { myCurrentEntity = null; } }
private OptionsPanel() { super(new GridBagLayout()); GridBagConstraints gc = new GridBagConstraints(); gc.fill = GridBagConstraints.HORIZONTAL; gc.weightx = 1; gc.weighty = 0; gc.anchor = GridBagConstraints.NORTHWEST; myPackageLocalForMembersCheckbox = new JCheckBox(InspectionsBundle.message("inspection.visibility.option")); myPackageLocalForMembersCheckbox.setSelected(SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS); myPackageLocalForMembersCheckbox .getModel() .addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS = myPackageLocalForMembersCheckbox.isSelected(); } }); gc.gridy = 0; add(myPackageLocalForMembersCheckbox, gc); myPackageLocalForTopClassesCheckbox = new JCheckBox(InspectionsBundle.message("inspection.visibility.option1")); myPackageLocalForTopClassesCheckbox.setSelected(SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES); myPackageLocalForTopClassesCheckbox .getModel() .addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES = myPackageLocalForTopClassesCheckbox.isSelected(); } }); gc.gridy = 1; add(myPackageLocalForTopClassesCheckbox, gc); myPrivateForInnersCheckbox = new JCheckBox(InspectionsBundle.message("inspection.visibility.option2")); myPrivateForInnersCheckbox.setSelected(SUGGEST_PRIVATE_FOR_INNERS); myPrivateForInnersCheckbox .getModel() .addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { SUGGEST_PRIVATE_FOR_INNERS = myPrivateForInnersCheckbox.isSelected(); } }); gc.gridy = 2; gc.weighty = 1; add(myPrivateForInnersCheckbox, gc); }
private OptionsPanel() { super(new GridBagLayout()); GridBagConstraints gc = new GridBagConstraints(); gc.weighty = 0; gc.weightx = 1; gc.fill = GridBagConstraints.HORIZONTAL; gc.anchor = GridBagConstraints.NORTHWEST; myReportClassesCheckbox = new JCheckBox(InspectionsBundle.message("inspection.can.be.final.option")); myReportClassesCheckbox.setSelected(REPORT_CLASSES); myReportClassesCheckbox .getModel() .addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { REPORT_CLASSES = myReportClassesCheckbox.isSelected(); } }); gc.gridy = 0; add(myReportClassesCheckbox, gc); myReportMethodsCheckbox = new JCheckBox(InspectionsBundle.message("inspection.can.be.final.option1")); myReportMethodsCheckbox.setSelected(REPORT_METHODS); myReportMethodsCheckbox .getModel() .addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { REPORT_METHODS = myReportMethodsCheckbox.isSelected(); } }); gc.gridy++; add(myReportMethodsCheckbox, gc); myReportFieldsCheckbox = new JCheckBox(InspectionsBundle.message("inspection.can.be.final.option2")); myReportFieldsCheckbox.setSelected(REPORT_FIELDS); myReportFieldsCheckbox .getModel() .addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { REPORT_FIELDS = myReportFieldsCheckbox.isSelected(); } }); gc.weighty = 1; gc.gridy++; add(myReportFieldsCheckbox, gc); }
@Override @Nullable public CommonProblemDescriptor[] checkElement( @NotNull final RefEntity refEntity, @NotNull final AnalysisScope scope, @NotNull final InspectionManager manager, @NotNull final GlobalInspectionContext globalContext, @NotNull final ProblemDescriptionsProcessor processor) { if (refEntity instanceof RefJavaElement) { final RefJavaElement refElement = (RefJavaElement) refEntity; if (refElement instanceof RefParameter) return null; if (!refElement.isReferenced()) return null; if (refElement.isSyntheticJSP()) return null; if (refElement.isFinal()) return null; if (!((RefElementImpl) refElement).checkFlag(CanBeFinalAnnotator.CAN_BE_FINAL_MASK)) return null; final PsiMember psiMember = (PsiMember) refElement.getElement(); if (psiMember == null || !CanBeFinalHandler.allowToBeFinal(psiMember)) return null; PsiIdentifier psiIdentifier = null; if (refElement instanceof RefClass) { RefClass refClass = (RefClass) refElement; if (refClass.isInterface() || refClass.isAnonymous() || refClass.isAbstract()) return null; if (!isReportClasses()) return null; psiIdentifier = ((PsiClass) psiMember).getNameIdentifier(); } else if (refElement instanceof RefMethod) { RefMethod refMethod = (RefMethod) refElement; if (refMethod.getOwnerClass().isFinal()) return null; if (!isReportMethods()) return null; psiIdentifier = ((PsiMethod) psiMember).getNameIdentifier(); } else if (refElement instanceof RefField) { if (!isReportFields()) return null; psiIdentifier = ((PsiField) psiMember).getNameIdentifier(); } if (psiIdentifier != null) { return new ProblemDescriptor[] { manager.createProblemDescriptor( psiIdentifier, InspectionsBundle.message("inspection.export.results.can.be.final.description"), new AcceptSuggested(globalContext.getRefManager()), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false) }; } } return null; }
private void appendSuppressSection(final StringBuffer buf) { final InspectionTool tool = getTool(); if (tool != null) { final HighlightDisplayKey key = HighlightDisplayKey.find(tool.getShortName()); if (key != null) { // dummy entry points final SuppressActionWrapper.SuppressTreeAction[] suppressActions = new SuppressActionWrapper( myView.getProject(), tool, myView.getTree().getSelectionPaths()) .getChildren(null); if (suppressActions.length > 0) { final List<AnAction> activeSuppressActions = new ArrayList<AnAction>(); for (SuppressActionWrapper.SuppressTreeAction suppressAction : suppressActions) { if (suppressAction.isAvailable()) { activeSuppressActions.add(suppressAction); } } if (!activeSuppressActions.isEmpty()) { int idx = 0; @NonNls final String br = "<br>"; buf.append(br); HTMLComposerImpl.appendHeading( buf, InspectionsBundle.message("inspection.export.results.suppress")); for (AnAction suppressAction : activeSuppressActions) { buf.append(br); if (idx == activeSuppressActions.size() - 1) { buf.append(br); } HTMLComposer.appendAfterHeaderIndention(buf); @NonNls final String href = "<a HREF=\"file://bred.txt#suppress:" + idx + "\">" + suppressAction.getTemplatePresentation().getText() + "</a>"; buf.append(href); idx++; } } } } } }
private EditSettingsAction() { super( InspectionsBundle.message("inspection.action.edit.settings"), InspectionsBundle.message("inspection.action.edit.settings"), AllIcons.General.Settings); }
@SuppressWarnings({"NonStaticInitializer"}) private JComponent createRightActionsToolbar() { myIncludeAction = new AnAction(InspectionsBundle.message("inspections.result.view.include.action.text")) { { registerCustomShortcutSet(CommonShortcuts.INSERT, myTree); } @Override public void actionPerformed(AnActionEvent e) { final TreePath[] paths = myTree.getSelectionPaths(); if (paths != null) { for (TreePath path : paths) { ((InspectionTreeNode) path.getLastPathComponent()).amnesty(); } } updateView(false); } @Override public void update(final AnActionEvent e) { final TreePath[] paths = myTree.getSelectionPaths(); e.getPresentation() .setEnabled( paths != null && paths.length > 0 && !myGlobalInspectionContext.getUIOptions().FILTER_RESOLVED_ITEMS); } }; myExcludeAction = new AnAction(InspectionsBundle.message("inspections.result.view.exclude.action.text")) { { registerCustomShortcutSet(CommonShortcuts.getDelete(), myTree); } @Override public void actionPerformed(final AnActionEvent e) { final TreePath[] paths = myTree.getSelectionPaths(); if (paths != null) { for (TreePath path : paths) { ((InspectionTreeNode) path.getLastPathComponent()).ignoreElement(); } } updateView(false); } @Override public void update(final AnActionEvent e) { final TreePath[] path = myTree.getSelectionPaths(); e.getPresentation().setEnabled(path != null && path.length > 0); } }; DefaultActionGroup specialGroup = new DefaultActionGroup(); specialGroup.add(myGlobalInspectionContext.getUIOptions().createGroupBySeverityAction(this)); specialGroup.add(myGlobalInspectionContext.getUIOptions().createGroupByDirectoryAction(this)); specialGroup.add( myGlobalInspectionContext.getUIOptions().createFilterResolvedItemsAction(this)); specialGroup.add( myGlobalInspectionContext.getUIOptions().createShowOutdatedProblemsAction(this)); specialGroup.add(myGlobalInspectionContext.getUIOptions().createShowDiffOnlyAction(this)); specialGroup.add(new EditSettingsAction()); specialGroup.add(new InvokeQuickFixAction(this)); specialGroup.add(new InspectionsOptionsToolbarAction(this)); return createToolbar(specialGroup); }
class Browser extends JPanel { private static final String UNDER_CONSTRUCTION = InspectionsBundle.message("inspection.tool.description.under.construction.text"); private final List<ClickListener> myClickListeners = ContainerUtil.createLockFreeCopyOnWriteList(); private RefEntity myCurrentEntity; private JEditorPane myHTMLViewer; private final InspectionResultsView myView; private final HyperlinkListener myHyperLinkListener; private CommonProblemDescriptor myCurrentDescriptor; public static class ClickEvent { public static final int REF_ELEMENT = 1; public static final int FILE_OFFSET = 2; private final VirtualFile myFile; private final int myStartPosition; private final int myEndPosition; private final RefElement refElement; private final int myEventType; public ClickEvent(VirtualFile myFile, int myStartPosition, int myEndPosition) { this.myFile = myFile; this.myStartPosition = myStartPosition; this.myEndPosition = myEndPosition; myEventType = FILE_OFFSET; refElement = null; } public int getEventType() { return myEventType; } public VirtualFile getFile() { return myFile; } public int getStartOffset() { return myStartPosition; } public int getEndOffset() { return myEndPosition; } public RefElement getClickedElement() { return refElement; } } public void dispose() { removeAll(); if (myHTMLViewer != null) { myHTMLViewer.removeHyperlinkListener(myHyperLinkListener); myHTMLViewer = null; } myClickListeners.clear(); } public interface ClickListener { void referenceClicked(ClickEvent e); } private void showPageFromHistory(RefEntity newEntity) { InspectionTool tool = getTool(newEntity); try { if (tool instanceof DescriptorProviderInspection && !(tool instanceof CommonInspectionToolWrapper)) { showEmpty(); } else { try { String html = generateHTML(newEntity, tool); myHTMLViewer.read(new StringReader(html), null); setupStyle(); myHTMLViewer.setCaretPosition(0); } catch (Exception e) { showEmpty(); } } } finally { myCurrentEntity = newEntity; myCurrentDescriptor = null; } } public void showPageFor(RefEntity refEntity, CommonProblemDescriptor descriptor) { try { String html = generateHTML(refEntity, descriptor); myHTMLViewer.read(new StringReader(html), null); setupStyle(); myHTMLViewer.setCaretPosition(0); } catch (Exception e) { showEmpty(); } finally { myCurrentEntity = refEntity; myCurrentDescriptor = descriptor; } } public void showPageFor(RefEntity newEntity) { if (newEntity == null) { showEmpty(); return; } // multiple problems for one entity -> refresh browser showPageFromHistory(newEntity.getRefManager().getRefinedElement(newEntity)); } public Browser(InspectionResultsView view) { super(new BorderLayout()); myView = view; myCurrentEntity = null; myCurrentDescriptor = null; myHTMLViewer = new JEditorPane( UIUtil.HTML_MIME, InspectionsBundle.message("inspection.offline.view.empty.browser.text")); myHTMLViewer.setEditable(false); myHyperLinkListener = new HyperlinkListener() { @Override public void hyperlinkUpdate(HyperlinkEvent e) { if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { JEditorPane pane = (JEditorPane) e.getSource(); if (e instanceof HTMLFrameHyperlinkEvent) { HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent) e; HTMLDocument doc = (HTMLDocument) pane.getDocument(); doc.processHTMLFrameHyperlinkEvent(evt); } else { try { URL url = e.getURL(); @NonNls String ref = url.getRef(); if (ref.startsWith("pos:")) { int delimeterPos = ref.indexOf(':', "pos:".length() + 1); String startPosition = ref.substring("pos:".length(), delimeterPos); String endPosition = ref.substring(delimeterPos + 1); Integer textStartOffset = new Integer(startPosition); Integer textEndOffset = new Integer(endPosition); String fileURL = url.toExternalForm(); fileURL = fileURL.substring(0, fileURL.indexOf('#')); VirtualFile vFile = VirtualFileManager.getInstance().findFileByUrl(fileURL); if (vFile != null) { fireClickEvent(vFile, textStartOffset.intValue(), textEndOffset.intValue()); } } else if (ref.startsWith("descr:")) { if (myCurrentDescriptor instanceof ProblemDescriptor) { PsiElement psiElement = ((ProblemDescriptor) myCurrentDescriptor).getPsiElement(); if (psiElement == null) return; VirtualFile vFile = psiElement.getContainingFile().getVirtualFile(); if (vFile != null) { TextRange range = ((ProblemDescriptorBase) myCurrentDescriptor).getTextRange(); fireClickEvent(vFile, range.getStartOffset(), range.getEndOffset()); } } } else if (ref.startsWith("invoke:")) { int actionNumber = Integer.parseInt(ref.substring("invoke:".length())); getTool() .getQuickFixes(new RefElement[] {(RefElement) myCurrentEntity})[ actionNumber] .doApplyFix(new RefElement[] {(RefElement) myCurrentEntity}, myView); } else if (ref.startsWith("invokelocal:")) { int actionNumber = Integer.parseInt(ref.substring("invokelocal:".length())); if (actionNumber > -1) { invokeLocalFix(actionNumber); } } else if (ref.startsWith("suppress:")) { final SuppressActionWrapper.SuppressTreeAction[] suppressTreeActions = new SuppressActionWrapper( myView.getProject(), getTool(), myView.getTree().getSelectionPaths()) .getChildren(null); final List<AnAction> activeActions = new ArrayList<AnAction>(); for (SuppressActionWrapper.SuppressTreeAction suppressTreeAction : suppressTreeActions) { if (suppressTreeAction.isAvailable()) activeActions.add(suppressTreeAction); } if (!activeActions.isEmpty()) { int actionNumber = Integer.parseInt(ref.substring("suppress:".length())); if (actionNumber > -1 && activeActions.size() > actionNumber) { activeActions.get(actionNumber).actionPerformed(null); } } } else { int offset = Integer.parseInt(ref); String fileURL = url.toExternalForm(); fileURL = fileURL.substring(0, fileURL.indexOf('#')); VirtualFile vFile = VirtualFileManager.getInstance().findFileByUrl(fileURL); if (vFile == null) { vFile = VfsUtil.findFileByURL(url); } if (vFile != null) { fireClickEvent(vFile, offset, offset); } } } catch (Throwable t) { // ??? } } } } }; myHTMLViewer.addHyperlinkListener(myHyperLinkListener); final JScrollPane pane = ScrollPaneFactory.createScrollPane(myHTMLViewer); pane.setBorder(null); add(pane, BorderLayout.CENTER); setupStyle(); } private void setupStyle() { Document document = myHTMLViewer.getDocument(); if (!(document instanceof StyledDocument)) { return; } StyledDocument styledDocument = (StyledDocument) document; EditorColorsManager colorsManager = EditorColorsManager.getInstance(); EditorColorsScheme scheme = colorsManager.getGlobalScheme(); Style style = styledDocument.addStyle("active", null); StyleConstants.setFontFamily(style, scheme.getEditorFontName()); StyleConstants.setFontSize(style, scheme.getEditorFontSize()); styledDocument.setCharacterAttributes(0, document.getLength(), style, false); } public void addClickListener(ClickListener listener) { myClickListeners.add(listener); } private void fireClickEvent(VirtualFile file, int startPosition, int endPosition) { ClickEvent e = new ClickEvent(file, startPosition, endPosition); for (ClickListener listener : myClickListeners) { listener.referenceClicked(e); } } private String generateHTML(final RefEntity refEntity, final InspectionTool tool) { final StringBuffer buf = new StringBuffer(); if (refEntity instanceof RefElement) { final Runnable action = new Runnable() { @Override public void run() { tool.getComposer().compose(buf, refEntity); } }; ApplicationManager.getApplication().runReadAction(action); } else { tool.getComposer().compose(buf, refEntity); } uppercaseFirstLetter(buf); if (refEntity instanceof RefElement) { appendSuppressSection(buf); } insertHeaderFooter(buf); return buf.toString(); } @SuppressWarnings({"HardCodedStringLiteral"}) private static void insertHeaderFooter(final StringBuffer buf) { buf.insert(0, "<HTML><BODY>"); buf.append("</BODY></HTML>"); } private String generateHTML(final RefEntity refEntity, final CommonProblemDescriptor descriptor) { final StringBuffer buf = new StringBuffer(); final Runnable action = new Runnable() { @Override public void run() { InspectionTool tool = getTool(refEntity); tool.getComposer().compose(buf, refEntity, descriptor); } }; ApplicationManager.getApplication().runReadAction(action); uppercaseFirstLetter(buf); if (refEntity instanceof RefElement) { appendSuppressSection(buf); } insertHeaderFooter(buf); return buf.toString(); } private InspectionTool getTool(final RefEntity refEntity) { InspectionTool tool = getTool(); assert tool != null; final GlobalInspectionContextImpl manager = tool.getContext(); if (manager == null) return tool; if (refEntity instanceof RefElement) { PsiElement element = ((RefElement) refEntity).getElement(); if (element == null) return tool; final InspectionProfileWrapper profileWrapper = InspectionProjectProfileManagerImpl.getInstanceImpl(manager.getProject()) .getProfileWrapper(); if (profileWrapper == null) return tool; tool = profileWrapper.getInspectionTool(tool.getShortName(), element); } return tool; } private void appendSuppressSection(final StringBuffer buf) { final InspectionTool tool = getTool(); if (tool != null) { final HighlightDisplayKey key = HighlightDisplayKey.find(tool.getShortName()); if (key != null) { // dummy entry points final SuppressActionWrapper.SuppressTreeAction[] suppressActions = new SuppressActionWrapper( myView.getProject(), tool, myView.getTree().getSelectionPaths()) .getChildren(null); if (suppressActions.length > 0) { final List<AnAction> activeSuppressActions = new ArrayList<AnAction>(); for (SuppressActionWrapper.SuppressTreeAction suppressAction : suppressActions) { if (suppressAction.isAvailable()) { activeSuppressActions.add(suppressAction); } } if (!activeSuppressActions.isEmpty()) { int idx = 0; @NonNls final String br = "<br>"; buf.append(br); HTMLComposerImpl.appendHeading( buf, InspectionsBundle.message("inspection.export.results.suppress")); for (AnAction suppressAction : activeSuppressActions) { buf.append(br); if (idx == activeSuppressActions.size() - 1) { buf.append(br); } HTMLComposer.appendAfterHeaderIndention(buf); @NonNls final String href = "<a HREF=\"file://bred.txt#suppress:" + idx + "\">" + suppressAction.getTemplatePresentation().getText() + "</a>"; buf.append(href); idx++; } } } } } } private static void uppercaseFirstLetter(final StringBuffer buf) { if (buf.length() > 1) { char[] firstLetter = new char[1]; buf.getChars(0, 1, firstLetter, 0); buf.setCharAt(0, Character.toUpperCase(firstLetter[0])); } } @SuppressWarnings({"HardCodedStringLiteral"}) public void showEmpty() { myCurrentEntity = null; try { myHTMLViewer.read(new StringReader("<html><body></body></html>"), null); } catch (IOException e) { // can't be } } public void showDescription(InspectionTool tool) { if (tool.getShortName().length() == 0) { showEmpty(); return; } @NonNls StringBuffer page = new StringBuffer(); page.append("<table border='0' cellspacing='0' cellpadding='0' width='100%'>"); page.append("<tr><td colspan='2'>"); HTMLComposer.appendHeading( page, InspectionsBundle.message("inspection.tool.in.browser.id.title")); page.append("</td></tr>"); page.append("<tr><td width='37'></td>" + "<td>"); page.append(tool.getShortName()); page.append("</td></tr>"); page.append("<tr height='10'></tr>"); page.append("<tr><td colspan='2'>"); HTMLComposer.appendHeading( page, InspectionsBundle.message("inspection.tool.in.browser.description.title")); page.append("</td></tr>"); page.append("<tr><td width='37'></td>" + "<td>"); @NonNls final String underConstruction = "<b>" + UNDER_CONSTRUCTION + "</b></html>"; try { @NonNls String description = tool.loadDescription(); if (description == null) { description = underConstruction; } page.append(UIUtil.getHtmlBody(description)); page.append("</td></tr></table>"); myHTMLViewer.setText(XmlStringUtil.wrapInHtml(page)); setupStyle(); } finally { myCurrentEntity = null; } } @Nullable private InspectionTool getTool() { if (myView != null) { return myView.getTree().getSelectedTool(); } return null; } public void invokeLocalFix(int idx) { if (myView.getTree().getSelectionCount() != 1) return; final InspectionTreeNode node = (InspectionTreeNode) myView.getTree().getSelectionPath().getLastPathComponent(); if (node instanceof ProblemDescriptionNode) { final ProblemDescriptionNode problemNode = (ProblemDescriptionNode) node; final CommonProblemDescriptor descriptor = problemNode.getDescriptor(); final RefEntity element = problemNode.getElement(); invokeFix(element, descriptor, idx); } else if (node instanceof RefElementNode) { RefElementNode elementNode = (RefElementNode) node; RefEntity element = elementNode.getElement(); CommonProblemDescriptor descriptor = elementNode.getProblem(); if (descriptor != null) { invokeFix(element, descriptor, idx); } } } private void invokeFix( final RefEntity element, final CommonProblemDescriptor descriptor, final int idx) { final QuickFix[] fixes = descriptor.getFixes(); if (fixes != null && fixes.length > idx && fixes[idx] != null) { if (element instanceof RefElement) { PsiElement psiElement = ((RefElement) element).getElement(); if (psiElement != null && psiElement.isValid()) { if (!FileModificationService.getInstance().preparePsiElementForWrite(psiElement)) return; performFix(element, descriptor, idx, fixes[idx]); } } else { performFix(element, descriptor, idx, fixes[idx]); } } } private void performFix( final RefEntity element, final CommonProblemDescriptor descriptor, final int idx, final QuickFix fix) { final Runnable command = new Runnable() { @Override public void run() { ApplicationManager.getApplication() .runWriteAction( new Runnable() { @Override public void run() { final PsiModificationTracker tracker = PsiManager.getInstance(myView.getProject()).getModificationTracker(); final long startCount = tracker.getModificationCount(); CommandProcessor.getInstance() .markCurrentCommandAsGlobal(myView.getProject()); // CCE here means QuickFix was incorrectly inherited fix.applyFix(myView.getProject(), descriptor); if (startCount != tracker.getModificationCount()) { final DescriptorProviderInspection tool = ((DescriptorProviderInspection) myView.getTree().getSelectedTool()); if (tool != null) { tool.ignoreProblem(element, descriptor, idx); } myView.updateView(false); } } }); } }; CommandProcessor.getInstance() .executeCommand(myView.getProject(), command, fix.getName(), null); } }
public Browser(InspectionResultsView view) { super(new BorderLayout()); myView = view; myCurrentEntity = null; myCurrentDescriptor = null; myHTMLViewer = new JEditorPane( UIUtil.HTML_MIME, InspectionsBundle.message("inspection.offline.view.empty.browser.text")); myHTMLViewer.setEditable(false); myHyperLinkListener = new HyperlinkListener() { @Override public void hyperlinkUpdate(HyperlinkEvent e) { if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { JEditorPane pane = (JEditorPane) e.getSource(); if (e instanceof HTMLFrameHyperlinkEvent) { HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent) e; HTMLDocument doc = (HTMLDocument) pane.getDocument(); doc.processHTMLFrameHyperlinkEvent(evt); } else { try { URL url = e.getURL(); @NonNls String ref = url.getRef(); if (ref.startsWith("pos:")) { int delimeterPos = ref.indexOf(':', "pos:".length() + 1); String startPosition = ref.substring("pos:".length(), delimeterPos); String endPosition = ref.substring(delimeterPos + 1); Integer textStartOffset = new Integer(startPosition); Integer textEndOffset = new Integer(endPosition); String fileURL = url.toExternalForm(); fileURL = fileURL.substring(0, fileURL.indexOf('#')); VirtualFile vFile = VirtualFileManager.getInstance().findFileByUrl(fileURL); if (vFile != null) { fireClickEvent(vFile, textStartOffset.intValue(), textEndOffset.intValue()); } } else if (ref.startsWith("descr:")) { if (myCurrentDescriptor instanceof ProblemDescriptor) { PsiElement psiElement = ((ProblemDescriptor) myCurrentDescriptor).getPsiElement(); if (psiElement == null) return; VirtualFile vFile = psiElement.getContainingFile().getVirtualFile(); if (vFile != null) { TextRange range = ((ProblemDescriptorBase) myCurrentDescriptor).getTextRange(); fireClickEvent(vFile, range.getStartOffset(), range.getEndOffset()); } } } else if (ref.startsWith("invoke:")) { int actionNumber = Integer.parseInt(ref.substring("invoke:".length())); getTool() .getQuickFixes(new RefElement[] {(RefElement) myCurrentEntity})[ actionNumber] .doApplyFix(new RefElement[] {(RefElement) myCurrentEntity}, myView); } else if (ref.startsWith("invokelocal:")) { int actionNumber = Integer.parseInt(ref.substring("invokelocal:".length())); if (actionNumber > -1) { invokeLocalFix(actionNumber); } } else if (ref.startsWith("suppress:")) { final SuppressActionWrapper.SuppressTreeAction[] suppressTreeActions = new SuppressActionWrapper( myView.getProject(), getTool(), myView.getTree().getSelectionPaths()) .getChildren(null); final List<AnAction> activeActions = new ArrayList<AnAction>(); for (SuppressActionWrapper.SuppressTreeAction suppressTreeAction : suppressTreeActions) { if (suppressTreeAction.isAvailable()) activeActions.add(suppressTreeAction); } if (!activeActions.isEmpty()) { int actionNumber = Integer.parseInt(ref.substring("suppress:".length())); if (actionNumber > -1 && activeActions.size() > actionNumber) { activeActions.get(actionNumber).actionPerformed(null); } } } else { int offset = Integer.parseInt(ref); String fileURL = url.toExternalForm(); fileURL = fileURL.substring(0, fileURL.indexOf('#')); VirtualFile vFile = VirtualFileManager.getInstance().findFileByUrl(fileURL); if (vFile == null) { vFile = VfsUtil.findFileByURL(url); } if (vFile != null) { fireClickEvent(vFile, offset, offset); } } } catch (Throwable t) { // ??? } } } } }; myHTMLViewer.addHyperlinkListener(myHyperLinkListener); final JScrollPane pane = ScrollPaneFactory.createScrollPane(myHTMLViewer); pane.setBorder(null); add(pane, BorderLayout.CENTER); setupStyle(); }
public class CanBeFinalInspection extends GlobalJavaBatchInspectionTool { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.canBeFinal.CanBeFinalInspection"); public boolean REPORT_CLASSES; public boolean REPORT_METHODS; public boolean REPORT_FIELDS = true; public static final String DISPLAY_NAME = InspectionsBundle.message("inspection.can.be.final.display.name"); @NonNls public static final String SHORT_NAME = "CanBeFinal"; @NonNls private static final String QUICK_FIX_NAME = InspectionsBundle.message("inspection.can.be.final.accept.quickfix"); private class OptionsPanel extends JPanel { private final JCheckBox myReportClassesCheckbox; private final JCheckBox myReportMethodsCheckbox; private final JCheckBox myReportFieldsCheckbox; private OptionsPanel() { super(new GridBagLayout()); GridBagConstraints gc = new GridBagConstraints(); gc.weighty = 0; gc.weightx = 1; gc.fill = GridBagConstraints.HORIZONTAL; gc.anchor = GridBagConstraints.NORTHWEST; myReportClassesCheckbox = new JCheckBox(InspectionsBundle.message("inspection.can.be.final.option")); myReportClassesCheckbox.setSelected(REPORT_CLASSES); myReportClassesCheckbox .getModel() .addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { REPORT_CLASSES = myReportClassesCheckbox.isSelected(); } }); gc.gridy = 0; add(myReportClassesCheckbox, gc); myReportMethodsCheckbox = new JCheckBox(InspectionsBundle.message("inspection.can.be.final.option1")); myReportMethodsCheckbox.setSelected(REPORT_METHODS); myReportMethodsCheckbox .getModel() .addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { REPORT_METHODS = myReportMethodsCheckbox.isSelected(); } }); gc.gridy++; add(myReportMethodsCheckbox, gc); myReportFieldsCheckbox = new JCheckBox(InspectionsBundle.message("inspection.can.be.final.option2")); myReportFieldsCheckbox.setSelected(REPORT_FIELDS); myReportFieldsCheckbox .getModel() .addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { REPORT_FIELDS = myReportFieldsCheckbox.isSelected(); } }); gc.weighty = 1; gc.gridy++; add(myReportFieldsCheckbox, gc); } } public boolean isReportClasses() { return REPORT_CLASSES; } public boolean isReportMethods() { return REPORT_METHODS; } public boolean isReportFields() { return REPORT_FIELDS; } @Override public JComponent createOptionsPanel() { return new OptionsPanel(); } @Override @Nullable public RefGraphAnnotator getAnnotator(@NotNull final RefManager refManager) { return new CanBeFinalAnnotator(refManager); } @Override @Nullable public CommonProblemDescriptor[] checkElement( @NotNull final RefEntity refEntity, @NotNull final AnalysisScope scope, @NotNull final InspectionManager manager, @NotNull final GlobalInspectionContext globalContext, @NotNull final ProblemDescriptionsProcessor processor) { if (refEntity instanceof RefJavaElement) { final RefJavaElement refElement = (RefJavaElement) refEntity; if (refElement instanceof RefParameter) return null; if (!refElement.isReferenced()) return null; if (refElement.isSyntheticJSP()) return null; if (refElement.isFinal()) return null; if (!((RefElementImpl) refElement).checkFlag(CanBeFinalAnnotator.CAN_BE_FINAL_MASK)) return null; final PsiMember psiMember = (PsiMember) refElement.getElement(); if (psiMember == null || !CanBeFinalHandler.allowToBeFinal(psiMember)) return null; PsiIdentifier psiIdentifier = null; if (refElement instanceof RefClass) { RefClass refClass = (RefClass) refElement; if (refClass.isInterface() || refClass.isAnonymous() || refClass.isAbstract()) return null; if (!isReportClasses()) return null; psiIdentifier = ((PsiClass) psiMember).getNameIdentifier(); } else if (refElement instanceof RefMethod) { RefMethod refMethod = (RefMethod) refElement; if (refMethod.getOwnerClass().isFinal()) return null; if (!isReportMethods()) return null; psiIdentifier = ((PsiMethod) psiMember).getNameIdentifier(); } else if (refElement instanceof RefField) { if (!isReportFields()) return null; psiIdentifier = ((PsiField) psiMember).getNameIdentifier(); } if (psiIdentifier != null) { return new ProblemDescriptor[] { manager.createProblemDescriptor( psiIdentifier, InspectionsBundle.message("inspection.export.results.can.be.final.description"), new AcceptSuggested(globalContext.getRefManager()), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false) }; } } return null; } @Override protected boolean queryExternalUsagesRequests( @NotNull final RefManager manager, @NotNull final GlobalJavaInspectionContext globalContext, @NotNull final ProblemDescriptionsProcessor problemsProcessor) { for (RefElement entryPoint : globalContext.getEntryPointsManager(manager).getEntryPoints()) { problemsProcessor.ignoreElement(entryPoint); } manager.iterate( new RefJavaVisitor() { @Override public void visitElement(@NotNull RefEntity refEntity) { if (problemsProcessor.getDescriptions(refEntity) == null) return; refEntity.accept( new RefJavaVisitor() { @Override public void visitMethod(@NotNull final RefMethod refMethod) { if (!refMethod.isStatic() && !PsiModifier.PRIVATE.equals(refMethod.getAccessModifier()) && !(refMethod instanceof RefImplicitConstructor)) { globalContext.enqueueDerivedMethodsProcessor( refMethod, new GlobalJavaInspectionContext.DerivedMethodsProcessor() { @Override public boolean process(PsiMethod derivedMethod) { ((RefElementImpl) refMethod) .setFlag(false, CanBeFinalAnnotator.CAN_BE_FINAL_MASK); problemsProcessor.ignoreElement(refMethod); return false; } }); } } @Override public void visitClass(@NotNull final RefClass refClass) { if (!refClass.isAnonymous()) { globalContext.enqueueDerivedClassesProcessor( refClass, new GlobalJavaInspectionContext.DerivedClassesProcessor() { @Override public boolean process(PsiClass inheritor) { ((RefClassImpl) refClass) .setFlag(false, CanBeFinalAnnotator.CAN_BE_FINAL_MASK); problemsProcessor.ignoreElement(refClass); return false; } }); } } @Override public void visitField(@NotNull final RefField refField) { globalContext.enqueueFieldUsagesProcessor( refField, new GlobalJavaInspectionContext.UsagesProcessor() { @Override public boolean process(PsiReference psiReference) { PsiElement expression = psiReference.getElement(); if (expression instanceof PsiReferenceExpression && PsiUtil.isAccessedForWriting((PsiExpression) expression)) { ((RefFieldImpl) refField) .setFlag(false, CanBeFinalAnnotator.CAN_BE_FINAL_MASK); problemsProcessor.ignoreElement(refField); return false; } return true; } }); } }); } }); return false; } @Override @Nullable public QuickFix getQuickFix(final String hint) { return new AcceptSuggested(null); } @Override @NotNull public String getDisplayName() { return DISPLAY_NAME; } @Override @NotNull public String getGroupDisplayName() { return GroupNames.DECLARATION_REDUNDANCY; } @Override @NotNull public String getShortName() { return SHORT_NAME; } private static class AcceptSuggested implements LocalQuickFix { private final RefManager myManager; public AcceptSuggested(final RefManager manager) { myManager = manager; } @Override @NotNull public String getFamilyName() { return QUICK_FIX_NAME; } @Override public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { final PsiElement element = descriptor.getPsiElement(); final PsiModifierListOwner psiElement = PsiTreeUtil.getParentOfType(element, PsiModifierListOwner.class); if (psiElement != null) { RefJavaElement refElement = (RefJavaElement) (myManager != null ? myManager.getReference(psiElement) : null); try { if (psiElement instanceof PsiVariable) { ((PsiVariable) psiElement).normalizeDeclaration(); } final PsiModifierList modifierList = psiElement.getModifierList(); LOG.assertTrue(modifierList != null); modifierList.setModifierProperty(PsiModifier.FINAL, true); modifierList.setModifierProperty(PsiModifier.VOLATILE, false); } catch (IncorrectOperationException e) { LOG.error(e); } if (refElement != null) { RefJavaUtil.getInstance().setIsFinal(refElement, true); } } } } }
@Override @NotNull public String getName() { return InspectionsBundle.message("inspection.visibility.accept.quickfix"); }
public class VisibilityInspection extends GlobalJavaInspectionTool { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.visibility.VisibilityInspection"); public boolean SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS = true; public boolean SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES = true; public boolean SUGGEST_PRIVATE_FOR_INNERS = false; private static final String DISPLAY_NAME = InspectionsBundle.message("inspection.visibility.display.name"); @NonNls private static final String SHORT_NAME = "WeakerAccess"; private static final String CAN_BE_PRIVATE = InspectionsBundle.message("inspection.visibility.compose.suggestion", "private"); private static final String CAN_BE_PACKAGE_LOCAL = InspectionsBundle.message("inspection.visibility.compose.suggestion", "package local"); private static final String CAN_BE_PROTECTED = InspectionsBundle.message("inspection.visibility.compose.suggestion", "protected"); private class OptionsPanel extends JPanel { private final JCheckBox myPackageLocalForMembersCheckbox; private final JCheckBox myPrivateForInnersCheckbox; private final JCheckBox myPackageLocalForTopClassesCheckbox; private OptionsPanel() { super(new GridBagLayout()); GridBagConstraints gc = new GridBagConstraints(); gc.fill = GridBagConstraints.HORIZONTAL; gc.weightx = 1; gc.weighty = 0; gc.anchor = GridBagConstraints.NORTHWEST; myPackageLocalForMembersCheckbox = new JCheckBox(InspectionsBundle.message("inspection.visibility.option")); myPackageLocalForMembersCheckbox.setSelected(SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS); myPackageLocalForMembersCheckbox .getModel() .addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS = myPackageLocalForMembersCheckbox.isSelected(); } }); gc.gridy = 0; add(myPackageLocalForMembersCheckbox, gc); myPackageLocalForTopClassesCheckbox = new JCheckBox(InspectionsBundle.message("inspection.visibility.option1")); myPackageLocalForTopClassesCheckbox.setSelected(SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES); myPackageLocalForTopClassesCheckbox .getModel() .addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES = myPackageLocalForTopClassesCheckbox.isSelected(); } }); gc.gridy = 1; add(myPackageLocalForTopClassesCheckbox, gc); myPrivateForInnersCheckbox = new JCheckBox(InspectionsBundle.message("inspection.visibility.option2")); myPrivateForInnersCheckbox.setSelected(SUGGEST_PRIVATE_FOR_INNERS); myPrivateForInnersCheckbox .getModel() .addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { SUGGEST_PRIVATE_FOR_INNERS = myPrivateForInnersCheckbox.isSelected(); } }); gc.gridy = 2; gc.weighty = 1; add(myPrivateForInnersCheckbox, gc); } } @Override public JComponent createOptionsPanel() { return new OptionsPanel(); } @Override @NotNull public String getDisplayName() { return DISPLAY_NAME; } @Override @NotNull public String getGroupDisplayName() { return GroupNames.DECLARATION_REDUNDANCY; } @Override @NotNull public String getShortName() { return SHORT_NAME; } @Override @Nullable public CommonProblemDescriptor[] checkElement( @NotNull final RefEntity refEntity, @NotNull final AnalysisScope scope, @NotNull final InspectionManager manager, @NotNull final GlobalInspectionContext globalContext, @NotNull final ProblemDescriptionsProcessor processor) { if (refEntity instanceof RefJavaElement) { final RefJavaElement refElement = (RefJavaElement) refEntity; if (refElement instanceof RefParameter) return null; if (refElement.isSyntheticJSP()) return null; // ignore entry points. if (refElement.isEntry()) return null; // ignore implicit constructors. User should not be able to see them. if (refElement instanceof RefImplicitConstructor) return null; if (refElement instanceof RefField && ((RefField) refElement).getElement() instanceof PsiEnumConstant) return null; // ignore library override methods. if (refElement instanceof RefMethod) { RefMethod refMethod = (RefMethod) refElement; if (refMethod.isExternalOverride()) return null; if (refMethod.isEntry()) return null; } // ignore anonymous classes. They do not have access modifiers. if (refElement instanceof RefClass) { RefClass refClass = (RefClass) refElement; if (refClass.isAnonymous() || refClass.isEntry() || refClass.isTestCase() || refClass.isServlet() || refClass.isApplet() || refClass.isLocalClass()) return null; if (isTopLevelClass(refClass) && !SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES) return null; } // ignore unreferenced code. They could be a potential entry points. if (refElement.getInReferences().isEmpty()) return null; // ignore interface members. They always have public access modifier. if (refElement.getOwner() instanceof RefClass) { RefClass refClass = (RefClass) refElement.getOwner(); if (refClass.isInterface()) return null; } String access = getPossibleAccess(refElement); if (access != refElement.getAccessModifier() && access != null) { final PsiElement element = refElement.getElement(); final PsiElement nameIdentifier = element != null ? HighlightUsagesHandler.getNameIdentifier(element) : null; if (nameIdentifier != null) { return new ProblemDescriptor[] { manager.createProblemDescriptor( nameIdentifier, access.equals(PsiModifier.PRIVATE) ? CAN_BE_PRIVATE : access.equals(PsiModifier.PACKAGE_LOCAL) ? CAN_BE_PACKAGE_LOCAL : CAN_BE_PROTECTED, new AcceptSuggestedAccess(globalContext.getRefManager(), access), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false) }; } } } return null; } @Nullable @PsiModifier.ModifierConstant public String getPossibleAccess(@Nullable RefJavaElement refElement) { if (refElement == null) return null; String curAccess = refElement.getAccessModifier(); String weakestAccess = PsiModifier.PRIVATE; if (isTopLevelClass(refElement) || isCalledOnSubClasses(refElement)) { weakestAccess = PsiModifier.PACKAGE_LOCAL; } if (isAbstractMethod(refElement)) { weakestAccess = PsiModifier.PROTECTED; } if (curAccess == weakestAccess) return curAccess; while (true) { String weakerAccess = getWeakerAccess(curAccess, refElement); if (weakerAccess == null || RefJavaUtil.getInstance().compareAccess(weakerAccess, weakestAccess) < 0) break; if (isAccessible(refElement, weakerAccess)) { curAccess = weakerAccess; } else { break; } } return curAccess; } private static boolean isCalledOnSubClasses(RefElement refElement) { return refElement instanceof RefMethod && ((RefMethod) refElement).isCalledOnSubClass(); } private static boolean isAbstractMethod(RefElement refElement) { return refElement instanceof RefMethod && ((RefMethod) refElement).isAbstract(); } private static boolean isTopLevelClass(RefElement refElement) { return refElement instanceof RefClass && RefJavaUtil.getInstance().getTopLevelClass(refElement) == refElement; } @Nullable @PsiModifier.ModifierConstant private String getWeakerAccess( @PsiModifier.ModifierConstant String curAccess, RefElement refElement) { if (curAccess == PsiModifier.PUBLIC) { return isTopLevelClass(refElement) ? PsiModifier.PACKAGE_LOCAL : PsiModifier.PROTECTED; } if (curAccess == PsiModifier.PROTECTED) { return SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS ? PsiModifier.PACKAGE_LOCAL : PsiModifier.PRIVATE; } if (curAccess == PsiModifier.PACKAGE_LOCAL) { return PsiModifier.PRIVATE; } return null; } private boolean isAccessible( RefJavaElement to, @PsiModifier.ModifierConstant String accessModifier) { for (RefElement refElement : to.getInReferences()) { if (!isAccessibleFrom(refElement, to, accessModifier)) return false; } if (to instanceof RefMethod) { RefMethod refMethod = (RefMethod) to; if (refMethod.isAbstract() && (refMethod.getDerivedMethods().isEmpty() || refMethod.getAccessModifier() == PsiModifier.PRIVATE)) return false; for (RefMethod refOverride : refMethod.getDerivedMethods()) { if (!isAccessibleFrom(refOverride, to, accessModifier)) return false; } for (RefMethod refSuper : refMethod.getSuperMethods()) { if (RefJavaUtil.getInstance().compareAccess(refSuper.getAccessModifier(), accessModifier) > 0) return false; } } if (to instanceof RefClass) { RefClass refClass = (RefClass) to; for (RefClass subClass : refClass.getSubClasses()) { if (!isAccessibleFrom(subClass, to, accessModifier)) return false; } List children = refClass.getChildren(); if (children != null) { for (Object refElement : children) { if (!isAccessible((RefJavaElement) refElement, accessModifier)) return false; } } for (final RefElement refElement : refClass.getInTypeReferences()) { if (!isAccessibleFrom(refElement, refClass, accessModifier)) return false; } List<RefJavaElement> classExporters = ((RefClassImpl) refClass).getClassExporters(); if (classExporters != null) { for (RefJavaElement refExporter : classExporters) { if (getAccessLevel(accessModifier) < getAccessLevel(refExporter.getAccessModifier())) return false; } } } return true; } private static int getAccessLevel(@PsiModifier.ModifierConstant String access) { if (access == PsiModifier.PRIVATE) return 1; if (access == PsiModifier.PACKAGE_LOCAL) return 2; if (access == PsiModifier.PROTECTED) return 3; return 4; } private boolean isAccessibleFrom(RefElement from, RefJavaElement to, String accessModifier) { if (accessModifier == PsiModifier.PUBLIC) return true; final RefJavaUtil refUtil = RefJavaUtil.getInstance(); if (accessModifier == PsiModifier.PACKAGE_LOCAL) { return RefJavaUtil.getPackage(from) == RefJavaUtil.getPackage(to); } RefClass fromTopLevel = refUtil.getTopLevelClass(from); RefClass toTopLevel = refUtil.getTopLevelClass(to); RefClass fromOwner = refUtil.getOwnerClass(from); RefClass toOwner = refUtil.getOwnerClass(to); if (accessModifier == PsiModifier.PROTECTED) { if (SUGGEST_PRIVATE_FOR_INNERS) { return refUtil.isInheritor(fromTopLevel, toOwner) || fromOwner != null && refUtil.isInheritor(fromOwner, toTopLevel) || toOwner != null && refUtil.getOwnerClass(toOwner) == from; } return refUtil.isInheritor(fromTopLevel, toOwner); } if (accessModifier == PsiModifier.PRIVATE) { if (SUGGEST_PRIVATE_FOR_INNERS) { if (isInExtendsList(to, fromTopLevel.getElement().getExtendsList())) return false; if (isInExtendsList(to, fromTopLevel.getElement().getImplementsList())) return false; if (isInAnnotations(to, fromTopLevel)) return false; return fromTopLevel == toOwner || fromOwner == toTopLevel || toOwner != null && refUtil.getOwnerClass(toOwner) == from; } if (fromOwner != null && fromOwner.isStatic() && !to.isStatic() && refUtil.isInheritor(fromOwner, toOwner)) return false; if (fromTopLevel == toOwner) { if (from instanceof RefClass && to instanceof RefClass) { final PsiClass fromClass = ((RefClass) from).getElement(); LOG.assertTrue(fromClass != null); if (isInExtendsList(to, fromClass.getExtendsList())) return false; if (isInExtendsList(to, fromClass.getImplementsList())) return false; } return true; } } return false; } private static boolean isInAnnotations(final RefJavaElement to, final RefClass fromTopLevel) { final PsiModifierList modifierList = fromTopLevel.getElement().getModifierList(); if (modifierList == null) return false; final PsiElement toElement = to.getElement(); final boolean[] resolved = new boolean[] {false}; modifierList.accept( new JavaRecursiveElementWalkingVisitor() { @Override public void visitReferenceExpression(PsiReferenceExpression expression) { if (resolved[0]) return; super.visitReferenceExpression(expression); if (expression.resolve() == toElement) { resolved[0] = true; } } }); return resolved[0]; } private static boolean isInExtendsList( final RefJavaElement to, final PsiReferenceList extendsList) { if (extendsList != null) { final PsiJavaCodeReferenceElement[] referenceElements = extendsList.getReferenceElements(); for (PsiJavaCodeReferenceElement referenceElement : referenceElements) { final PsiReferenceParameterList parameterList = referenceElement.getParameterList(); if (parameterList != null) { for (PsiType type : parameterList.getTypeArguments()) { if (extendsList .getManager() .areElementsEquivalent(PsiUtil.resolveClassInType(type), to.getElement())) { return true; } } } } } return false; } @Override protected boolean queryExternalUsagesRequests( @NotNull final RefManager manager, @NotNull final GlobalJavaInspectionContext globalContext, @NotNull final ProblemDescriptionsProcessor processor) { final EntryPointsManager entryPointsManager = globalContext.getEntryPointsManager(manager); for (RefElement entryPoint : entryPointsManager.getEntryPoints()) { ignoreElement(processor, entryPoint); } ExtensionPoint<VisibilityExtension> point = Extensions.getRootArea().getExtensionPoint(ExtensionPoints.VISIBLITY_TOOL); for (VisibilityExtension addin : point.getExtensions()) { addin.fillIgnoreList(manager, processor); } manager.iterate( new RefJavaVisitor() { @Override public void visitElement(@NotNull final RefEntity refEntity) { if (!(refEntity instanceof RefElement)) return; if (processor.getDescriptions(refEntity) == null) return; refEntity.accept( new RefJavaVisitor() { @Override public void visitField(@NotNull final RefField refField) { if (refField.getAccessModifier() != PsiModifier.PRIVATE) { globalContext.enqueueFieldUsagesProcessor( refField, new GlobalJavaInspectionContext.UsagesProcessor() { @Override public boolean process(PsiReference psiReference) { ignoreElement(processor, refField); return false; } }); } } @Override public void visitMethod(@NotNull final RefMethod refMethod) { if (!refMethod.isExternalOverride() && refMethod.getAccessModifier() != PsiModifier.PRIVATE && !(refMethod instanceof RefImplicitConstructor)) { globalContext.enqueueDerivedMethodsProcessor( refMethod, new GlobalJavaInspectionContext.DerivedMethodsProcessor() { @Override public boolean process(PsiMethod derivedMethod) { ignoreElement(processor, refMethod); return false; } }); globalContext.enqueueMethodUsagesProcessor( refMethod, new GlobalJavaInspectionContext.UsagesProcessor() { @Override public boolean process(PsiReference psiReference) { ignoreElement(processor, refMethod); return false; } }); if (entryPointsManager.isAddNonJavaEntries()) { final RefClass ownerClass = refMethod.getOwnerClass(); if (refMethod.isConstructor() && ownerClass.getDefaultConstructor() != null) { String qualifiedName = ownerClass.getElement().getQualifiedName(); if (qualifiedName != null) { final Project project = manager.getProject(); PsiSearchHelper.SERVICE .getInstance(project) .processUsagesInNonJavaFiles( qualifiedName, new PsiNonJavaFileReferenceProcessor() { @Override public boolean process( PsiFile file, int startOffset, int endOffset) { entryPointsManager.addEntryPoint(refMethod, false); ignoreElement(processor, refMethod); return false; } }, GlobalSearchScope.projectScope(project)); } } } } } @Override public void visitClass(@NotNull final RefClass refClass) { if (!refClass.isAnonymous()) { globalContext.enqueueDerivedClassesProcessor( refClass, new GlobalJavaInspectionContext.DerivedClassesProcessor() { @Override public boolean process(PsiClass inheritor) { ignoreElement(processor, refClass); return false; } }); globalContext.enqueueClassUsagesProcessor( refClass, new GlobalJavaInspectionContext.UsagesProcessor() { @Override public boolean process(PsiReference psiReference) { ignoreElement(processor, refClass); return false; } }); } } }); } }); return false; } private static void ignoreElement( @NotNull ProblemDescriptionsProcessor processor, @NotNull RefEntity refElement) { processor.ignoreElement(refElement); if (refElement instanceof RefClass) { RefClass refClass = (RefClass) refElement; RefMethod defaultConstructor = refClass.getDefaultConstructor(); if (defaultConstructor != null) { processor.ignoreElement(defaultConstructor); return; } } RefEntity owner = refElement.getOwner(); if (owner instanceof RefElement) { processor.ignoreElement(owner); } } @Override public void compose( @NotNull final StringBuffer buf, @NotNull final RefEntity refEntity, @NotNull final HTMLComposer composer) { composer.appendElementInReferences(buf, (RefElement) refEntity); } @Override @Nullable public QuickFix getQuickFix(final String hint) { return new AcceptSuggestedAccess(null, hint); } @Override @Nullable public String getHint(@NotNull final QuickFix fix) { return ((AcceptSuggestedAccess) fix).getHint(); } private static class AcceptSuggestedAccess implements LocalQuickFix { private final RefManager myManager; @PsiModifier.ModifierConstant private final String myHint; private AcceptSuggestedAccess( final RefManager manager, @PsiModifier.ModifierConstant String hint) { myManager = manager; myHint = hint; } @Override @NotNull public String getName() { return InspectionsBundle.message("inspection.visibility.accept.quickfix"); } @Override @NotNull public String getFamilyName() { return getName(); } @Override public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { if (!FileModificationService.getInstance() .preparePsiElementForWrite(descriptor.getPsiElement())) return; final PsiModifierListOwner element = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiModifierListOwner.class); if (element != null) { RefElement refElement = null; if (myManager != null) { refElement = myManager.getReference(element); } try { if (element instanceof PsiVariable) { ((PsiVariable) element).normalizeDeclaration(); } PsiModifierList list = element.getModifierList(); LOG.assertTrue(list != null); if (element instanceof PsiMethod) { PsiMethod psiMethod = (PsiMethod) element; PsiClass containingClass = psiMethod.getContainingClass(); if (containingClass != null && containingClass.getParent() instanceof PsiFile && myHint == PsiModifier.PRIVATE && list.hasModifierProperty(PsiModifier.FINAL)) { list.setModifierProperty(PsiModifier.FINAL, false); } } list.setModifierProperty(myHint, true); if (refElement instanceof RefJavaElement) { RefJavaUtil.getInstance().setAccessModifier((RefJavaElement) refElement, myHint); } } catch (IncorrectOperationException e) { LOG.error(e); } } } public String getHint() { return myHint; } } }
@NotNull public String getName() { // The test (see the TestThisPlugin class) uses this string to identify the quick fix action. return InspectionsBundle.message("inspection.comparing.references.use.quickfix"); }
/** @author max */ public class ComparingReferencesInspection extends BaseJavaLocalInspectionTool { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ComparingReferencesInspection"); private final LocalQuickFix myQuickFix = new MyQuickFix(); @SuppressWarnings({"WeakerAccess"}) @NonNls public String CHECKED_CLASSES = "java.lang.String;java.util.Date"; @NonNls private static final String DESCRIPTION_TEMPLATE = InspectionsBundle.message("inspection.comparing.references.problem.descriptor"); @NotNull public String getDisplayName() { return "'==' or '!=' instead of 'equals()'"; } @NotNull public String getGroupDisplayName() { return GroupNames.BUGS_GROUP_NAME; } @NotNull public String getShortName() { return "ComparingReferences"; } private boolean isCheckedType(PsiType type) { if (!(type instanceof PsiClassType)) return false; StringTokenizer tokenizer = new StringTokenizer(CHECKED_CLASSES, ";"); while (tokenizer.hasMoreTokens()) { String className = tokenizer.nextToken(); if (type.equalsToText(className)) return true; } return false; } @NotNull @Override public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) { return new JavaElementVisitor() { @Override public void visitReferenceExpression(PsiReferenceExpression psiReferenceExpression) {} @Override public void visitBinaryExpression(PsiBinaryExpression expression) { super.visitBinaryExpression(expression); IElementType opSign = expression.getOperationSign().getTokenType(); if (opSign == JavaTokenType.EQEQ || opSign == JavaTokenType.NE) { PsiExpression lOperand = expression.getLOperand(); PsiExpression rOperand = expression.getROperand(); if (rOperand == null || isNullLiteral(lOperand) || isNullLiteral(rOperand)) return; PsiType lType = lOperand.getType(); PsiType rType = rOperand.getType(); if (isCheckedType(lType) || isCheckedType(rType)) { holder.registerProblem(expression, DESCRIPTION_TEMPLATE, myQuickFix); } } } }; } private static boolean isNullLiteral(PsiExpression expr) { return expr instanceof PsiLiteralExpression && "null".equals(expr.getText()); } private static class MyQuickFix implements LocalQuickFix { @NotNull public String getName() { // The test (see the TestThisPlugin class) uses this string to identify the quick fix action. return InspectionsBundle.message("inspection.comparing.references.use.quickfix"); } public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { try { PsiBinaryExpression binaryExpression = (PsiBinaryExpression) descriptor.getPsiElement(); IElementType opSign = binaryExpression.getOperationSign().getTokenType(); PsiExpression lExpr = binaryExpression.getLOperand(); PsiExpression rExpr = binaryExpression.getROperand(); if (rExpr == null) return; PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory(); PsiMethodCallExpression equalsCall = (PsiMethodCallExpression) factory.createExpressionFromText("a.equals(b)", null); equalsCall.getMethodExpression().getQualifierExpression().replace(lExpr); equalsCall.getArgumentList().getExpressions()[0].replace(rExpr); PsiExpression result = (PsiExpression) binaryExpression.replace(equalsCall); if (opSign == JavaTokenType.NE) { PsiPrefixExpression negation = (PsiPrefixExpression) factory.createExpressionFromText("!a", null); negation.getOperand().replace(result); result.replace(negation); } } catch (IncorrectOperationException e) { LOG.error(e); } } @NotNull public String getFamilyName() { return getName(); } } public JComponent createOptionsPanel() { JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT)); final JTextField checkedClasses = new JTextField(CHECKED_CLASSES); checkedClasses .getDocument() .addDocumentListener( new DocumentAdapter() { public void textChanged(DocumentEvent event) { CHECKED_CLASSES = checkedClasses.getText(); } }); panel.add(checkedClasses); return panel; } public boolean isEnabledByDefault() { return true; } }
private OptionsPanel() { super(new GridBagLayout()); GridBagConstraints gc = new GridBagConstraints(); gc.weighty = 0; gc.weightx = 1; gc.fill = GridBagConstraints.HORIZONTAL; gc.anchor = GridBagConstraints.NORTHWEST; mySuggestNullables = new JCheckBox(InspectionsBundle.message("inspection.data.flow.nullable.quickfix.option")); mySuggestNullables.setSelected(SUGGEST_NULLABLE_ANNOTATIONS); mySuggestNullables .getModel() .addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { SUGGEST_NULLABLE_ANNOTATIONS = mySuggestNullables.isSelected(); } }); myDontReportTrueAsserts = new JCheckBox(InspectionsBundle.message("inspection.data.flow.true.asserts.option")); myDontReportTrueAsserts.setSelected(DONT_REPORT_TRUE_ASSERT_STATEMENTS); myDontReportTrueAsserts .getModel() .addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { DONT_REPORT_TRUE_ASSERT_STATEMENTS = myDontReportTrueAsserts.isSelected(); } }); myIgnoreAssertions = new JCheckBox("Ignore assert statements"); myIgnoreAssertions.setSelected(IGNORE_ASSERT_STATEMENTS); myIgnoreAssertions .getModel() .addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { IGNORE_ASSERT_STATEMENTS = myIgnoreAssertions.isSelected(); } }); myReportConstantReferences = new JCheckBox("Warn when reading a value guaranteed to be constant"); myReportConstantReferences.setSelected(REPORT_CONSTANT_REFERENCE_VALUES); myReportConstantReferences .getModel() .addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { REPORT_CONSTANT_REFERENCE_VALUES = myReportConstantReferences.isSelected(); } }); myTreatUnknownMembersAsNullable = new JCheckBox("Treat non-annotated members and parameters as @Nullable"); myTreatUnknownMembersAsNullable.setSelected(TREAT_UNKNOWN_MEMBERS_AS_NULLABLE); myTreatUnknownMembersAsNullable .getModel() .addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { TREAT_UNKNOWN_MEMBERS_AS_NULLABLE = myTreatUnknownMembersAsNullable.isSelected(); } }); gc.insets = new Insets(0, 0, 0, 0); gc.gridy = 0; add(mySuggestNullables, gc); final JButton configureAnnotations = new JButton(InspectionsBundle.message("configure.annotations.option")); configureAnnotations.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Project project = CommonDataKeys.PROJECT.getData( DataManager.getInstance().getDataContext(OptionsPanel.this)); if (project == null) project = ProjectManager.getInstance().getDefaultProject(); final NullableNotNullDialog dialog = new NullableNotNullDialog(project); dialog.show(); } }); gc.gridy++; gc.fill = GridBagConstraints.NONE; gc.insets.left = 20; gc.insets.bottom = 15; add(configureAnnotations, gc); gc.fill = GridBagConstraints.HORIZONTAL; gc.weighty = 1; gc.insets.left = 0; gc.gridy++; add(myDontReportTrueAsserts, gc); gc.gridy++; add(myIgnoreAssertions, gc); gc.gridy++; add(myReportConstantReferences, gc); gc.gridy++; add(myTreatUnknownMembersAsNullable, gc); }