Home | History | Annotate | Download | only in lint
      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.annotations.NonNull;
     20 import com.android.annotations.Nullable;
     21 import com.android.ide.eclipse.adt.AdtPlugin;
     22 import com.android.tools.lint.checks.AccessibilityDetector;
     23 import com.android.tools.lint.checks.DetectMissingPrefix;
     24 import com.android.tools.lint.checks.DosLineEndingDetector;
     25 import com.android.tools.lint.checks.HardcodedValuesDetector;
     26 import com.android.tools.lint.checks.InefficientWeightDetector;
     27 import com.android.tools.lint.checks.ManifestOrderDetector;
     28 import com.android.tools.lint.checks.MissingIdDetector;
     29 import com.android.tools.lint.checks.ObsoleteLayoutParamsDetector;
     30 import com.android.tools.lint.checks.PxUsageDetector;
     31 import com.android.tools.lint.checks.ScrollViewChildDetector;
     32 import com.android.tools.lint.checks.SecurityDetector;
     33 import com.android.tools.lint.checks.TextFieldDetector;
     34 import com.android.tools.lint.checks.TranslationDetector;
     35 import com.android.tools.lint.checks.TypoDetector;
     36 import com.android.tools.lint.checks.TypographyDetector;
     37 import com.android.tools.lint.checks.UseCompoundDrawableDetector;
     38 import com.android.tools.lint.checks.UselessViewDetector;
     39 import com.android.tools.lint.detector.api.Issue;
     40 import com.android.tools.lint.detector.api.Issue.OutputFormat;
     41 
     42 import org.eclipse.core.resources.IMarker;
     43 import org.eclipse.core.runtime.CoreException;
     44 import org.eclipse.jface.text.IDocument;
     45 import org.eclipse.jface.text.contentassist.ICompletionProposal;
     46 import org.eclipse.jface.text.contentassist.IContextInformation;
     47 import org.eclipse.swt.graphics.Image;
     48 import org.eclipse.swt.graphics.Point;
     49 import org.eclipse.ui.ISharedImages;
     50 import org.eclipse.ui.PartInitException;
     51 import org.eclipse.ui.PlatformUI;
     52 
     53 import java.lang.reflect.Constructor;
     54 import java.util.Collections;
     55 import java.util.HashMap;
     56 import java.util.List;
     57 import java.util.Map;
     58 
     59 abstract class LintFix implements ICompletionProposal {
     60     protected final IMarker mMarker;
     61     protected final String mId;
     62 
     63     protected LintFix(String id, IMarker marker) {
     64         mId = id;
     65         mMarker = marker;
     66     }
     67 
     68     /**
     69      * Returns true if this fix needs focus (which means that when the fix is
     70      * performed from for example a {@link LintListDialog}'s Fix button) the
     71      * editor needs to be given focus.
     72      *
     73      * @return true if this fix needs focus after being applied
     74      */
     75     public boolean needsFocus() {
     76         return true;
     77     }
     78 
     79     /**
     80      * Returns true if this fix can be performed along side other fixes
     81      *
     82      * @return true if this fix can be performed in a bulk operation with other
     83      *         fixes
     84      */
     85     public boolean isBulkCapable() {
     86         return false;
     87     }
     88 
     89     /**
     90      * Returns true if this fix can be cancelled once it's invoked. This is the case
     91      * for fixes which shows a confirmation dialog (such as the Extract String etc).
     92      * This will be used to determine whether the marker can be deleted immediately
     93      * (for non-cancelable fixes) or if it should be left alone and detected fix
     94      * on the next save.
     95      *
     96      * @return true if the fix can be cancelled
     97      */
     98     public boolean isCancelable() {
     99         return true;
    100     }
    101 
    102     // ---- Implements ICompletionProposal ----
    103 
    104     @Override
    105     public String getDisplayString() {
    106         return null;
    107     }
    108 
    109     @Override
    110     public String getAdditionalProposalInfo() {
    111         Issue issue = EclipseLintClient.getRegistry().getIssue(mId);
    112         if (issue != null) {
    113             return issue.getExplanation(OutputFormat.HTML);
    114         }
    115 
    116         return null;
    117     }
    118 
    119     public void deleteMarker() {
    120         try {
    121             mMarker.delete();
    122         } catch (PartInitException e) {
    123             AdtPlugin.log(e, null);
    124         } catch (CoreException e) {
    125             AdtPlugin.log(e, null);
    126         }
    127     }
    128 
    129     @Override
    130     public Point getSelection(IDocument document) {
    131         return null;
    132     }
    133 
    134     @Override
    135     public Image getImage() {
    136         ISharedImages sharedImages = PlatformUI.getWorkbench().getSharedImages();
    137         return sharedImages.getImage(ISharedImages.IMG_OBJS_WARN_TSK);
    138     }
    139 
    140     @Override
    141     public IContextInformation getContextInformation() {
    142         return null;
    143     }
    144 
    145     // --- Access to available fixes ---
    146 
    147     private static final Map<String, Class<? extends LintFix>> sFixes =
    148             new HashMap<String, Class<? extends LintFix>>();
    149     // Keep this map in sync with BuiltinIssueRegistry's hasAutoFix() data
    150     static {
    151         sFixes.put(InefficientWeightDetector.INEFFICIENT_WEIGHT.getId(),
    152                 LinearLayoutWeightFix.class);
    153         sFixes.put(AccessibilityDetector.ISSUE.getId(), SetAttributeFix.class);
    154         sFixes.put(InefficientWeightDetector.BASELINE_WEIGHTS.getId(), SetAttributeFix.class);
    155         sFixes.put(ManifestOrderDetector.ALLOW_BACKUP.getId(), SetAttributeFix.class);
    156         sFixes.put(MissingIdDetector.ISSUE.getId(), SetAttributeFix.class);
    157         sFixes.put(HardcodedValuesDetector.ISSUE.getId(), ExtractStringFix.class);
    158         sFixes.put(UselessViewDetector.USELESS_LEAF.getId(), RemoveUselessViewFix.class);
    159         sFixes.put(UselessViewDetector.USELESS_PARENT.getId(), RemoveUselessViewFix.class);
    160         sFixes.put(PxUsageDetector.PX_ISSUE.getId(), ConvertToDpFix.class);
    161         sFixes.put(TextFieldDetector.ISSUE.getId(), SetAttributeFix.class);
    162         sFixes.put(SecurityDetector.EXPORTED_SERVICE.getId(), SetAttributeFix.class);
    163         sFixes.put(TranslationDetector.MISSING.getId(), SetAttributeFix.class);
    164         sFixes.put(DetectMissingPrefix.MISSING_NAMESPACE.getId(), AddPrefixFix.class);
    165         sFixes.put(ScrollViewChildDetector.ISSUE.getId(), SetScrollViewSizeFix.class);
    166         sFixes.put(ObsoleteLayoutParamsDetector.ISSUE.getId(), ObsoleteLayoutParamsFix.class);
    167         sFixes.put(TypographyDetector.DASHES.getId(), TypographyFix.class);
    168         sFixes.put(TypographyDetector.ELLIPSIS.getId(), TypographyFix.class);
    169         sFixes.put(TypographyDetector.FRACTIONS.getId(), TypographyFix.class);
    170         sFixes.put(TypographyDetector.OTHER.getId(), TypographyFix.class);
    171         sFixes.put(TypographyDetector.QUOTES.getId(), TypographyFix.class);
    172         sFixes.put(UseCompoundDrawableDetector.ISSUE.getId(),
    173                 UseCompoundDrawableDetectorFix.class);
    174         sFixes.put(TypoDetector.ISSUE.getId(), TypoFix.class);
    175         sFixes.put(DosLineEndingDetector.ISSUE.getId(), DosLineEndingsFix.class);
    176         // ApiDetector.UNSUPPORTED is provided as a marker resolution rather than
    177         // a quick assistant (the marker resolution adds a suitable @TargetApi annotation)
    178     }
    179 
    180     public static boolean hasFix(String id) {
    181         return sFixes.containsKey(id);
    182     }
    183 
    184     /**
    185      * Returns one or more fixes for the given issue, or null if no fixes are available
    186      *
    187      * @param id the id o the issue to obtain a fix for (see {@link Issue#getId()})
    188      * @param marker the marker corresponding to the error
    189      * @return a nonempty list of fix, or null
    190      */
    191     @Nullable
    192     public static List<LintFix> getFixes(@NonNull String id, @NonNull IMarker marker) {
    193         Class<? extends LintFix> clazz = sFixes.get(id);
    194         if (clazz != null) {
    195             try {
    196                 Constructor<? extends LintFix> constructor = clazz.getDeclaredConstructor(
    197                         String.class, IMarker.class);
    198                 constructor.setAccessible(true);
    199                 LintFix fix = constructor.newInstance(id, marker);
    200                 List<LintFix> alternatives = fix.getAllFixes();
    201                 if (alternatives != null) {
    202                     return alternatives;
    203                 } else {
    204                     return Collections.singletonList(fix);
    205                 }
    206             } catch (Throwable t) {
    207                 AdtPlugin.log(t, null);
    208             }
    209         }
    210 
    211         return null;
    212     }
    213 
    214     /**
    215      * Returns a full list of fixes for this issue. This will produce a list of
    216      * multiple fixes, in the desired order, which provide alternative ways of
    217      * fixing the issue.
    218      *
    219      * @return a list of fixes to fix this issue, or null if there are no
    220      *         variations
    221      */
    222     @Nullable
    223     protected List<LintFix> getAllFixes() {
    224         return null;
    225     }
    226 }
    227