blob: 891eced0f726d535ea8521855336fab3bbf82857 [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
*
* 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.tools.lint.detector.api;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.resources.ResourceFolderType;
import com.android.tools.lint.client.api.LintDriver;
import com.android.tools.lint.client.api.XmlParser;
import com.google.common.annotations.Beta;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import java.io.File;
/**
* A {@link Context} used when checking XML files.
* <p/>
* <b>NOTE: This is not a public or final API; if you rely on this be prepared
* to adjust your code for the next tools release.</b>
*/
@Beta
public class XmlContext extends ResourceContext {
static final String SUPPRESS_COMMENT_PREFIX = "<!--suppress "; //$NON-NLS-1$
/** The XML parser */
private final XmlParser mParser;
/** The XML document */
public Document document;
/**
* Construct a new {@link XmlContext}
*
* @param driver the driver running through the checks
* @param project the project containing the file being checked
* @param main the main project if this project is a library project, or
* null if this is not a library project. The main project is
* the root project of all library projects, not necessarily the
* directly including project.
* @param file the file being checked
* @param folderType the {@link ResourceFolderType} of this file, if any
*/
public XmlContext(
@NonNull LintDriver driver,
@NonNull Project project,
@Nullable Project main,
@NonNull File file,
@Nullable ResourceFolderType folderType,
@NonNull XmlParser parser) {
super(driver, project, main, file, folderType);
mParser = parser;
}
/**
* Returns the location for the given node, which may be an element or an attribute.
*
* @param node the node to look up the location for
* @return the location for the node
*/
@NonNull
public Location getLocation(@NonNull Node node) {
return mParser.getLocation(this, node);
}
/**
* Returns the location for name-portion of the given element or attribute.
*
* @param node the node to look up the location for
* @return the location for the node
*/
@NonNull
public Location getNameLocation(@NonNull Node node) {
return mParser.getNameLocation(this, node);
}
/**
* Returns the location for value-portion of the given attribute
*
* @param node the node to look up the location for
* @return the location for the node
*/
@NonNull
public Location getValueLocation(@NonNull Attr node) {
return mParser.getValueLocation(this, node);
}
/**
* Creates a new location within an XML text node
*
* @param textNode the text node
* @param begin the start offset within the text node (inclusive)
* @param end the end offset within the text node (exclusive)
* @return a new location
*/
@NonNull
public Location getLocation(@NonNull Node textNode, int begin, int end) {
assert textNode.getNodeType() == Node.TEXT_NODE;
return mParser.getLocation(this, textNode, begin, end);
}
@NonNull
public XmlParser getParser() {
return mParser;
}
/**
* Reports an issue applicable to a given DOM node. The DOM node is used as the
* scope to check for suppress lint annotations.
*
* @param issue the issue to report
* @param scope the DOM node scope the error applies to. The lint infrastructure
* will check whether there are suppress directives on this node (or its enclosing
* nodes) and if so suppress the warning without involving the client.
* @param location the location of the issue, or null if not known
* @param message the message for this warning
*/
public void report(
@NonNull Issue issue,
@Nullable Node scope,
@Nullable Location location,
@NonNull String message) {
if (scope != null && mDriver.isSuppressed(this, issue, scope)) {
return;
}
super.report(issue, location, message);
}
/**
* Report an error.
* Like {@link #report(Issue, org.w3c.dom.Node, Location, String)} but with
* a now-unused data parameter at the end.
*
* @deprecated Use {@link #report(Issue, org.w3c.dom.Node, Location, String)} instead;
* this method is here for custom rule compatibility
*/
@SuppressWarnings("UnusedDeclaration") // Potentially used by external existing custom rules
@Deprecated
public void report(
@NonNull Issue issue,
@Nullable Node scope,
@Nullable Location location,
@NonNull String message,
@SuppressWarnings("UnusedParameters") @Nullable Object data) {
report(issue, scope, location, message);
}
@Override
public void report(
@NonNull Issue issue,
@Nullable Location location,
@NonNull String message) {
// Warn if clients use the non-scoped form? No, there are cases where an
// XML detector's error isn't applicable to one particular location (or it's
// not feasible to compute it cheaply)
//mDriver.getClient().log(null, "Warning: Issue " + issue
// + " was reported without a scope node: Can't be suppressed.");
// For now just check the document root itself
if (document != null && mDriver.isSuppressed(this, issue, document)) {
return;
}
super.report(issue, location, message);
}
@Override
@Nullable
protected String getSuppressCommentPrefix() {
return SUPPRESS_COMMENT_PREFIX;
}
public boolean isSuppressedWithComment(@NonNull Node node, @NonNull Issue issue) {
// Check whether there is a comment marker
String contents = getContents();
assert contents != null; // otherwise we wouldn't be here
int start = mParser.getNodeStartOffset(this, node);
if (start != -1) {
return isSuppressedWithComment(start, issue);
}
return false;
}
@NonNull
public Location.Handle createLocationHandle(@NonNull Node node) {
return mParser.createLocationHandle(this, node);
}
}