1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Eclipse Public License, Version 1.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.eclipse.org/org/documents/epl-v10.php 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.ide.eclipse.adt.internal.lint; 17 18 19 import com.android.ide.eclipse.adt.AdtPlugin; 20 import com.android.tools.lint.checks.AccessibilityDetector; 21 import com.android.tools.lint.checks.DetectMissingPrefix; 22 import com.android.tools.lint.checks.HardcodedValuesDetector; 23 import com.android.tools.lint.checks.InefficientWeightDetector; 24 import com.android.tools.lint.checks.ObsoleteLayoutParamsDetector; 25 import com.android.tools.lint.checks.PxUsageDetector; 26 import com.android.tools.lint.checks.ScrollViewChildDetector; 27 import com.android.tools.lint.checks.SecurityDetector; 28 import com.android.tools.lint.checks.TextFieldDetector; 29 import com.android.tools.lint.checks.TypographyDetector; 30 import com.android.tools.lint.checks.UseCompoundDrawableDetector; 31 import com.android.tools.lint.checks.UselessViewDetector; 32 import com.android.tools.lint.detector.api.Issue; 33 34 import org.eclipse.core.resources.IMarker; 35 import org.eclipse.core.runtime.CoreException; 36 import org.eclipse.jface.text.IDocument; 37 import org.eclipse.jface.text.contentassist.ICompletionProposal; 38 import org.eclipse.jface.text.contentassist.IContextInformation; 39 import org.eclipse.swt.graphics.Image; 40 import org.eclipse.swt.graphics.Point; 41 import org.eclipse.ui.ISharedImages; 42 import org.eclipse.ui.PartInitException; 43 import org.eclipse.ui.PlatformUI; 44 45 import java.lang.reflect.Constructor; 46 import java.util.HashMap; 47 import java.util.Map; 48 49 abstract class LintFix implements ICompletionProposal { 50 protected final IMarker mMarker; 51 protected final String mId; 52 LintFix(String id, IMarker marker)53 protected LintFix(String id, IMarker marker) { 54 mId = id; 55 mMarker = marker; 56 } 57 58 /** 59 * Returns true if this fix needs focus (which means that when the fix is 60 * performed from for example a {@link LintListDialog}'s Fix button) the 61 * editor needs to be given focus. 62 * 63 * @return true if this fix needs focus after being applied 64 */ needsFocus()65 public boolean needsFocus() { 66 return true; 67 } 68 69 /** 70 * Returns true if this fix can be performed along side other fixes 71 * 72 * @return true if this fix can be performed in a bulk operation with other 73 * fixes 74 */ isBulkCapable()75 public boolean isBulkCapable() { 76 return false; 77 } 78 79 /** 80 * Returns true if this fix can be cancelled once it's invoked. This is the case 81 * for fixes which shows a confirmation dialog (such as the Extract String etc). 82 * This will be used to determine whether the marker can be deleted immediately 83 * (for non-cancelable fixes) or if it should be left alone and detected fix 84 * on the next save. 85 * 86 * @return true if the 87 */ isCancelable()88 public boolean isCancelable() { 89 return true; 90 } 91 92 // ---- Implements ICompletionProposal ---- 93 94 @Override getDisplayString()95 public String getDisplayString() { 96 return null; 97 } 98 99 @Override getAdditionalProposalInfo()100 public String getAdditionalProposalInfo() { 101 Issue issue = EclipseLintClient.getRegistry().getIssue(mId); 102 if (issue != null) { 103 return issue.getExplanation().replace("\n", "<br>"); //$NON-NLS-1$ //$NON-NLS-2$ 104 } 105 106 return null; 107 } 108 deleteMarker()109 public void deleteMarker() { 110 try { 111 mMarker.delete(); 112 } catch (PartInitException e) { 113 AdtPlugin.log(e, null); 114 } catch (CoreException e) { 115 AdtPlugin.log(e, null); 116 } 117 } 118 119 @Override getSelection(IDocument document)120 public Point getSelection(IDocument document) { 121 return null; 122 } 123 124 @Override getImage()125 public Image getImage() { 126 ISharedImages sharedImages = PlatformUI.getWorkbench().getSharedImages(); 127 return sharedImages.getImage(ISharedImages.IMG_OBJS_WARN_TSK); 128 } 129 130 @Override getContextInformation()131 public IContextInformation getContextInformation() { 132 return null; 133 } 134 135 // --- Access to available fixes --- 136 137 private static final Map<String, Class<? extends LintFix>> sFixes = 138 new HashMap<String, Class<? extends LintFix>>(); 139 // Keep this map in sync with BuiltinIssueRegistry's hasAutoFix() data 140 static { InefficientWeightDetector.INEFFICIENT_WEIGHT.getId()141 sFixes.put(InefficientWeightDetector.INEFFICIENT_WEIGHT.getId(), 142 LinearLayoutWeightFix.class); AccessibilityDetector.ISSUE.getId()143 sFixes.put(AccessibilityDetector.ISSUE.getId(), SetAttributeFix.class); InefficientWeightDetector.BASELINE_WEIGHTS.getId()144 sFixes.put(InefficientWeightDetector.BASELINE_WEIGHTS.getId(), SetAttributeFix.class); HardcodedValuesDetector.ISSUE.getId()145 sFixes.put(HardcodedValuesDetector.ISSUE.getId(), ExtractStringFix.class); UselessViewDetector.USELESS_LEAF.getId()146 sFixes.put(UselessViewDetector.USELESS_LEAF.getId(), RemoveUselessViewFix.class); UselessViewDetector.USELESS_PARENT.getId()147 sFixes.put(UselessViewDetector.USELESS_PARENT.getId(), RemoveUselessViewFix.class); PxUsageDetector.ISSUE.getId()148 sFixes.put(PxUsageDetector.ISSUE.getId(), ConvertToDpFix.class); TextFieldDetector.ISSUE.getId()149 sFixes.put(TextFieldDetector.ISSUE.getId(), SetAttributeFix.class); SecurityDetector.EXPORTED_SERVICE.getId()150 sFixes.put(SecurityDetector.EXPORTED_SERVICE.getId(), SetAttributeFix.class); DetectMissingPrefix.MISSING_NAMESPACE.getId()151 sFixes.put(DetectMissingPrefix.MISSING_NAMESPACE.getId(), AddPrefixFix.class); ScrollViewChildDetector.ISSUE.getId()152 sFixes.put(ScrollViewChildDetector.ISSUE.getId(), SetScrollViewSizeFix.class); ObsoleteLayoutParamsDetector.ISSUE.getId()153 sFixes.put(ObsoleteLayoutParamsDetector.ISSUE.getId(), ObsoleteLayoutParamsFix.class); TypographyDetector.DASHES.getId()154 sFixes.put(TypographyDetector.DASHES.getId(), TypographyFix.class); TypographyDetector.ELLIPSIS.getId()155 sFixes.put(TypographyDetector.ELLIPSIS.getId(), TypographyFix.class); TypographyDetector.FRACTIONS.getId()156 sFixes.put(TypographyDetector.FRACTIONS.getId(), TypographyFix.class); TypographyDetector.OTHER.getId()157 sFixes.put(TypographyDetector.OTHER.getId(), TypographyFix.class); TypographyDetector.QUOTES.getId()158 sFixes.put(TypographyDetector.QUOTES.getId(), TypographyFix.class); UseCompoundDrawableDetector.ISSUE.getId()159 sFixes.put(UseCompoundDrawableDetector.ISSUE.getId(), 160 UseCompoundDrawableDetectorFix.class); 161 // ApiDetector.UNSUPPORTED is provided as a marker resolution rather than 162 // a quick assistant (the marker resolution adds a suitable @TargetApi annotation) 163 } 164 hasFix(String id)165 public static boolean hasFix(String id) { 166 return sFixes.containsKey(id); 167 } 168 169 /** 170 * Returns a fix for the given issue, or null if no fix is available 171 * 172 * @param id the id o the issue to obtain a fix for (see {@link Issue#getId()}) 173 * @param marker the marker corresponding to the error 174 * @return a fix, or null 175 */ getFix(String id, final IMarker marker)176 public static LintFix getFix(String id, final IMarker marker) { 177 Class<? extends LintFix> clazz = sFixes.get(id); 178 if (clazz != null) { 179 try { 180 Constructor<? extends LintFix> constructor = clazz.getDeclaredConstructor( 181 String.class, IMarker.class); 182 constructor.setAccessible(true); 183 return constructor.newInstance(id, marker); 184 } catch (Throwable t) { 185 AdtPlugin.log(t, null); 186 } 187 } 188 189 return null; 190 } 191 } 192