| /* |
| * 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.checks; |
| |
| import static com.android.SdkConstants.PROGUARD_CONFIG; |
| import static com.android.SdkConstants.PROJECT_PROPERTIES; |
| |
| import com.android.annotations.NonNull; |
| 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.Implementation; |
| import com.android.tools.lint.detector.api.Issue; |
| import com.android.tools.lint.detector.api.Location; |
| 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; |
| |
| /** |
| * Check which looks for errors in Proguard files. |
| */ |
| public class ProguardDetector extends Detector { |
| |
| private static final Implementation IMPLEMENTATION = new Implementation(ProguardDetector.class, |
| Scope.PROGUARD_SCOPE); |
| |
| /** The main issue discovered by this detector */ |
| public static final Issue WRONG_KEEP = Issue.create( |
| "Proguard", //$NON-NLS-1$ |
| "Using obsolete ProGuard configuration", |
| "Using `-keepclasseswithmembernames` in a proguard config file is not " + |
| "correct; it can cause some symbols to be renamed which should not be.\n" + |
| "Earlier versions of ADT used to create proguard.cfg files with the " + |
| "wrong format. Instead of `-keepclasseswithmembernames` use " + |
| "`-keepclasseswithmembers`, since the old flags also implies " + |
| "\"allow shrinking\" which means symbols only referred to from XML and " + |
| "not Java (such as possibly CustomViews) can get deleted.", |
| Category.CORRECTNESS, |
| 8, |
| Severity.FATAL, |
| IMPLEMENTATION) |
| .addMoreInfo( |
| "http://http://code.google.com/p/android/issues/detail?id=16384"); //$NON-NLS-1$ |
| |
| /** Finds ProGuard files that contain non-project specific configuration |
| * locally and suggests replacing it with an include path */ |
| public static final Issue SPLIT_CONFIG = Issue.create( |
| "ProguardSplit", //$NON-NLS-1$ |
| "Proguard.cfg file contains generic Android rules", |
| |
| "Earlier versions of the Android tools bundled a single `proguard.cfg` file " + |
| "containing a ProGuard configuration file suitable for Android shrinking and " + |
| "obfuscation. However, that version was copied into new projects, which " + |
| "means that it does not continue to get updated as we improve the default " + |
| "ProGuard rules for Android.\n" + |
| "\n" + |
| "In the new version of the tools, we have split the ProGuard configuration " + |
| "into two halves:\n" + |
| "* A simple configuration file containing only project-specific flags, in " + |
| "your project\n" + |
| "* A generic configuration file containing the recommended set of ProGuard " + |
| "options for Android projects. This generic file lives in the SDK install " + |
| "directory which means that it gets updated along with the tools.\n" + |
| "\n" + |
| "In order for this to work, the proguard.config property in the " + |
| "`project.properties` file now refers to a path, so you can reference both " + |
| "the generic file as well as your own (and any additional files too).\n" + |
| "\n" + |
| "To migrate your project to the new setup, create a new `proguard-project.txt` file " + |
| "in your project containing any project specific ProGuard flags as well as " + |
| "any customizations you have made, then update your project.properties file " + |
| "to contain:\n" + |
| "`proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt`", |
| |
| Category.CORRECTNESS, |
| 3, |
| Severity.WARNING, |
| IMPLEMENTATION); |
| |
| @Override |
| public void run(@NonNull Context context) { |
| String contents = context.getContents(); |
| if (contents != null) { |
| if (context.isEnabled(WRONG_KEEP)) { |
| int index = contents.indexOf( |
| // Old pattern: |
| "-keepclasseswithmembernames class * {\n" + //$NON-NLS-1$ |
| " public <init>(android."); //$NON-NLS-1$ |
| if (index != -1) { |
| context.report(WRONG_KEEP, |
| Location.create(context.file, contents, index, index), |
| "Obsolete ProGuard file; use `-keepclasseswithmembers` instead of " + |
| "`-keepclasseswithmembernames`"); |
| } |
| } |
| if (context.isEnabled(SPLIT_CONFIG)) { |
| int index = contents.indexOf("-keep public class * extends android.app.Activity"); |
| if (index != -1) { |
| // Only complain if project.properties actually references this file; |
| // no need to bother the users who got a default proguard.cfg file |
| // when they created their projects but haven't actually hooked it up |
| // to shrinking & obfuscation. |
| File propertyFile = new File(context.file.getParentFile(), PROJECT_PROPERTIES); |
| if (!propertyFile.exists()) { |
| return; |
| } |
| String properties = context.getClient().readFile(propertyFile); |
| int i = properties.indexOf(PROGUARD_CONFIG); |
| if (i == -1) { |
| return; |
| } |
| // Make sure the entry isn't just commented out, such as |
| // # To enable ProGuard to shrink and obfuscate your code, uncomment this: |
| // #proguard.config=proguard.cfg |
| for (; i >= 0; i--) { |
| char c = properties.charAt(i); |
| if (c == '#') { |
| return; |
| } |
| if (c == '\n') { |
| break; |
| } |
| } |
| if (properties.contains(PROGUARD_CONFIG)) { |
| context.report(SPLIT_CONFIG, |
| Location.create(context.file, contents, index, index), |
| String.format( |
| "Local ProGuard configuration contains general Android " + |
| "configuration: Inherit these settings instead? " + |
| "Modify `project.properties` to define " + |
| "`proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:%1$s`" + |
| " and then keep only project-specific configuration here", |
| context.file.getName())); |
| } |
| } |
| } |
| } |
| } |
| |
| @Override |
| public boolean appliesTo(@NonNull Context context, @NonNull File file) { |
| return true; |
| } |
| |
| @NonNull |
| @Override |
| public Speed getSpeed() { |
| return Speed.FAST; |
| } |
| } |