lint-checks

16:38:51.273 INFO  jd.cli.Main - Decompiling lint-checks.jar
package com.android.tools.lint.checks;

import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.tools.lint.detector.api.Category;
import com.android.tools.lint.detector.api.Implementation;
import com.android.tools.lint.detector.api.Issue;
import com.android.tools.lint.detector.api.LayoutDetector;
import com.android.tools.lint.detector.api.Scope;
import com.android.tools.lint.detector.api.Severity;
import com.android.tools.lint.detector.api.Speed;
import com.android.tools.lint.detector.api.XmlContext;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;

public class AccessibilityDetector
  extends LayoutDetector
{
  public static final Issue ISSUE = Issue.create("ContentDescription", "Image without `contentDescription`", "Ensures that image widgets provide a contentDescription", "Non-textual widgets like ImageViews and ImageButtons should use the `contentDescription` attribute to specify a textual description of the widget such that screen readers and other accessibility tools can adequately describe the user interface.\n\nNote that elements in application screens that are purely decorative and do not provide any content or enable a user action should not have accessibility content descriptions. In this case, just suppress the lint warning with a tools:ignore=\"ContentDescription\" attribute.\n\nNote that for text fields, you should not set both the `hint` and the `contentDescription` attributes since the hint will never be shown. Just set the `hint`. See http://developer.android.com/guide/topics/ui/accessibility/checklist.html#special-cases.", Category.A11Y, 3, Severity.WARNING, new Implementation(AccessibilityDetector.class, Scope.RESOURCE_FILE_SCOPE));
  
  @NonNull
  public Speed getSpeed()
  {
    return Speed.FAST;
  }
  
  public Collection<String> getApplicableElements()
  {
    return Arrays.asList(new String[] { "ImageButton", "ImageView" });
  }
  
  @Nullable
  public Collection<String> getApplicableAttributes()
  {
    return Collections.singletonList("contentDescription");
  }
  
  public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute)
  {
    Element element = attribute.getOwnerElement();
    if (element.hasAttributeNS("http://schemas.android.com/apk/res/android", "hint")) {
      context.report(ISSUE, element, context.getLocation(attribute), "Do not set both contentDescription and hint: the contentDescription will mask the hint", null);
    }
  }
  
  public void visitElement(@NonNull XmlContext context, @NonNull Element element)
  {
    if (!element.hasAttributeNS("http://schemas.android.com/apk/res/android", "contentDescription"))
    {
      if ("no".equals(element.getAttributeNS("http://schemas.android.com/apk/res/android", "importantForAccessibility"))) {
        return;
      }
      context.report(ISSUE, element, context.getLocation(element), "[Accessibility] Missing contentDescription attribute on image", null);
    }
    else
    {
      Attr attributeNode = element.getAttributeNodeNS("http://schemas.android.com/apk/res/android", "contentDescription");
      String attribute = attributeNode.getValue();
      if ((attribute.isEmpty()) || (attribute.equals("TODO"))) {
        context.report(ISSUE, attributeNode, context.getLocation(attributeNode), "[Accessibility] Empty contentDescription attribute on image", null);
      }
    }
  }
}

