/******************************************************************************* * Copyright (c) 2011 Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is made available under the terms of the * Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.common.ui.marker; import java.net.MalformedURLException; import java.net.URL; import java.util.Set; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.jdt.core.IAnnotatable; import org.eclipse.jdt.core.IAnnotation; import org.eclipse.jdt.core.IBuffer; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.ILocalVariable; import org.eclipse.jdt.core.IMemberValuePair; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.ISourceReference; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.BodyDeclaration; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.refactoring.CompilationUnitChange; import org.eclipse.jdt.internal.core.JavaElement; import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.ImageRegistry; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.contentassist.IContextInformation; import org.eclipse.jpt.common.core.internal.utility.jdt.ASTTools; import org.eclipse.ltk.core.refactoring.TextChange; import org.eclipse.ltk.core.refactoring.TextFileChange; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Shell; import org.eclipse.text.edits.InsertEdit; import org.eclipse.text.edits.ReplaceEdit; import org.eclipse.ui.IMarkerResolution2; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import org.jboss.tools.common.EclipseUtil; import org.jboss.tools.common.preferences.SeverityPreferences; import org.jboss.tools.common.refactoring.MarkerResolutionUtils; import org.jboss.tools.common.ui.CommonUIMessages; import org.jboss.tools.common.ui.CommonUIPlugin; import org.jboss.tools.common.validation.WarningNameManager; import org.osgi.service.prefs.BackingStoreException; /** * @author Daniel Azarov */ public class AddSuppressWarningsMarkerResolution implements IMarkerResolution2, IJavaCompletionProposal { public static final String SUPPRESS_WARNINGS_ANNOTATION = "SuppressWarnings"; public static final String SPACE = " "; //$NON-NLS-1$ public static final String DOT = "."; //$NON-NLS-1$ public static final String AT = "@"; //$NON-NLS-1$ private static final String PROBLEM_ID = JavaCore.COMPILER_PB_UNHANDLED_WARNING_TOKEN; private SP preferences = new SP(); private IFile file; private IAnnotatable element; private String preferenceKey; private String label; private String description; private ICompilationUnit cu; public AddSuppressWarningsMarkerResolution(IFile file, IJavaElement element, String preferenceKey){ this.file = file; this.element = getAnnatatableElement(element); String[] names = WarningNameManager.getInstance().getWarningNames(preferenceKey); if(names != null && names.length > 0){ this.preferenceKey = names[0]; }else{ this.preferenceKey = null; } label = NLS.bind(CommonUIMessages.ADD_SUPPRESS_WARNINGS_TITLE, this.preferenceKey, element.getElementName()); if(element instanceof IMethod){ label += "()"; } description = getPreview(); } public AddSuppressWarningsMarkerResolution(IFile file, IJavaElement element, String preferenceKey, ICompilationUnit compilationUnit){ this(file, element, preferenceKey); this.cu = compilationUnit; description = getPreview(); } private String getPreview(){ TextChange previewChange = getPreviewChange(); try { return MarkerResolutionUtils.getPreview(previewChange); } catch (CoreException e) { CommonUIPlugin.getDefault().logError(e); } return label; } private IAnnotatable getAnnatatableElement(IJavaElement element){ IJavaElement elem = element; while(elem != null){ if(element instanceof IAnnotatable){ return (IAnnotatable) element; } elem = elem.getParent(); } return null; } @Override public String getLabel() { return label; } private TextChange getPreviewChange(){ if(element != null && preferenceKey != null){ try { ICompilationUnit original = (cu != null) ? cu : EclipseUtil.getCompilationUnit(file); if(original == null) { return null; } ICompilationUnit compilationUnit = original.getWorkingCopy(new NullProgressMonitor()); TextChange change = getChange(compilationUnit); compilationUnit.discardWorkingCopy(); return change; } catch (JavaModelException e) { CommonUIPlugin.getDefault().logError(e); } } return null; } private CompilationUnitChange getChange(ICompilationUnit compilationUnit) throws JavaModelException{ CompilationUnit cuNode = ASTTools.buildASTRoot(compilationUnit); IJavaElement workingCopyElement = findWorkingCopy(compilationUnit, (IJavaElement)element); ASTNode elementNode = null; if(workingCopyElement instanceof JavaElement){ elementNode = ((JavaElement) workingCopyElement).findNode(cuNode); } IAnnotation annotation = findAnnotation(workingCopyElement); CompilationUnitChange change = null; if(annotation != null){ change = updateAnnotation(SUPPRESS_WARNINGS_ANNOTATION, preferenceKey, compilationUnit, annotation); }else{ change = addAnnotation(SUPPRESS_WARNINGS_ANNOTATION+"(\""+preferenceKey+"\")", compilationUnit, workingCopyElement, elementNode); } return change; } @Override public void run(IMarker marker) { ICompilationUnit original = EclipseUtil.getCompilationUnit(file); if(original != null) { do_run(original, false); } } private void do_run(ICompilationUnit original, boolean leaveDirty){ if(element != null && preferenceKey != null && original != null){ disablePreference(); try { ICompilationUnit compilationUnit = original.getWorkingCopy(new NullProgressMonitor()); CompilationUnitChange change = getChange(compilationUnit); if(change != null){ if(leaveDirty){ change.setSaveMode(TextFileChange.LEAVE_DIRTY); } change.perform(new NullProgressMonitor()); original.reconcile(ICompilationUnit.NO_AST, false, null, new NullProgressMonitor()); } compilationUnit.discardWorkingCopy(); } catch (JavaModelException e) { CommonUIPlugin.getDefault().logError(e); } catch (CoreException e) { CommonUIPlugin.getDefault().logError(e); } } } private IAnnotation findAnnotation(IJavaElement workingCopyElement) throws JavaModelException{ IAnnotation annotation = ((IAnnotatable)workingCopyElement).getAnnotation(SUPPRESS_WARNINGS_ANNOTATION); if(annotation != null && annotation.exists()){ return annotation; } return null; } public static String getShortName(String qualifiedName){ int lastDot = qualifiedName.lastIndexOf(DOT); String name; if(lastDot < 0) name = qualifiedName; else name = qualifiedName.substring(lastDot+1); return name; } private void disablePreference(){ String value = preferences.getProjectPreference(file.getProject(), PROBLEM_ID); if(!SeverityPreferences.IGNORE.equals(value)){ IEclipsePreferences projectPreferences = preferences.getProjectPreferences(file.getProject()); String projectValue = null; if(projectPreferences != null){ projectValue = projectPreferences.get(PROBLEM_ID, null); } if(projectValue != null){ MessageDialog dialog = new MessageDialog(getShell(), label, null, CommonUIMessages.ADD_SUPPRESS_WARNINGS_MESSAGE+ CommonUIMessages.ADD_SUPPRESS_WARNINGS_QUESTION1, MessageDialog.QUESTION_WITH_CANCEL, new String[]{CommonUIMessages.ADD_SUPPRESS_WARNINGS_CANCEL, CommonUIMessages.ADD_SUPPRESS_WARNINGS_DISABLE}, 0); int result = dialog.open(); if(result == 1){ IEclipsePreferences ePrefs = preferences.getProjectPreferences(file.getProject()); ePrefs.put(PROBLEM_ID, SeverityPreferences.IGNORE); try { ePrefs.flush(); } catch (BackingStoreException e) { CommonUIPlugin.getDefault().logError(e); } } }else{ MessageDialog dialog = new MessageDialog(getShell(), label, null, CommonUIMessages.ADD_SUPPRESS_WARNINGS_MESSAGE+ NLS.bind(CommonUIMessages.ADD_SUPPRESS_WARNINGS_QUESTION2, file.getProject().getName()), MessageDialog.QUESTION_WITH_CANCEL, new String[]{CommonUIMessages.ADD_SUPPRESS_WARNINGS_CANCEL, CommonUIMessages.ADD_SUPPRESS_WARNINGS_WORKSPACE, CommonUIMessages.ADD_SUPPRESS_WARNINGS_PROJECT}, 0); int result = dialog.open(); if(result == 1){ IEclipsePreferences ePrefs = preferences.getInstancePreferences(); ePrefs.put(PROBLEM_ID, SeverityPreferences.IGNORE); try { ePrefs.flush(); } catch (BackingStoreException e) { CommonUIPlugin.getDefault().logError(e); } }else if(result == 2){ IEclipsePreferences ePrefs = preferences.getProjectPreferences(file.getProject()); ePrefs.put(PROBLEM_ID, SeverityPreferences.IGNORE); try { ePrefs.flush(); } catch (BackingStoreException e) { CommonUIPlugin.getDefault().logError(e); } } } } } private static Shell getShell() { IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); if (window == null) { IWorkbenchWindow[] windows = PlatformUI.getWorkbench().getWorkbenchWindows(); if (windows.length > 0) { return windows[0].getShell(); } } else { return window.getShell(); } return null; } @Override public String getDescription() { return description; } @Override public Image getImage() { String key = "ADD_ANNOTATION"; ImageRegistry registry = CommonUIPlugin.getDefault().getImageRegistry(); Image image = registry.get(key); if (image == null) { try { image = ImageDescriptor.createFromURL( new URL(CommonUIPlugin.getDefault().getBundle() .getEntry("/"), "icons/add_annotation.png")).createImage(); registry.put(key, image); } catch (MalformedURLException e) { CommonUIPlugin.getDefault().logError(e); } } return image; } private CompilationUnitChange updateAnnotation(String name, String parameter, ICompilationUnit compilationUnit, IAnnotation annotation) throws JavaModelException{ String str = AT+name; str += "({"; for(IMemberValuePair pair : annotation.getMemberValuePairs()){ if(pair.getValueKind() == IMemberValuePair.K_STRING){ Object value = pair.getValue(); if(value instanceof String){ if(value.toString().equals(parameter)){ return null; } str += "\""+value+"\", "; }else if(value instanceof Object[]){ Object[] array = (Object[])value; for(Object a : array){ if(a instanceof String){ if(a.toString().equals(parameter)){ return null; } str += "\""+a+"\", "; } } } } else if(pair.getValueKind() == IMemberValuePair.K_QUALIFIED_NAME || pair.getValueKind() == IMemberValuePair.K_SIMPLE_NAME){ Object value = pair.getValue(); if(value instanceof String){ str += value+", "; }else if(value instanceof Object[]){ Object[] array = (Object[])value; for(Object a : array){ if(a instanceof String){ str += a+", "; } } } } } str += "\""+parameter+"\""; str += "})"; CompilationUnitChange change = new CompilationUnitChange("", compilationUnit); ReplaceEdit edit = new ReplaceEdit(annotation.getSourceRange().getOffset(), annotation.getSourceRange().getLength(), str); change.setEdit(edit); return change; } private CompilationUnitChange addAnnotation(String name, ICompilationUnit compilationUnit, IJavaElement element, ASTNode node) throws JavaModelException{ if(!(element instanceof ISourceReference)) return null; ISourceReference workingCopySourceReference = (ISourceReference) element; IBuffer buffer = compilationUnit.getBuffer(); int position = workingCopySourceReference.getSourceRange().getOffset(); if(node != null){ position = node.getStartPosition(); if(node instanceof BodyDeclaration && ((BodyDeclaration)node).getJavadoc() != null){ position += ((BodyDeclaration)node).getJavadoc().getLength(); char c = buffer.getChar(position); while((c == '\r' || c == '\n') && position < buffer.getLength()-2 ){ position++; c = buffer.getChar(position); } } while(position < buffer.getLength()-1){ char c = buffer.getChar(position); if(c != '\r' && c != '\n' && c != ' ' && c != '\t'){ break; } position++; } } String str = AT+name; if(!(workingCopySourceReference instanceof ILocalVariable)){ str += compilationUnit.findRecommendedLineSeparator(); int index = position; while(index >= 0){ char c = buffer.getChar(index); if(c == '\r' || c == '\n') break; index--; } index++; if(index < position){ String spaces = buffer.getText(index, position-index); str += spaces; } }else{ str += SPACE; } CompilationUnitChange change = new CompilationUnitChange("", compilationUnit); InsertEdit edit = new InsertEdit(position, str); change.setEdit(edit); return change; } @SuppressWarnings("unchecked") private static <T extends IJavaElement> T findWorkingCopy(ICompilationUnit compilationUnit, T element) throws JavaModelException{ if(element instanceof IAnnotation){ IJavaElement parent = findWorkingCopy(compilationUnit, element.getParent()); if(parent instanceof IAnnotatable){ for(IAnnotation a : ((IAnnotatable)parent).getAnnotations()){ if(a.getElementName().equals(element.getElementName())) return (T)a; } } }else if(element instanceof ILocalVariable && ((ILocalVariable) element).isParameter()){ IJavaElement parent = findWorkingCopy(compilationUnit, element.getParent()); if(parent instanceof IMethod){ for(ILocalVariable parameter : ((IMethod)parent).getParameters()){ if(parameter.getElementName().equals(element.getElementName()) && parameter.getTypeSignature().equals(((ILocalVariable)element).getTypeSignature())) return (T)parameter; } } }else{ IJavaElement[] elements = compilationUnit.findElements(element); if(elements != null){ for(IJavaElement e : elements){ if(e.getClass().equals(element.getClass())) return (T)e; } } } return null; } static class SP extends SeverityPreferences{ @Override protected Set<String> getSeverityOptionNames() { return null; } @Override protected String createSeverityOption(String shortName) { return null; } @Override protected String getPluginId() { return JavaCore.PLUGIN_ID; } } @Override public void apply(IDocument document) { do_run(cu, true); } @Override public Point getSelection(IDocument document) { return null; } @Override public String getAdditionalProposalInfo() { return description; } @Override public String getDisplayString() { return label; } @Override public IContextInformation getContextInformation() { return null; } @Override public int getRelevance() { return 100; } }