blob: 366e94945df9717d20693c7077bdc78dffb1f18e [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.eclipse.org/org/documents/epl-v10.php
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.ide.eclipse.adt.internal.lint;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.tools.lint.checks.AccessibilityDetector;
import com.android.tools.lint.checks.DetectMissingPrefix;
import com.android.tools.lint.checks.DosLineEndingDetector;
import com.android.tools.lint.checks.HardcodedValuesDetector;
import com.android.tools.lint.checks.InefficientWeightDetector;
import com.android.tools.lint.checks.ManifestDetector;
import com.android.tools.lint.checks.MissingIdDetector;
import com.android.tools.lint.checks.ObsoleteLayoutParamsDetector;
import com.android.tools.lint.checks.PxUsageDetector;
import com.android.tools.lint.checks.ScrollViewChildDetector;
import com.android.tools.lint.checks.SecurityDetector;
import com.android.tools.lint.checks.TextFieldDetector;
import com.android.tools.lint.checks.TranslationDetector;
import com.android.tools.lint.checks.TypoDetector;
import com.android.tools.lint.checks.TypographyDetector;
import com.android.tools.lint.checks.UseCompoundDrawableDetector;
import com.android.tools.lint.checks.UselessViewDetector;
import com.android.tools.lint.detector.api.Issue;
import com.android.tools.lint.detector.api.TextFormat;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import java.lang.reflect.Constructor;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
abstract class LintFix implements ICompletionProposal {
protected final IMarker mMarker;
protected final String mId;
protected LintFix(String id, IMarker marker) {
mId = id;
mMarker = marker;
}
/**
* Returns true if this fix needs focus (which means that when the fix is
* performed from for example a {@link LintListDialog}'s Fix button) the
* editor needs to be given focus.
*
* @return true if this fix needs focus after being applied
*/
public boolean needsFocus() {
return true;
}
/**
* Returns true if this fix can be performed along side other fixes
*
* @return true if this fix can be performed in a bulk operation with other
* fixes
*/
public boolean isBulkCapable() {
return false;
}
/**
* Returns true if this fix can be cancelled once it's invoked. This is the case
* for fixes which shows a confirmation dialog (such as the Extract String etc).
* This will be used to determine whether the marker can be deleted immediately
* (for non-cancelable fixes) or if it should be left alone and detected fix
* on the next save.
*
* @return true if the fix can be cancelled
*/
public boolean isCancelable() {
return true;
}
// ---- Implements ICompletionProposal ----
@Override
public String getDisplayString() {
return null;
}
@Override
public String getAdditionalProposalInfo() {
Issue issue = EclipseLintClient.getRegistry().getIssue(mId);
if (issue != null) {
return issue.getExplanation(TextFormat.HTML);
}
return null;
}
public void deleteMarker() {
try {
mMarker.delete();
} catch (PartInitException e) {
AdtPlugin.log(e, null);
} catch (CoreException e) {
AdtPlugin.log(e, null);
}
}
@Override
public Point getSelection(IDocument document) {
return null;
}
@Override
public Image getImage() {
ISharedImages sharedImages = PlatformUI.getWorkbench().getSharedImages();
return sharedImages.getImage(ISharedImages.IMG_OBJS_WARN_TSK);
}
@Override
public IContextInformation getContextInformation() {
return null;
}
// --- Access to available fixes ---
private static final Map<String, Class<? extends LintFix>> sFixes =
new HashMap<String, Class<? extends LintFix>>();
// Keep this map in sync with BuiltinIssueRegistry's hasAutoFix() data
static {
sFixes.put(InefficientWeightDetector.INEFFICIENT_WEIGHT.getId(),
LinearLayoutWeightFix.class);
sFixes.put(AccessibilityDetector.ISSUE.getId(), SetAttributeFix.class);
sFixes.put(InefficientWeightDetector.BASELINE_WEIGHTS.getId(), SetAttributeFix.class);
sFixes.put(ManifestDetector.ALLOW_BACKUP.getId(), SetAttributeFix.class);
sFixes.put(MissingIdDetector.ISSUE.getId(), SetAttributeFix.class);
sFixes.put(HardcodedValuesDetector.ISSUE.getId(), ExtractStringFix.class);
sFixes.put(UselessViewDetector.USELESS_LEAF.getId(), RemoveUselessViewFix.class);
sFixes.put(UselessViewDetector.USELESS_PARENT.getId(), RemoveUselessViewFix.class);
sFixes.put(PxUsageDetector.PX_ISSUE.getId(), ConvertToDpFix.class);
sFixes.put(TextFieldDetector.ISSUE.getId(), SetAttributeFix.class);
sFixes.put(SecurityDetector.EXPORTED_SERVICE.getId(), SetAttributeFix.class);
sFixes.put(TranslationDetector.MISSING.getId(), SetAttributeFix.class);
sFixes.put(DetectMissingPrefix.MISSING_NAMESPACE.getId(), AddPrefixFix.class);
sFixes.put(ScrollViewChildDetector.ISSUE.getId(), SetScrollViewSizeFix.class);
sFixes.put(ObsoleteLayoutParamsDetector.ISSUE.getId(), ObsoleteLayoutParamsFix.class);
sFixes.put(TypographyDetector.DASHES.getId(), TypographyFix.class);
sFixes.put(TypographyDetector.ELLIPSIS.getId(), TypographyFix.class);
sFixes.put(TypographyDetector.FRACTIONS.getId(), TypographyFix.class);
sFixes.put(TypographyDetector.OTHER.getId(), TypographyFix.class);
sFixes.put(TypographyDetector.QUOTES.getId(), TypographyFix.class);
sFixes.put(UseCompoundDrawableDetector.ISSUE.getId(),
UseCompoundDrawableDetectorFix.class);
sFixes.put(TypoDetector.ISSUE.getId(), TypoFix.class);
sFixes.put(DosLineEndingDetector.ISSUE.getId(), DosLineEndingsFix.class);
// ApiDetector.UNSUPPORTED is provided as a marker resolution rather than
// a quick assistant (the marker resolution adds a suitable @TargetApi annotation)
}
public static boolean hasFix(String id) {
return sFixes.containsKey(id);
}
/**
* Returns one or more fixes for the given issue, or null if no fixes are available
*
* @param id the id o the issue to obtain a fix for (see {@link Issue#getId()})
* @param marker the marker corresponding to the error
* @return a nonempty list of fix, or null
*/
@Nullable
public static List<LintFix> getFixes(@NonNull String id, @NonNull IMarker marker) {
Class<? extends LintFix> clazz = sFixes.get(id);
if (clazz != null) {
try {
Constructor<? extends LintFix> constructor = clazz.getDeclaredConstructor(
String.class, IMarker.class);
constructor.setAccessible(true);
LintFix fix = constructor.newInstance(id, marker);
List<LintFix> alternatives = fix.getAllFixes();
if (alternatives != null) {
return alternatives;
} else {
return Collections.singletonList(fix);
}
} catch (Throwable t) {
AdtPlugin.log(t, null);
}
}
return null;
}
/**
* Returns a full list of fixes for this issue. This will produce a list of
* multiple fixes, in the desired order, which provide alternative ways of
* fixing the issue.
*
* @return a list of fixes to fix this issue, or null if there are no
* variations
*/
@Nullable
protected List<LintFix> getAllFixes() {
return null;
}
}