/* Location:
 * Qualified Name:     com.android.tools.lint.checks.AccessibilityDetector
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package com.android.tools.lint.checks;

import com.android.tools.lint.client.api.LintDriver;
import com.android.tools.lint.detector.api.JavaContext;
import java.util.ArrayList;
import java.util.List;
import lombok.ast.ForwardingAstVisitor;
import lombok.ast.Identifier;
import lombok.ast.Select;

class AlwaysShowActionDetector$FieldAccessChecker
  extends ForwardingAstVisitor
{
  private final JavaContext mContext;
  
  public AlwaysShowActionDetector$FieldAccessChecker(AlwaysShowActionDetector paramAlwaysShowActionDetector, JavaContext context)
  {
    mContext = context;
  }
  
  public boolean visitSelect(Select node)
  {
    String description = node.astIdentifier().astValue();
    boolean isIfRoom = description.equals("SHOW_AS_ACTION_IF_ROOM");
    boolean isAlways = description.equals("SHOW_AS_ACTION_ALWAYS");
    if (((isIfRoom) || (isAlways)) && (node.astOperand().toString().equals("MenuItem"))) {
      if (isAlways)
      {
        if (mContext.getDriver().isSuppressed(AlwaysShowActionDetector.ISSUE, node)) {
          return super.visitSelect(node);
        }
        if (AlwaysShowActionDetector.access$000(this$0) == null) {
          AlwaysShowActionDetector.access$002(this$0, new ArrayList());
        }
        AlwaysShowActionDetector.access$000(this$0).add(mContext.getLocation(node));
      }
      else
      {
        AlwaysShowActionDetector.access$102(this$0, true);
      }
    }
    return super.visitSelect(node);
  }
}

/* Location:
 * Qualified Name:     com.android.tools.lint.checks.AlwaysShowActionDetector.FieldAccessChecker
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package com.android.tools.lint.checks;

import com.android.annotations.NonNull;
import com.android.resources.ResourceFolderType;
import com.android.tools.lint.client.api.LintDriver;
import com.android.tools.lint.detector.api.Category;
import com.android.tools.lint.detector.api.Context;
import com.android.tools.lint.detector.api.Detector.JavaScanner;
import com.android.tools.lint.detector.api.Implementation;
import com.android.tools.lint.detector.api.Issue;
import com.android.tools.lint.detector.api.JavaContext;
import com.android.tools.lint.detector.api.Location;
import com.android.tools.lint.detector.api.ResourceXmlDetector;
import com.android.tools.lint.detector.api.Scope;
import com.android.tools.lint.detector.api.Severity;
import com.android.tools.lint.detector.api.Speed;
import com.android.tools.lint.detector.api.XmlContext;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import lombok.ast.AstVisitor;
import lombok.ast.ForwardingAstVisitor;
import lombok.ast.Identifier;
import lombok.ast.Select;
import org.w3c.dom.Attr;

public class AlwaysShowActionDetector
  extends ResourceXmlDetector
  implements Detector.JavaScanner
{
  public static final Issue ISSUE = Issue.create("AlwaysShowAction", "Usage of `showAsAction=always`", "Checks for uses of `showAsAction=\"always\"` and suggests `showAsAction=\"ifRoom\"` instead", "Using `showAsAction=\"always\"` in menu XML, or `MenuItem.SHOW_AS_ACTION_ALWAYS` in Java code is usually a deviation from the user interface style guide.Use `ifRoom` or the corresponding `MenuItem.SHOW_AS_ACTION_IF_ROOM` instead.\n\nIf `always` is used sparingly there are usually no problems and behavior is roughly equivalent to `ifRoom` but with preference over other `ifRoom` items. Using it more than twice in the same menu is a bad idea.\n\nThis check looks for menu XML files that contain more than two `always` actions, or some `always` actions and no `ifRoom` actions. In Java code, it looks for projects that contain references to `MenuItem.SHOW_AS_ACTION_ALWAYS` and no references to `MenuItem.SHOW_AS_ACTION_IF_ROOM`.", Category.USABILITY, 3, Severity.WARNING, new Implementation(AlwaysShowActionDetector.class, Scope.JAVA_AND_RESOURCE_FILES)).addMoreInfo("http://developer.android.com/design/patterns/actionbar.html");
  private List<Attr> mFileAttributes;
  private boolean mIgnoreFile;
  private List<Location> mAlwaysFields;
  private boolean mHasIfRoomRefs;
  
  public boolean appliesTo(@NonNull ResourceFolderType folderType)
  {
    return folderType == ResourceFolderType.MENU;
  }
  
  @NonNull
  public Speed getSpeed()
  {
    return Speed.FAST;
  }
  
  public Collection<String> getApplicableAttributes()
  {
    return Collections.singletonList("showAsAction");
  }
  
  public void beforeCheckFile(@NonNull Context context)
  {
    mFileAttributes = null;
  }
  
  public void afterCheckFile(@NonNull Context context)
  {
    if (mIgnoreFile)
    {
      mFileAttributes = null;
      return;
    }
    if (mFileAttributes != null)
    {
      assert ((context instanceof XmlContext));
      
      List<Attr> always = new ArrayList();
      List<Attr> ifRoom = new ArrayList();
      for (Attr attribute : mFileAttributes)
      {
        String value = attribute.getValue();
        if (value.equals("always"))
        {
          always.add(attribute);
        }
        else if (value.equals("ifRoom"))
        {
          ifRoom.add(attribute);
        }
        else if (value.indexOf('|') != -1)
        {
          String[] flags = value.split("\\|");
          for (String flag : flags)
          {
            if (flag.equals("always"))
            {
              always.add(attribute);
              break;
            }
            if (flag.equals("ifRoom"))
            {
              ifRoom.add(attribute);
              break;
            }
          }
        }
      }
      if ((!always.isEmpty()) && (mFileAttributes.size() > 1)) {
        if ((always.size() > 2) || (ifRoom.isEmpty()))
        {
          XmlContext xmlContext = (XmlContext)context;
          Location location = null;
          for (int i = always.size() - 1; i >= 0; i--)
          {
            Location next = location;
            location = xmlContext.getLocation((org.w3c.dom.Node)always.get(i));
            if (next != null) {
              location.setSecondary(next);
            }
          }
          context.report(ISSUE, location, "Prefer \"ifRoom\" instead of \"always\"", null);
        }
      }
    }
  }
  
  public void afterCheckProject(@NonNull Context context)
  {
    if ((mAlwaysFields != null) && (!mHasIfRoomRefs)) {
      for (Location location : mAlwaysFields) {
        context.report(ISSUE, location, "Prefer \"SHOW_AS_ACTION_IF_ROOM\" instead of \"SHOW_AS_ACTION_ALWAYS\"", null);
      }
    }
  }
  
  public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute)
  {
    if (context.getDriver().isSuppressed(ISSUE, attribute))
    {
      mIgnoreFile = true;
      return;
    }
    if (mFileAttributes == null) {
      mFileAttributes = new ArrayList();
    }
    mFileAttributes.add(attribute);
  }
  
  public List<Class<? extends lombok.ast.Node>> getApplicableNodeTypes()
  {
    return Collections.singletonList(Select.class);
  }
  
  public AstVisitor createJavaVisitor(@NonNull JavaContext context)
  {
    return new FieldAccessChecker(context);
  }
  
  private class FieldAccessChecker
    extends ForwardingAstVisitor
  {
    private final JavaContext mContext;
    
    public FieldAccessChecker(JavaContext context)
    {
      mContext = context;
    }
    
    public boolean visitSelect(Select node)
    {
      String description = node.astIdentifier().astValue();
      boolean isIfRoom = description.equals("SHOW_AS_ACTION_IF_ROOM");
      boolean isAlways = description.equals("SHOW_AS_ACTION_ALWAYS");
      if (((isIfRoom) || (isAlways)) && (node.astOperand().toString().equals("MenuItem"))) {
        if (isAlways)
        {
          if (mContext.getDriver().isSuppressed(AlwaysShowActionDetector.ISSUE, node)) {
            return super.visitSelect(node);
          }
          if (mAlwaysFields == null) {
            mAlwaysFields = new ArrayList();
          }
          mAlwaysFields.add(mContext.getLocation(node));
        }
        else
        {
          mHasIfRoomRefs = true;
        }
      }
      return super.visitSelect(node);
    }
  }
}

/* Location:
 * Qualified Name:     com.android.tools.lint.checks.AlwaysShowActionDetector
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package com.android.tools.lint.checks;

import com.android.tools.lint.client.api.IssueRegistry;
import com.android.tools.lint.client.api.LintDriver;
import com.android.tools.lint.detector.api.Implementation;
import com.android.tools.lint.detector.api.Issue;
import com.android.tools.lint.detector.api.JavaContext;
import com.android.tools.lint.detector.api.Scope;
import java.util.EnumSet;
import java.util.Iterator;
import lombok.ast.Annotation;
import lombok.ast.AnnotationElement;
import lombok.ast.AnnotationValue;
import lombok.ast.ArrayInitializer;
import lombok.ast.Block;
import lombok.ast.ConstructorDeclaration;
import lombok.ast.Expression;
import lombok.ast.ForwardingAstVisitor;
import lombok.ast.MethodDeclaration;
import lombok.ast.Modifiers;
import lombok.ast.Node;
import lombok.ast.Select;
import lombok.ast.StrictListAccessor;
import lombok.ast.StringLiteral;
import lombok.ast.TypeBody;
import lombok.ast.TypeReference;
import lombok.ast.VariableDefinition;
import lombok.ast.VariableDefinitionEntry;

class AnnotationDetector$AnnotationChecker
  extends ForwardingAstVisitor
{
  private final JavaContext mContext;
  
  public AnnotationDetector$AnnotationChecker(JavaContext context)
  {
    mContext = context;
  }
  
  public boolean visitAnnotation(Annotation node)
  {
    String type = node.astAnnotationTypeReference().getTypeName();
    if (("SuppressLint".equals(type)) || ("android.annotation.SuppressLint".equals(type)))
    {
      Node parent = node.getParent();
      if ((parent instanceof Modifiers))
      {
        parent = parent.getParent();
        if ((parent instanceof VariableDefinition)) {
          for (AnnotationElement element : node.astElements())
          {
            AnnotationValue valueNode = element.astValue();
            if (valueNode != null) {
              if ((valueNode instanceof StringLiteral))
              {
                StringLiteral literal = (StringLiteral)valueNode;
                String id = literal.astValue();
                if (!checkId(node, id)) {
                  return super.visitAnnotation(node);
                }
              }
              else if ((valueNode instanceof ArrayInitializer))
              {
                ArrayInitializer array = (ArrayInitializer)valueNode;
                StrictListAccessor<Expression, ArrayInitializer> expressions = array.astExpressions();
                if (expressions != null)
                {
                  Iterator<Expression> arrayIterator = expressions.iterator();
                  while (arrayIterator.hasNext())
                  {
                    Expression arrayElement = (Expression)arrayIterator.next();
                    if ((arrayElement instanceof StringLiteral))
                    {
                      String id = ((StringLiteral)arrayElement).astValue();
                      if (!checkId(node, id)) {
                        return super.visitAnnotation(node);
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    return super.visitAnnotation(node);
  }
  
  private boolean checkId(Annotation node, String id)
  {
    IssueRegistry registry = mContext.getDriver().getRegistry();
    Issue issue = registry.getIssue(id);
    if (((issue != null) && (!issue.getImplementation().getScope().contains(Scope.JAVA_FILE))) || (issue == ApiDetector.UNSUPPORTED))
    {
      Node parent = node.getParent();
      while ((parent != null) && 
        (!(parent instanceof MethodDeclaration)) && (!(parent instanceof ConstructorDeclaration)) && (!(parent instanceof Block)))
      {
        if ((parent instanceof TypeBody)) {
          return true;
        }
        if ((issue == ApiDetector.UNSUPPORTED) && ((parent instanceof VariableDefinition)))
        {
          VariableDefinition definition = (VariableDefinition)parent;
          for (VariableDefinitionEntry entry : definition.astVariables())
          {
            Expression initializer = entry.astInitializer();
            if ((initializer instanceof Select)) {
              return true;
            }
          }
        }
        parent = parent.getParent();
        if (parent == null) {
          return true;
        }
      }
      mContext.report(AnnotationDetector.ISSUE, node, mContext.getLocation(node), String.format("The @SuppressLint annotation cannot be used on a local variable with the lint check '%1$s': move out to the surrounding method", new Object[] { id }), null);
      
      return false;
    }
    return true;
  }
}

/* Location:
 * Qualified Name:     com.android.tools.lint.checks.AnnotationDetector.AnnotationChecker
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package com.android.tools.lint.checks;

import com.android.annotations.NonNull;
import com.android.tools.lint.client.api.IssueRegistry;
import com.android.tools.lint.client.api.LintDriver;
import com.android.tools.lint.detector.api.Category;
import com.android.tools.lint.detector.api.Context;
import com.android.tools.lint.detector.api.Detector;
import com.android.tools.lint.detector.api.Detector.JavaScanner;
import com.android.tools.lint.detector.api.Implementation;
import com.android.tools.lint.detector.api.Issue;
import com.android.tools.lint.detector.api.JavaContext;
import com.android.tools.lint.detector.api.Scope;
import com.android.tools.lint.detector.api.Severity;
import com.android.tools.lint.detector.api.Speed;
import java.io.File;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import lombok.ast.Annotation;
import lombok.ast.AnnotationElement;
import lombok.ast.AnnotationValue;
import lombok.ast.ArrayInitializer;
import lombok.ast.AstVisitor;
import lombok.ast.Block;
import lombok.ast.ConstructorDeclaration;
import lombok.ast.Expression;
import lombok.ast.ForwardingAstVisitor;
import lombok.ast.MethodDeclaration;
import lombok.ast.Modifiers;
import lombok.ast.Node;
import lombok.ast.Select;
import lombok.ast.StrictListAccessor;
import lombok.ast.StringLiteral;
import lombok.ast.TypeBody;
import lombok.ast.TypeReference;
import lombok.ast.VariableDefinition;
import lombok.ast.VariableDefinitionEntry;

public class AnnotationDetector
  extends Detector
  implements Detector.JavaScanner
{
  public static final Issue ISSUE = Issue.create("LocalSuppress", "@SuppressLint on invalid element", "Looks for @SuppressLint annotations in locations where it doesn't work for class based checks", "The `@SuppressAnnotation` is used to suppress Lint warnings in Java files. However, while many lint checks analyzes the Java source code, where they can find annotations on (for example) local variables, some checks are analyzing the `.class` files. And in class files, annotations only appear on classes, fields and methods. Annotations placed on local variables disappear. If you attempt to suppress a lint error for a class-file based lint check, the suppress annotation not work. You must move the annotation out to the surrounding method.", Category.CORRECTNESS, 3, Severity.ERROR, new Implementation(AnnotationDetector.class, Scope.JAVA_FILE_SCOPE));
  
  public boolean appliesTo(@NonNull Context context, @NonNull File file)
  {
    return true;
  }
  
  @NonNull
  public Speed getSpeed()
  {
    return Speed.FAST;
  }
  
  public List<Class<? extends Node>> getApplicableNodeTypes()
  {
    return Collections.singletonList(Annotation.class);
  }
  
  public AstVisitor createJavaVisitor(@NonNull JavaContext context)
  {
    return new AnnotationChecker(context);
  }
  
  private static class AnnotationChecker
    extends ForwardingAstVisitor
  {
    private final JavaContext mContext;
    
    public AnnotationChecker(JavaContext context)
    {
      mContext = context;
    }
    
    public boolean visitAnnotation(Annotation node)
    {
      String type = node.astAnnotationTypeReference().getTypeName();
      if (("SuppressLint".equals(type)) || ("android.annotation.SuppressLint".equals(type)))
      {
        Node parent = node.getParent();
        if ((parent instanceof Modifiers))
        {
          parent = parent.getParent();
          if ((parent instanceof VariableDefinition)) {
            for (AnnotationElement element : node.astElements())
            {
              AnnotationValue valueNode = element.astValue();
              if (valueNode != null) {
                if ((valueNode instanceof StringLiteral))
                {
                  StringLiteral literal = (StringLiteral)valueNode;
                  String id = literal.astValue();
                  if (!checkId(node, id)) {
                    return super.visitAnnotation(node);
                  }
                }
                else if ((valueNode instanceof ArrayInitializer))
                {
                  ArrayInitializer array = (ArrayInitializer)valueNode;
                  StrictListAccessor<Expression, ArrayInitializer> expressions = array.astExpressions();
                  if (expressions != null)
                  {
                    Iterator<Expression> arrayIterator = expressions.iterator();
                    while (arrayIterator.hasNext())
                    {
                      Expression arrayElement = (Expression)arrayIterator.next();
                      if ((arrayElement instanceof StringLiteral))
                      {
                        String id = ((StringLiteral)arrayElement).astValue();
                        if (!checkId(node, id)) {
                          return super.visitAnnotation(node);
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
      return super.visitAnnotation(node);
    }
    
    private boolean checkId(Annotation node, String id)
    {
      IssueRegistry registry = mContext.getDriver().getRegistry();
      Issue issue = registry.getIssue(id);
      if (((issue != null) && (!issue.getImplementation().getScope().contains(Scope.JAVA_FILE))) || (issue == ApiDetector.UNSUPPORTED))
      {
        Node parent = node.getParent();
        while ((parent != null) && 
          (!(parent instanceof MethodDeclaration)) && (!(parent instanceof ConstructorDeclaration)) && (!(parent instanceof Block)))
        {
          if ((parent instanceof TypeBody)) {
            return true;
          }
          if ((issue == ApiDetector.UNSUPPORTED) && ((parent instanceof VariableDefinition)))
          {
            VariableDefinition definition = (VariableDefinition)parent;
            for (VariableDefinitionEntry entry : definition.astVariables())
            {
              Expression initializer = entry.astInitializer();
              if ((initializer instanceof Select)) {
                return true;
              }
            }
          }
          parent = parent.getParent();
          if (parent == null) {
            return true;
          }
        }
        mContext.report(AnnotationDetector.ISSUE, node, mContext.getLocation(node), String.format("The @SuppressLint annotation cannot be used on a local variable with the lint check '%1$s': move out to the surrounding method", new Object[] { id }), null);
        
        return false;
      }
      return true;
    }
  }
}

/* Location:
 * Qualified Name:     com.android.tools.lint.checks.AnnotationDetector
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package com.android.tools.lint.checks;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXException;

public class Api
{
  private final Map<String, ApiClass> mClasses;
  
  public static Api parseApi(File apiFile)
  {
    FileInputStream fileInputStream = null;
    try
    {
      fileInputStream = new FileInputStream(apiFile);
      SAXParserFactory parserFactory = SAXParserFactory.newInstance();
      SAXParser parser = parserFactory.newSAXParser();
      ApiParser apiParser = new ApiParser();
      parser.parse(fileInputStream, apiParser);
      return new Api(apiParser.getClasses());
    }
    catch (ParserConfigurationException e)
    {
      e.printStackTrace();
    }
    catch (SAXException e)
    {
      e.printStackTrace();
    }
    catch (IOException e)
    {
      e.printStackTrace();
    }
    finally
    {
      if (fileInputStream != null) {
        try
        {
          fileInputStream.close();
        }
        catch (IOException e) {}
      }
    }
    return null;
  }
  
  private Api(Map<String, ApiClass> classes)
  {
    mClasses = new HashMap(classes);
  }
  
  ApiClass getClass(String fqcn)
  {
    return (ApiClass)mClasses.get(fqcn);
  }
  
  Map<String, ApiClass> getClasses()
  {
    return Collections.unmodifiableMap(mClasses);
  }
}

/* Location:
 * Qualified Name:     com.android.tools.lint.checks.Api
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package com.android.tools.lint.checks;

import com.android.annotations.Nullable;
import com.android.utils.Pair;
import com.google.common.collect.Lists;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class ApiClass
{
  private final String mName;
  private final int mSince;
  private final List<Pair<String, Integer>> mSuperClasses = Lists.newArrayList();
  private final List<Pair<String, Integer>> mInterfaces = Lists.newArrayList();
  private final Map<String, Integer> mFields = new HashMap();
  private final Map<String, Integer> mMethods = new HashMap();
  
  ApiClass(String name, int since)
  {
    mName = name;
    mSince = since;
  }
  
  String getName()
  {
    return mName;
  }
  
  int getSince()
  {
    return mSince;
  }
  
  Integer getField(String name, Api info)
  {
    int min = Integer.MAX_VALUE;
    Integer i = (Integer)mFields.get(name);
    if (i != null) {
      min = i.intValue();
    }
    for (Pair<String, Integer> superClassPair : mSuperClasses)
    {
      ApiClass superClass = info.getClass((String)superClassPair.getFirst());
      if (superClass != null)
      {
        i = superClass.getField(name, info);
        if (i != null)
        {
          int tmp = (((Integer)superClassPair.getSecond()).intValue() > i.intValue() ? (Integer)superClassPair.getSecond() : i).intValue();
          if (tmp < min) {
            min = tmp;
          }
        }
      }
    }
    for (Pair<String, Integer> superClassPair : mInterfaces)
    {
      ApiClass superClass = info.getClass((String)superClassPair.getFirst());
      if (superClass != null)
      {
        i = superClass.getField(name, info);
        if (i != null)
        {
          int tmp = (((Integer)superClassPair.getSecond()).intValue() > i.intValue() ? (Integer)superClassPair.getSecond() : i).intValue();
          if (tmp < min) {
            min = tmp;
          }
        }
      }
    }
    return Integer.valueOf(min);
  }
  
  int getMethod(String methodSignature, Api info)
  {
    int min = Integer.MAX_VALUE;
    Integer i = (Integer)mMethods.get(methodSignature);
    if (i != null)
    {
      min = i.intValue();
      if (methodSignature.startsWith("<init>")) {
        return i.intValue();
      }
    }
    for (Pair<String, Integer> superClassPair : mSuperClasses)
    {
      ApiClass superClass = info.getClass((String)superClassPair.getFirst());
      if (superClass != null)
      {
        i = Integer.valueOf(superClass.getMethod(methodSignature, info));
        if (i != null)
        {
          int tmp = (((Integer)superClassPair.getSecond()).intValue() > i.intValue() ? (Integer)superClassPair.getSecond() : i).intValue();
          if (tmp < min) {
            min = tmp;
          }
        }
      }
    }
    for (Pair<String, Integer> interfacePair : mInterfaces)
    {
      ApiClass superClass = info.getClass((String)interfacePair.getFirst());
      if (superClass != null)
      {
        i = Integer.valueOf(superClass.getMethod(methodSignature, info));
        if (i != null)
        {
          int tmp = (((Integer)interfacePair.getSecond()).intValue() > i.intValue() ? (Integer)interfacePair.getSecond() : i).intValue();
          if (tmp < min) {
            min = tmp;
          }
        }
      }
    }
    return min;
  }
  
  void addField(String name, int since)
  {
    Integer i = (Integer)mFields.get(name);
    if ((i == null) || (i.intValue() > since)) {
      mFields.put(name, Integer.valueOf(since));
    }
  }
  
  void addMethod(String name, int since)
  {
    int index = name.indexOf(')');
    if (index != -1) {
      name = name.substring(0, index + 1);
    }
    Integer i = (Integer)mMethods.get(name);
    if ((i == null) || (i.intValue() > since)) {
      mMethods.put(name, Integer.valueOf(since));
    }
  }
  
  void addSuperClass(String superClass, int since)
  {
    addToArray(mSuperClasses, superClass, since);
  }
  
  void addInterface(String interfaceClass, int since)
  {
    addToArray(mInterfaces, interfaceClass, since);
  }
  
  static void addToArray(List<Pair<String, Integer>> list, String name, int value)
  {
    for (Pair<String, Integer> pair : list) {
      if (name.equals(pair.getFirst())) {
        return;
      }
    }
    list.add(Pair.of(name, Integer.valueOf(value)));
  }
  
  @Nullable
  public String getPackage()
  {
    int index = mName.lastIndexOf('/');
    if (index != -1) {
      return mName.substring(0, index);
    }
    return null;
  }
  
  public String toString()
  {
    return mName;
  }
  
  Set<String> getAllMethods(Api info)
  {
    Set<String> members = new HashSet(100);
    addAllMethods(info, members, true);
    
    return members;
  }
  
  private void addAllMethods(Api info, Set<String> set, boolean includeConstructors)
  {
    if (!includeConstructors) {
      for (String method : mMethods.keySet()) {
        if (!method.startsWith("<init>")) {
          set.add(method);
        }
      }
    } else {
      for (String method : mMethods.keySet()) {
        set.add(method);
      }
    }
    for (Pair<String, Integer> superClass : mSuperClasses)
    {
      ApiClass clz = info.getClass((String)superClass.getFirst());
      assert (clz != null) : ((Integer)superClass.getSecond());
      if (clz != null) {
        clz.addAllMethods(info, set, false);
      }
    }
    for (Pair<String, Integer> superClass : mInterfaces)
    {
      ApiClass clz = info.getClass((String)superClass.getFirst());
      assert (clz != null) : ((Integer)superClass.getSecond());
      if (clz != null) {
        clz.addAllMethods(info, set, false);
      }
    }
  }
  
  Set<String> getAllFields(Api info)
  {
    Set<String> members = new HashSet(100);
    addAllFields(info, members);
    
    return members;
  }
  
  private void addAllFields(Api info, Set<String> set)
  {
    for (String field : mFields.keySet()) {
      set.add(field);
    }
    for (Pair<String, Integer> superClass : mSuperClasses)
    {
      ApiClass clz = info.getClass((String)superClass.getFirst());
      assert (clz != null) : ((Integer)superClass.getSecond());
      if (clz != null) {
        clz.addAllFields(info, set);
      }
    }
    for (Pair<String, Integer> superClass : mInterfaces)
    {
      ApiClass clz = info.getClass((String)superClass.getFirst());
      assert (clz != null) : ((Integer)superClass.getSecond());
      if (clz != null) {
        clz.addAllFields(info, set);
      }
    }
  }
}

/* Location:
 * Qualified Name:     com.android.tools.lint.checks.ApiClass
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package com.android.tools.lint.checks;

import lombok.ast.ForwardingAstVisitor;

class ApiDetector$1
  extends ForwardingAstVisitor
{
  ApiDetector$1(ApiDetector paramApiDetector) {}
}

/* Location:
 * Qualified Name:     com.android.tools.lint.checks.ApiDetector.1
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package com.android.tools.lint.checks;

import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.ide.common.sdk.SdkVersionInfo;
import com.android.tools.lint.client.api.LintDriver;
import com.android.tools.lint.detector.api.ClassContext;
import com.android.tools.lint.detector.api.DefaultPosition;
import com.android.tools.lint.detector.api.JavaContext;
import com.android.tools.lint.detector.api.Location;
import com.android.utils.Pair;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import lombok.ast.Annotation;
import lombok.ast.AnnotationElement;
import lombok.ast.AnnotationValue;
import lombok.ast.BinaryExpression;
import lombok.ast.Case;
import lombok.ast.ClassDeclaration;
import lombok.ast.ConstructorDeclaration;
import lombok.ast.ConstructorInvocation;
import lombok.ast.Expression;
import lombok.ast.ForwardingAstVisitor;
import lombok.ast.Identifier;
import lombok.ast.ImportDeclaration;
import lombok.ast.IntegralLiteral;
import lombok.ast.MethodDeclaration;
import lombok.ast.MethodInvocation;
import lombok.ast.Modifiers;
import lombok.ast.Node;
import lombok.ast.Select;
import lombok.ast.StrictListAccessor;
import lombok.ast.StringLiteral;
import lombok.ast.SuperConstructorInvocation;
import lombok.ast.Switch;
import lombok.ast.Try;
import lombok.ast.TypeReference;
import lombok.ast.VariableDefinition;
import lombok.ast.VariableDefinitionEntry;
import lombok.ast.VariableReference;

final class ApiDetector$ApiVisitor
  extends ForwardingAstVisitor
{
  private JavaContext mContext;
  private Map<String, String> mClassToImport = Maps.newHashMap();
  private List<String> mStarImports;
  private Set<String> mLocalVars;
  private Node mCurrentMethod;
  private Set<String> mFields;
  private List<String> mStaticStarImports;
  
  private ApiDetector$ApiVisitor(ApiDetector paramApiDetector, JavaContext context)
  {
    mContext = context;
  }
  
  public boolean visitImportDeclaration(ImportDeclaration node)
  {
    if (node.astStarImport())
    {
      String fqcn = node.asFullyQualifiedName();
      int strip = fqcn.lastIndexOf('*');
      if (strip != -1)
      {
        strip = fqcn.lastIndexOf('.', strip);
        if (strip != -1)
        {
          String pkgName = ClassContext.getInternalName(fqcn.substring(0, strip));
          if (ApiLookup.isRelevantOwner(pkgName)) {
            if (node.astStaticImport())
            {
              if (mStaticStarImports == null) {
                mStaticStarImports = Lists.newArrayList();
              }
              mStaticStarImports.add(pkgName);
            }
            else
            {
              if (mStarImports == null) {
                mStarImports = Lists.newArrayList();
              }
              mStarImports.add(pkgName);
            }
          }
        }
      }
    }
    else if (node.astStaticImport())
    {
      String fqcn = node.asFullyQualifiedName();
      String fieldName = ClassContext.getInternalName(fqcn);
      int index = fieldName.lastIndexOf('$');
      if (index != -1)
      {
        String owner = fieldName.substring(0, index);
        String name = fieldName.substring(index + 1);
        checkField(node, name, owner);
      }
    }
    else
    {
      String fqcn = node.asFullyQualifiedName();
      
      int last = fqcn.lastIndexOf('.');
      if (last != -1)
      {
        String className = fqcn.substring(last + 1);
        mClassToImport.put(className, fqcn);
      }
    }
    return super.visitImportDeclaration(node);
  }
  
  public boolean visitSelect(Select node)
  {
    boolean result = super.visitSelect(node);
    if ((node.getParent() instanceof Select)) {
      return result;
    }
    String name = node.astIdentifier().astValue();
    boolean isField = Character.isUpperCase(name.charAt(0));
    if (!isField)
    {
      Select current = node;
      while (current != null)
      {
        Expression operand = current.astOperand();
        if ((operand instanceof Select))
        {
          current = (Select)operand;
          if ("R".equals(current.astIdentifier().astValue()))
          {
            isField = true;
            break;
          }
        }
        else
        {
          if (!(operand instanceof VariableReference)) {
            break;
          }
          VariableReference reference = (VariableReference)operand;
          if (!"R".equals(reference.astIdentifier().astValue())) {
            break;
          }
          isField = true; break;
        }
      }
    }
    String className;
    if (isField)
    {
      Expression operand = node.astOperand();
      if (operand.getClass() == Select.class)
      {
        String cls = operand.toString();
        if (Character.isUpperCase(cls.charAt(0)))
        {
          int firstDot = cls.indexOf('.');
          if (firstDot != -1)
          {
            String base = cls.substring(0, firstDot);
            String fqcn = (String)mClassToImport.get(base);
            if (fqcn != null)
            {
              String owner = ClassContext.getInternalName(fqcn + cls.substring(firstDot));
              checkField(node, name, owner);
              return result;
            }
            if (mStarImports != null) {
              for (String packagePrefix : mStarImports)
              {
                String owner = ClassContext.getInternalName(packagePrefix + '/' + cls);
                if (checkField(node, name, owner))
                {
                  mClassToImport.put(name, owner);
                  return result;
                }
              }
            }
          }
        }
        String owner = ClassContext.getInternalName(cls);
        checkField(node, name, owner);
        return result;
      }
      if (operand.getClass() == VariableReference.class)
      {
        className = ((VariableReference)operand).astIdentifier().astValue();
        
        String fqcn = (String)mClassToImport.get(className);
        if (fqcn != null)
        {
          String owner = ClassContext.getInternalName(fqcn);
          checkField(node, name, owner);
          return result;
        }
        if (Character.isUpperCase(className.charAt(0))) {
          if (mStarImports != null) {
            for (String packagePrefix : mStarImports)
            {
              String owner = ClassContext.getInternalName(packagePrefix) + '/' + className;
              if (checkField(node, name, owner))
              {
                mClassToImport.put(name, owner);
                return result;
              }
            }
          }
        }
      }
    }
    return result;
  }
  
  public boolean visitVariableReference(VariableReference node)
  {
    boolean result = super.visitVariableReference(node);
    if (node.getParent() != null)
    {
      Node parent = node.getParent();
      Class<? extends Node> parentClass = parent.getClass();
      if ((parentClass == Select.class) || (parentClass == Switch.class) || (parentClass == Case.class) || (parentClass == ConstructorInvocation.class) || (parentClass == SuperConstructorInvocation.class) || (parentClass == AnnotationElement.class)) {
        return result;
      }
      if (((parent instanceof MethodInvocation)) && (((MethodInvocation)parent).astOperand() == node)) {
        return result;
      }
      if ((parent instanceof BinaryExpression))
      {
        BinaryExpression expression = (BinaryExpression)parent;
        if (expression.astLeft() == node) {
          return result;
        }
      }
    }
    String name = node.astIdentifier().astValue();
    if ((Character.isUpperCase(name.charAt(0))) && ((mLocalVars == null) || (!mLocalVars.contains(nam
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

Further reading...

For more information on Java 1.5 Tiger, you may find Java 1.5 Tiger, A developer's Notebook by D. Flanagan and B. McLaughlin from O'Reilly of interest.

New!JAR listings


Copyright 2006-2017. Infinite Loop Ltd