• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
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 
17 package com.android.tools.lint.detector.api;
18 
19 import com.android.annotations.NonNull;
20 import com.android.annotations.Nullable;
21 import com.android.resources.ResourceFolderType;
22 import com.android.tools.lint.client.api.IDomParser;
23 import com.android.tools.lint.client.api.LintDriver;
24 import com.google.common.annotations.Beta;
25 
26 import org.w3c.dom.Document;
27 import org.w3c.dom.Node;
28 
29 import java.io.File;
30 import java.util.regex.Matcher;
31 import java.util.regex.Pattern;
32 
33 /**
34  * A {@link Context} used when checking XML files.
35  * <p/>
36  * <b>NOTE: This is not a public or final API; if you rely on this be prepared
37  * to adjust your code for the next tools release.</b>
38  */
39 @Beta
40 public class XmlContext extends Context {
41     /** The XML parser */
42     public IDomParser parser;
43     /** The XML document */
44     public Document document;
45     private final ResourceFolderType mFolderType;
46 
47     /**
48      * Construct a new {@link XmlContext}
49      *
50      * @param driver the driver running through the checks
51      * @param project the project containing the file being checked
52      * @param main the main project if this project is a library project, or
53      *            null if this is not a library project. The main project is
54      *            the root project of all library projects, not necessarily the
55      *            directly including project.
56      * @param file the file being checked
57      * @param folderType the {@link ResourceFolderType} of this file, if any
58      */
XmlContext( @onNull LintDriver driver, @NonNull Project project, @Nullable Project main, @NonNull File file, @Nullable ResourceFolderType folderType)59     public XmlContext(
60             @NonNull LintDriver driver,
61             @NonNull Project project,
62             @Nullable Project main,
63             @NonNull File file,
64             @Nullable ResourceFolderType folderType) {
65         super(driver, project, main, file);
66         mFolderType = folderType;
67     }
68 
69     /**
70      * Returns the location for the given node, which may be an element or an attribute.
71      *
72      * @param node the node to look up the location for
73      * @return the location for the node
74      */
75     @NonNull
getLocation(@onNull Node node)76     public Location getLocation(@NonNull Node node) {
77         if (parser != null) {
78             return parser.getLocation(this, node);
79         }
80 
81         return Location.create(file);
82     }
83 
84     /**
85      * Reports an issue applicable to a given DOM node. The DOM node is used as the
86      * scope to check for suppress lint annotations.
87      *
88      * @param issue the issue to report
89      * @param scope the DOM node scope the error applies to. The lint infrastructure
90      *    will check whether there are suppress directives on this node (or its enclosing
91      *    nodes) and if so suppress the warning without involving the client.
92      * @param location the location of the issue, or null if not known
93      * @param message the message for this warning
94      * @param data any associated data, or null
95      */
report( @onNull Issue issue, @Nullable Node scope, @Nullable Location location, @NonNull String message, @Nullable Object data)96     public void report(
97             @NonNull Issue issue,
98             @Nullable Node scope,
99             @Nullable Location location,
100             @NonNull String message,
101             @Nullable Object data) {
102         if (scope != null && mDriver.isSuppressed(issue, scope)) {
103             return;
104         }
105         super.report(issue, location, message, data);
106     }
107 
108     @Override
report( @onNull Issue issue, @Nullable Location location, @NonNull String message, @Nullable Object data)109     public void report(
110             @NonNull Issue issue,
111             @Nullable Location location,
112             @NonNull String message,
113             @Nullable Object data) {
114         // Warn if clients use the non-scoped form? No, there are cases where an
115         //  XML detector's error isn't applicable to one particular location (or it's
116         //  not feasible to compute it cheaply)
117         //mDriver.getClient().log(null, "Warning: Issue " + issue
118         //        + " was reported without a scope node: Can't be suppressed.");
119 
120         // For now just check the document root itself
121         if (document != null && mDriver.isSuppressed(issue, document)) {
122             return;
123         }
124 
125         super.report(issue, location, message, data);
126     }
127 
128     /**
129      * Returns the resource folder type of this XML file, if any.
130      *
131      * @return the resource folder type or null
132      */
133     @Nullable
getResourceFolderType()134     public ResourceFolderType getResourceFolderType() {
135         return mFolderType;
136     }
137 
138 
139     private final static Pattern sVersionPattern = Pattern.compile("^v(\\d+)$");//$NON-NLS-1$
140 
141     private static File sCachedFolder = null;
142     private static int sCachedFolderVersion = -1;
143 
144     /**
145      * Returns the folder version. For example, for the file values-v14/foo.xml,
146      * it returns 14.
147      *
148      * @return the folder version, or -1 if no specific version was specified
149      */
getFolderVersion()150     public int getFolderVersion() {
151         File parent = file.getParentFile();
152         if (parent.equals(sCachedFolder)) {
153             return sCachedFolderVersion;
154         }
155 
156         sCachedFolder = parent;
157         sCachedFolderVersion = -1;
158 
159         String[] qualifiers = parent.getName().split("-"); //$NON-NLS-1$
160         for (String qualifier : qualifiers) {
161             Matcher matcher = sVersionPattern.matcher(qualifier);
162             if (matcher.matches()) {
163                 sCachedFolderVersion = Integer.parseInt(matcher.group(1));
164                 break;
165             }
166         }
167 
168         return sCachedFolderVersion;
169     }
170 }
171