• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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 import static com.android.SdkConstants.DOT_CLASS;
19 import static com.android.SdkConstants.DOT_JAVA;
20 import static com.android.SdkConstants.DOT_XML;
21 
22 import com.android.SdkConstants;
23 import com.android.annotations.NonNull;
24 import com.android.annotations.Nullable;
25 import com.android.ide.eclipse.adt.AdtPlugin;
26 import com.android.ide.eclipse.adt.AdtUtils;
27 import com.android.tools.lint.client.api.IssueRegistry;
28 import com.android.tools.lint.client.api.LintDriver;
29 import com.android.tools.lint.detector.api.Issue;
30 import com.android.tools.lint.detector.api.Scope;
31 import com.android.utils.SdkUtils;
32 
33 import org.eclipse.core.resources.IFile;
34 import org.eclipse.core.resources.IMarker;
35 import org.eclipse.core.resources.IProject;
36 import org.eclipse.core.resources.IResource;
37 import org.eclipse.core.runtime.IProgressMonitor;
38 import org.eclipse.core.runtime.IStatus;
39 import org.eclipse.core.runtime.Status;
40 import org.eclipse.core.runtime.jobs.IJobManager;
41 import org.eclipse.core.runtime.jobs.Job;
42 
43 import java.io.File;
44 import java.util.ArrayList;
45 import java.util.EnumSet;
46 import java.util.List;
47 
48 /** Job to check lint on a set of resources */
49 final class LintJob extends Job {
50     /** Job family */
51     private static final Object FAMILY_RUN_LINT = new Object();
52     private final EclipseLintClient mClient;
53     private final List<? extends IResource> mResources;
54     private final IResource mSource;
55     private LintDriver mLint;
56     private boolean mFatal;
57 
LintJob( @onNull EclipseLintClient client, @NonNull List<? extends IResource> resources, @Nullable IResource source)58     LintJob(
59             @NonNull EclipseLintClient client,
60             @NonNull List<? extends IResource> resources,
61             @Nullable IResource source) {
62         super("Running Android Lint");
63         mClient = client;
64         mResources = resources;
65         mSource = source;
66     }
67 
68     @Override
belongsTo(Object family)69     public boolean belongsTo(Object family) {
70         return family == FAMILY_RUN_LINT;
71     }
72 
73     @Override
canceling()74     protected void canceling() {
75         super.canceling();
76         if (mLint != null) {
77             mLint.cancel();
78         }
79     }
80 
81     @Override
82     @NonNull
run(IProgressMonitor monitor)83     protected IStatus run(IProgressMonitor monitor) {
84         try {
85             monitor.beginTask("Looking for errors", IProgressMonitor.UNKNOWN);
86             IssueRegistry registry = EclipseLintClient.getRegistry();
87             EnumSet<Scope> scope = null;
88             List<File> files = new ArrayList<File>(mResources.size());
89             for (IResource resource : mResources) {
90                 File file = AdtUtils.getAbsolutePath(resource).toFile();
91                 files.add(file);
92 
93                 if (resource instanceof IProject && mSource == null) {
94                     scope = Scope.ALL;
95                 } else {
96                     String name = resource.getName();
97                     if (SdkUtils.endsWithIgnoreCase(name, DOT_XML)) {
98                         if (name.equals(SdkConstants.FN_ANDROID_MANIFEST_XML)) {
99                             scope = EnumSet.of(Scope.MANIFEST);
100                         } else {
101                             scope = Scope.RESOURCE_FILE_SCOPE;
102                         }
103                     } else if (name.endsWith(DOT_JAVA) && resource instanceof IFile) {
104                         if (scope != null) {
105                             if (!scope.contains(Scope.JAVA_FILE)) {
106                                 scope = EnumSet.copyOf(scope);
107                                 scope.add(Scope.JAVA_FILE);
108                             }
109                         } else {
110                             scope = Scope.JAVA_FILE_SCOPE;
111                         }
112                     } else if (name.endsWith(DOT_CLASS) && resource instanceof IFile) {
113                         if (scope != null) {
114                             if (!scope.contains(Scope.CLASS_FILE)) {
115                                 scope = EnumSet.copyOf(scope);
116                                 scope.add(Scope.CLASS_FILE);
117                             }
118                         } else {
119                             scope = Scope.CLASS_FILE_SCOPE;
120                         }
121                     } else {
122                         return new Status(Status.ERROR, AdtPlugin.PLUGIN_ID, Status.ERROR,
123                             "Only XML & Java files are supported for single file lint", null); //$NON-NLS-1$
124                     }
125                 }
126             }
127             if (scope == null) {
128                 scope = Scope.ALL;
129             }
130             if (mSource == null) {
131                 assert !Scope.checkSingleFile(scope) : scope + " with " + mResources;
132             }
133             // Check single file?
134             if (mSource != null) {
135                 // Delete specific markers
136                 IMarker[] markers = EclipseLintClient.getMarkers(mSource);
137                 for (IMarker marker : markers) {
138                     String id = marker.getAttribute(EclipseLintRunner.MARKER_CHECKID_PROPERTY, "");
139                     Issue issue = registry.getIssue(id);
140                     if (issue == null) {
141                         continue;
142                     }
143                     if (issue.getImplementation().isAdequate(scope)) {
144                         marker.delete();
145                     }
146                 }
147                 mClient.setSearchForSuperClasses(true);
148             } else {
149                 EclipseLintClient.clearMarkers(mResources);
150             }
151 
152             mLint = new LintDriver(registry, mClient);
153             mLint.analyze(files, scope);
154             mFatal = mClient.hasFatalErrors();
155             return Status.OK_STATUS;
156         } catch (Exception e) {
157             return new Status(Status.ERROR, AdtPlugin.PLUGIN_ID, Status.ERROR,
158                               "Failed", e); //$NON-NLS-1$
159         } finally {
160             if (monitor != null) {
161                 monitor.done();
162             }
163         }
164     }
165 
166     /**
167      * Returns true if a fatal error was encountered
168      *
169      * @return true if a fatal error was encountered
170      */
isFatal()171     public boolean isFatal() {
172         return mFatal;
173     }
174 
175     /**
176      * Returns the associated lint client
177      *
178      * @return the associated lint client
179      */
180     @NonNull
getLintClient()181     public EclipseLintClient getLintClient() {
182         return mClient;
183     }
184 
185     /** Returns the current lint jobs, if any (never returns null but array may be empty) */
186     @NonNull
getCurrentJobs()187     static Job[] getCurrentJobs() {
188         IJobManager jobManager = Job.getJobManager();
189         return jobManager.find(LintJob.FAMILY_RUN_LINT);
190     }
191 }
192